Skip to content

Commit ca1fbc3

Browse files
authored
Add SPP{_DAG} gate and some crumble fixes (#720)
- Fix crumble not falling back to emulated keyboard when copy works but paste fails - Fix crumble XCZ ordering - Fix not being able to hold 'e' or 'q' to zip around in crumble - Add "generalized S gate" `SPP` - Add `SPP_DAG` gate - Add `stim.GateData.flows` Fixes #709
1 parent 26416fc commit ca1fbc3

File tree

80 files changed

+2159
-764
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+2159
-764
lines changed

dev/canvas_with_texture_for_3d_diagrams.html

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@
104104
ctx.fillText('ERASE', x * 32 + 16 - ctx.measureText('ERASE').width / 2, y * 32 + 18);
105105
}
106106

107+
function drawCpp(ctx, c1, c2, i) {
108+
let {x, y} = pickRect(i);
109+
ctx.fillStyle = '#' + (c1 === 'X' || c2 === 'X' ? 'f' : '4') + (c1 === 'Y' || c2 === 'Y' ? 'f' : '4') + (c1 === 'Z' || c2 === 'Z' ? 'f' : '4');
110+
ctx.fillRect(x * 32, y * 32, 32, 32);
111+
ctx.fillStyle = 'black';
112+
ctx.font = '12pt serif';
113+
let t1 = 'CPP';
114+
ctx.fillText(t1, x * 32 + 16 - ctx.measureText(t1).width / 2, y * 32 + 5);
115+
let t2 = c1 + ':' + c2;
116+
ctx.font = '12pt serif';
117+
ctx.fillText(t2, x * 32 + 16 - ctx.measureText(t2).width / 2, y * 32 + 18);
118+
}
119+
107120
function drawHeraldPauliError1(ctx, i) {
108121
let {x, y} = pickRect(i);
109122
ctx.fillStyle = 'black';
@@ -203,6 +216,30 @@
203216
drawRect(ctx, "M_PAD", "#888", "#000", n++);
204217
drawHeraldErase(ctx, n++);
205218
drawHeraldPauliError1(ctx, n++);
219+
220+
drawRect(ctx, "SPP_X", "#F44", "#000", n++);
221+
drawRect(ctx, "SPP_Y", "#4F4", "#000", n++);
222+
drawRect(ctx, "SPP_Z", "#44F", "#000", n++);
223+
drawRect(ctx, "SPP_X†", "#F44", "#000", n++);
224+
drawRect(ctx, "SPP_Y†", "#4F4", "#000", n++);
225+
drawRect(ctx, "SPP_Z†", "#44F", "#000", n++);
226+
227+
n = 128 + 48;
228+
drawCpp(ctx, 'I', 'X', n++);
229+
drawCpp(ctx, 'I', 'Y', n++);
230+
drawCpp(ctx, 'I', 'Z', n++);
231+
drawCpp(ctx, 'X', 'I', n++);
232+
drawCpp(ctx, 'X', 'X', n++);
233+
drawCpp(ctx, 'X', 'Y', n++);
234+
drawCpp(ctx, 'X', 'Z', n++);
235+
drawCpp(ctx, 'Y', 'I', n++);
236+
drawCpp(ctx, 'Y', 'X', n++);
237+
drawCpp(ctx, 'Y', 'Y', n++);
238+
drawCpp(ctx, 'Y', 'Z', n++);
239+
drawCpp(ctx, 'Z', 'I', n++);
240+
drawCpp(ctx, 'Z', 'X', n++);
241+
drawCpp(ctx, 'Z', 'Y', n++);
242+
drawCpp(ctx, 'Z', 'Z', n++);
206243
}
207244

208245
draw(document.getElementById('cv').getContext('2d'))

doc/gates.md

Lines changed: 204 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
- [Z_ERROR](#Z_ERROR)
6363
- Collapsing Gates
6464
- [M](#M)
65-
- [MPP](#MPP)
6665
- [MR](#MR)
6766
- [MRX](#MRX)
6867
- [MRY](#MRY)
@@ -78,6 +77,10 @@
7877
- [MXX](#MXX)
7978
- [MYY](#MYY)
8079
- [MZZ](#MZZ)
80+
- Generalized Pauli Product Gates
81+
- [MPP](#MPP)
82+
- [SPP](#SPP)
83+
- [SPP_DAG](#SPP_DAG)
8184
- Control Flow
8285
- [REPEAT](#REPEAT)
8386
- Annotations
@@ -2435,62 +2438,6 @@ Decomposition (into H, S, CX, M, R):
24352438
# (The decomposition is trivial because this gate is in the target gate set.)
24362439

24372440

2438-
<a name="MPP"></a>
2439-
### The 'MPP' Instruction
2440-
2441-
Measure Pauli products.
2442-
2443-
Parens Arguments:
2444-
2445-
Optional.
2446-
A single float specifying the probability of flipping each reported measurement result.
2447-
2448-
Targets:
2449-
2450-
A series of Pauli products to measure.
2451-
2452-
Each Pauli product is a series of Pauli targets (`[XYZ]#`) separated by combiners (`*`).
2453-
Products can be negated by prefixing a Pauli target in the product with an inverter (`!`)
2454-
2455-
Examples:
2456-
2457-
# Measure the two-body +X1*Y2 observable.
2458-
MPP X1*Y2
2459-
2460-
# Measure the one-body -Z5 observable.
2461-
MPP !Z5
2462-
2463-
# Measure the two-body +X1*Y2 observable and also the three-body -Z3*Z4*Z5 observable.
2464-
MPP X1*Y2 !Z3*Z4*Z5
2465-
2466-
# Noisily measure +Z1+Z2 and +X1*X2 (independently flip each reported result 0.1% of the time).
2467-
MPP(0.001) Z1*Z2 X1*X2
2468-
2469-
Stabilizer Generators (for `MPP X0*Y1*Z2 X3*X4`):
2470-
2471-
XYZ__ -> rec[-2]
2472-
___XX -> rec[-1]
2473-
X____ -> X____
2474-
_Y___ -> _Y___
2475-
__Z__ -> __Z__
2476-
___X_ -> ___X_
2477-
____X -> ____X
2478-
ZZ___ -> ZZ___
2479-
_XX__ -> _XX__
2480-
___ZZ -> ___ZZ
2481-
2482-
Decomposition (into H, S, CX, M, R):
2483-
2484-
# The following circuit is equivalent (up to global phase) to `MPP X0*Y1*Z2 X3*X4`
2485-
S 1 1 1
2486-
H 0 1 3 4
2487-
CX 2 0 1 0 4 3
2488-
M 0 3
2489-
CX 2 0 1 0 4 3
2490-
H 0 1 3 4
2491-
S 1
2492-
2493-
24942441
<a name="MR"></a>
24952442
### The 'MR' Instruction
24962443

@@ -3027,6 +2974,206 @@ Decomposition (into H, S, CX, M, R):
30272974
CX 0 1
30282975

30292976

2977+
## Generalized Pauli Product Gates
2978+
2979+
<a name="MPP"></a>
2980+
### The 'MPP' Instruction
2981+
2982+
Measures general pauli product operators, like X1*Y2*Z3.
2983+
2984+
Parens Arguments:
2985+
2986+
An optional failure probability.
2987+
If no argument is given, all measurements are perfect.
2988+
If one argument is given, it's the chance of reporting measurement results incorrectly.
2989+
2990+
Targets:
2991+
2992+
A series of Pauli products to measure.
2993+
2994+
Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by
2995+
combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`). A negated
2996+
product will record the opposite measurement result.
2997+
2998+
Note that, although you can write down instructions that measure anti-Hermitian products,
2999+
like `MPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the
3000+
circuit since measuring an anti-Hermitian operator doesn't have well defined semantics.
3001+
3002+
Using overly-complicated Hermitian products, like saying `MPP X1*Y1*Y2*Z2` instead of
3003+
`MPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming
3004+
the circuit may have assumed that each qubit would appear at most once in each product.
3005+
3006+
Examples:
3007+
3008+
# Measure the two-body +X1*Y2 observable.
3009+
MPP X1*Y2
3010+
3011+
# Measure the one-body -Z5 observable.
3012+
MPP !Z5
3013+
3014+
# Measure the two-body +X1*Y2 observable and also the three-body -Z3*Z4*Z5 observable.
3015+
MPP X1*Y2 !Z3*Z4*Z5
3016+
3017+
# Noisily measure +Z1+Z2 and +X1*X2 (independently flip each reported result 0.1% of the time).
3018+
MPP(0.001) Z1*Z2 X1*X2
3019+
3020+
Stabilizer Generators (for `MPP X0*Y1*Z2 X3*X4`):
3021+
3022+
XYZ__ -> rec[-2]
3023+
___XX -> rec[-1]
3024+
X____ -> X____
3025+
_Y___ -> _Y___
3026+
__Z__ -> __Z__
3027+
___X_ -> ___X_
3028+
____X -> ____X
3029+
ZZ___ -> ZZ___
3030+
_XX__ -> _XX__
3031+
___ZZ -> ___ZZ
3032+
3033+
Decomposition (into H, S, CX, M, R):
3034+
3035+
# The following circuit is equivalent (up to global phase) to `MPP X0*Y1*Z2 X3*X4`
3036+
S 1 1 1
3037+
H 0 1 3 4
3038+
CX 2 0 1 0 4 3
3039+
M 0 3
3040+
CX 2 0 1 0 4 3
3041+
H 0 1 3 4
3042+
S 1
3043+
3044+
3045+
<a name="SPP"></a>
3046+
### The 'SPP' Instruction
3047+
3048+
The generalized S gate. Phases the -1 eigenspace of Pauli product observables by i.
3049+
3050+
Parens Arguments:
3051+
3052+
This instruction takes no parens arguments.
3053+
3054+
Targets:
3055+
3056+
A series of Pauli products to phase.
3057+
3058+
Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by
3059+
combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate
3060+
the product.
3061+
3062+
Note that, although you can write down instructions that phase anti-Hermitian products,
3063+
like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the
3064+
circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.
3065+
3066+
Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of
3067+
`SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming
3068+
the circuit may have assumed that each qubit would appear at most once in each product.
3069+
3070+
Examples:
3071+
3072+
# Perform an S gate on qubit 1.
3073+
SPP Z1
3074+
3075+
# Perform a SQRT_X gate on qubit 1.
3076+
SPP X1
3077+
3078+
# Perform a SQRT_X_DAG gate on qubit 1.
3079+
SPP !X1
3080+
3081+
# Perform a SQRT_XX gate between qubit 1 and qubit 2.
3082+
SPP X1*X2
3083+
3084+
# Perform a SQRT_YY gate between qubit 1 and 2, and a SQRT_ZZ_DAG between qubit 3 and 4.
3085+
SPP Y1*Y2 !Z1*Z2
3086+
3087+
# Phase the -1 eigenspace of -X1*Y2*Z3 by i.
3088+
SPP !X1*Y2*Z3
3089+
3090+
Stabilizer Generators (for `SPP X0*Y1*Z2`):
3091+
3092+
X__ -> X__
3093+
Z__ -> -YYZ
3094+
_X_ -> -XZZ
3095+
_Z_ -> XXZ
3096+
__X -> XYY
3097+
__Z -> __Z
3098+
3099+
Decomposition (into H, S, CX, M, R):
3100+
3101+
# The following circuit is equivalent (up to global phase) to `SPP X0*Y1*Z2`
3102+
CX 2 1
3103+
CX 1 0
3104+
S 1
3105+
S 1
3106+
H 1
3107+
CX 1 0
3108+
CX 2 1
3109+
3110+
3111+
<a name="SPP_DAG"></a>
3112+
### The 'SPP_DAG' Instruction
3113+
3114+
The generalized S gate. Phases the -1 eigenspace of Pauli product observables by i.
3115+
3116+
Parens Arguments:
3117+
3118+
This instruction takes no parens arguments.
3119+
3120+
Targets:
3121+
3122+
A series of Pauli products to phase.
3123+
3124+
Each Pauli product is a series of Pauli targets (like `X1`, `Y2`, or `Z3`) separated by
3125+
combiners (`*`). Each Pauli term can be inverted (like `!Y2` instead of `Y2`), to negate
3126+
the product.
3127+
3128+
Note that, although you can write down instructions that phase anti-Hermitian products,
3129+
like `SPP X1*Z1`, doing this will cause exceptions when you simulate or analyze the
3130+
circuit since phasing an anti-Hermitian operator doesn't have well defined semantics.
3131+
3132+
Using overly-complicated Hermitian products, like saying `SPP X1*Y1*Y2*Z2` instead of
3133+
`SPP !Z1*X2`, is technically allowed. But probably not a great idea since tools consuming
3134+
the circuit may have assumed that each qubit would appear at most once in each product.
3135+
3136+
Examples:
3137+
3138+
# Perform an S_DAG gate on qubit 1.
3139+
SPP_DAG Z1
3140+
3141+
# Perform a SQRT_X_DAG gate on qubit 1.
3142+
SPP_DAG X1
3143+
3144+
# Perform a SQRT_X gate on qubit 1.
3145+
SPP_DAG !X1
3146+
3147+
# Perform a SQRT_XX_DAG gate between qubit 1 and qubit 2.
3148+
SPP_DAG X1*X2
3149+
3150+
# Perform a SQRT_YY_DAG gate between qubit 1 and 2, and a SQRT_ZZ between qubit 3 and 4.
3151+
SPP_DAG Y1*Y2 !Z1*Z2
3152+
3153+
# Phase the -1 eigenspace of -X1*Y2*Z3 by -i.
3154+
SPP_DAG !X1*Y2*Z3
3155+
3156+
Stabilizer Generators (for `SPP_DAG X0*Y1*Z2`):
3157+
3158+
X__ -> X__
3159+
Z__ -> YYZ
3160+
_X_ -> XZZ
3161+
_Z_ -> -XXZ
3162+
__X -> -XYY
3163+
__Z -> __Z
3164+
3165+
Decomposition (into H, S, CX, M, R):
3166+
3167+
# The following circuit is equivalent (up to global phase) to `SPP_DAG X0*Y1*Z2`
3168+
CX 2 1
3169+
CX 1 0
3170+
H 1
3171+
S 1
3172+
S 1
3173+
CX 1 0
3174+
CX 2 1
3175+
3176+
30303177
## Control Flow
30313178

30323179
<a name="REPEAT"></a>

doc/python_api_reference_vDev.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
209209
- [`stim.GateData.__repr__`](#stim.GateData.__repr__)
210210
- [`stim.GateData.__str__`](#stim.GateData.__str__)
211211
- [`stim.GateData.aliases`](#stim.GateData.aliases)
212+
- [`stim.GateData.flows`](#stim.GateData.flows)
212213
- [`stim.GateData.generalized_inverse`](#stim.GateData.generalized_inverse)
213214
- [`stim.GateData.inverse`](#stim.GateData.inverse)
214215
- [`stim.GateData.is_noisy_gate`](#stim.GateData.is_noisy_gate)
@@ -7501,6 +7502,50 @@ def aliases(
75017502
"""
75027503
```
75037504

7505+
<a name="stim.GateData.flows"></a>
7506+
```python
7507+
# stim.GateData.flows
7508+
7509+
# (in class stim.GateData)
7510+
@property
7511+
def flows(
7512+
self,
7513+
) -> Optional[List[stim.Flow]]:
7514+
"""Returns stabilizer flow generators for the gate, or else None.
7515+
7516+
A stabilizer flow describes an input-output relationship that the gate
7517+
satisfies, where an input pauli string is transformed into an output
7518+
pauli string mediated by certain measurement results.
7519+
7520+
Caution: this method returns None for variable-target-count gates like MPP.
7521+
Not because MPP has no stabilizer flows, but because its stabilizer flows
7522+
depend on how many qubits it targets and what basis it targets them in.
7523+
7524+
Returns:
7525+
A list of stim.Flow instances representing the generators.
7526+
7527+
Examples:
7528+
>>> import stim
7529+
7530+
>>> stim.gate_data('H').flows
7531+
[stim.Flow("X -> Z"), stim.Flow("Z -> X")]
7532+
7533+
>>> for e in stim.gate_data('ISWAP').flows:
7534+
... print(e)
7535+
X_ -> ZY
7536+
Z_ -> _Z
7537+
_X -> YZ
7538+
_Z -> Z_
7539+
7540+
>>> for e in stim.gate_data('MXX').flows:
7541+
... print(e)
7542+
X_ -> X_
7543+
_X -> _X
7544+
ZZ -> ZZ
7545+
XX -> rec[-1]
7546+
"""
7547+
```
7548+
75047549
<a name="stim.GateData.generalized_inverse"></a>
75057550
```python
75067551
# stim.GateData.generalized_inverse

0 commit comments

Comments
 (0)