Skip to content

Commit 2fad404

Browse files
rafaelhaclaudeCopilot
authored
Add SPP and SPP_DAG instructions (#97)
## Summary - Implement SPP and SPP_DAG (generalized S gate) that phase the -1 eigenspace of Pauli product observables by i or -i - Reuses the MPP auxiliary qubit pattern: entangle with Pauli product, apply S/S_DAG, then uncompute - Extracted shared `_apply_pauli_controls` helper from MPP - Supports inverted targets (`!`) which toggle between SPP and SPP_DAG behavior - Supports multi-qubit Pauli products (e.g., `SPP X0*Y1*Z2`) and multiple products per instruction Closes #74 ## Test plan - [x] Unit tests: parsing single/multi-qubit products, SPP_DAG, multiple products - [x] Integration tests verifying equivalence to known gates: - `SPP Z0` = `S`, `SPP_DAG Z0` = `S_DAG` - `SPP X0` = `SQRT_X`, `SPP !X0` = `SQRT_X_DAG` - `SPP X0*X1` = `SQRT_XX`, `SPP Y0*Y1` = `SQRT_YY`, `SPP Z0*Z1` = `SQRT_ZZ` 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent f2c45e6 commit 2fad404

9 files changed

Lines changed: 255 additions & 78 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131
- Initial release
3232
- Clifford+T circuit simulation via stabilizer rank decomposition
3333
- Stabilizer decomposition backend based on pyzx and the [paramzx-extension](https://github.com/mjsutcliffe99/ParamZX) by [(2025) M Sutcliffe and A Kissinger](https://arxiv.org/pdf/2403.06777)
34-
- Support for all [Stim](https://github.com/quantumlib/Stim) instructions
34+
- Support for most [Stim](https://github.com/quantumlib/Stim) instructions
3535
- `T`, `T_DAG`, `R_Z`, `R_X`, `R_Y`, and `U3` instructions
3636
- Arbitrary rotations gates via magic cat state decomposition from Eq. 10 of [(2021) Qassim et al.](https://arxiv.org/pdf/2106.07740)
3737
- GPU acceleration via jax

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Tsim can be five orders of magnitude faster than [quizx](https://github.com/zxca
103103

104104
## Supported Instructions
105105

106-
Tsim supports all [Stim instructions](https://github.com/quantumlib/Stim/wiki/Stim-v1.9-Gate-Reference). In addition, Tsim defines the following non-Clifford instructions:
106+
Tsim supports most [Stim instructions](https://github.com/quantumlib/Stim/wiki/Stim-v1.9-Gate-Reference). In addition, Tsim defines the following non-Clifford instructions:
107107

108108
### `T` and `T_DAG`
109109

docs/demos/overview.ipynb

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"source": [
2929
"### Clifford Instructions\n",
3030
"\n",
31-
"Tsim supports all instructions [supported by Stim](https://github.com/quantumlib/Stim/wiki/Stim-v1.9-Gate-Reference). Below we show the standard generating set of Clifford gates:"
31+
"Tsim supports most instructions [supported by Stim](https://github.com/quantumlib/Stim/wiki/Stim-v1.9-Gate-Reference). Below we show the standard generating set of Clifford gates:"
3232
]
3333
},
3434
{
@@ -330,6 +330,25 @@
330330
"cell_type": "markdown",
331331
"id": "28",
332332
"metadata": {},
333+
"source": [
334+
"The `SPP` instruction phases the $-1$ eigenspace of a Pauli product observable by $i$. For example, `SPP Z0` is equivalent to the `S` gate, and `SPP X0*X1` is equivalent to `SQRT_XX`. The `SPP_DAG` instruction phases by $-i$ instead. The `!` operator inverts the product, swapping `SPP` and `SPP_DAG` behavior."
335+
]
336+
},
337+
{
338+
"cell_type": "code",
339+
"execution_count": null,
340+
"id": "29",
341+
"metadata": {},
342+
"outputs": [],
343+
"source": [
344+
"c = Circuit(\"SPP X0*Y1*Z2\")\n",
345+
"c.diagram(\"timeline-svg\", height=220)"
346+
]
347+
},
348+
{
349+
"cell_type": "markdown",
350+
"id": "30",
351+
"metadata": {},
333352
"source": [
334353
"### Noise Channels\n",
335354
"\n",
@@ -341,7 +360,7 @@
341360
{
342361
"cell_type": "code",
343362
"execution_count": null,
344-
"id": "29",
363+
"id": "31",
345364
"metadata": {},
346365
"outputs": [],
347366
"source": [
@@ -351,7 +370,7 @@
351370
},
352371
{
353372
"cell_type": "markdown",
354-
"id": "30",
373+
"id": "32",
355374
"metadata": {},
356375
"source": [
357376
"The `PAULI_CHANNEL_1(p_x, p_y, p_z)` instruction is a `X`, `Y`, and `Z` instruction that is applied with probabilities `p_x`, `p_y`, and `p_z` respectively."
@@ -360,7 +379,7 @@
360379
{
361380
"cell_type": "code",
362381
"execution_count": null,
363-
"id": "31",
382+
"id": "33",
364383
"metadata": {},
365384
"outputs": [],
366385
"source": [
@@ -370,7 +389,7 @@
370389
},
371390
{
372391
"cell_type": "markdown",
373-
"id": "32",
392+
"id": "34",
374393
"metadata": {},
375394
"source": [
376395
"The `PAULI_CHANNEL_2` instruction takes fifteen floats specifying the disjoint probabilities of each possible Pauli pair\n",
@@ -397,7 +416,7 @@
397416
{
398417
"cell_type": "code",
399418
"execution_count": null,
400-
"id": "33",
419+
"id": "35",
401420
"metadata": {},
402421
"outputs": [],
403422
"source": [
@@ -409,7 +428,7 @@
409428
},
410429
{
411430
"cell_type": "markdown",
412-
"id": "34",
431+
"id": "36",
413432
"metadata": {},
414433
"source": [
415434
"The `DEPOLARIZE1(p)` instruction applies a randomly chosen Pauli with probability `p`."
@@ -418,7 +437,7 @@
418437
{
419438
"cell_type": "code",
420439
"execution_count": null,
421-
"id": "35",
440+
"id": "37",
422441
"metadata": {},
423442
"outputs": [],
424443
"source": [
@@ -428,7 +447,7 @@
428447
},
429448
{
430449
"cell_type": "markdown",
431-
"id": "36",
450+
"id": "38",
432451
"metadata": {},
433452
"source": [
434453
"The `DEPOLARIZE2(p)` instruction applies a randomly chosen two-qubit Pauli with probability `p`."
@@ -437,7 +456,7 @@
437456
{
438457
"cell_type": "code",
439458
"execution_count": null,
440-
"id": "37",
459+
"id": "39",
441460
"metadata": {},
442461
"outputs": [],
443462
"source": [
@@ -447,7 +466,7 @@
447466
},
448467
{
449468
"cell_type": "markdown",
450-
"id": "38",
469+
"id": "40",
451470
"metadata": {},
452471
"source": [
453472
"The `CORRELATED_ERROR(p)` instruction applies a specified Pauli product with probability `p`. If no error occurred, then a following `ELSE_CORRELATED_ERROR(p2)` instruction may apply a Pauli product with probabiliy `p2`. If no error occurs again, further `ELSE_CORRELATED_ERROR(pi)` instructions in the chain may apply a Pauli products."
@@ -456,7 +475,7 @@
456475
{
457476
"cell_type": "code",
458477
"execution_count": null,
459-
"id": "39",
478+
"id": "41",
460479
"metadata": {},
461480
"outputs": [],
462481
"source": [
@@ -470,7 +489,7 @@
470489
},
471490
{
472491
"cell_type": "markdown",
473-
"id": "40",
492+
"id": "42",
474493
"metadata": {},
475494
"source": [
476495
"### Annotations\n",
@@ -483,7 +502,7 @@
483502
{
484503
"cell_type": "code",
485504
"execution_count": null,
486-
"id": "41",
505+
"id": "43",
487506
"metadata": {},
488507
"outputs": [],
489508
"source": [
@@ -496,7 +515,7 @@
496515
},
497516
{
498517
"cell_type": "markdown",
499-
"id": "42",
518+
"id": "44",
500519
"metadata": {},
501520
"source": [
502521
"The `OBSERVABLE_INCLUDE` instruction is only used in observable sampling mode and ignored otherwise. It instructs the detector sampler to record the XOR of the specified measurement bits."
@@ -505,7 +524,7 @@
505524
{
506525
"cell_type": "code",
507526
"execution_count": null,
508-
"id": "43",
527+
"id": "45",
509528
"metadata": {},
510529
"outputs": [],
511530
"source": [
@@ -518,7 +537,7 @@
518537
},
519538
{
520539
"cell_type": "markdown",
521-
"id": "44",
540+
"id": "46",
522541
"metadata": {},
523542
"source": [
524543
"## Sampling\n",
@@ -529,7 +548,7 @@
529548
{
530549
"cell_type": "code",
531550
"execution_count": null,
532-
"id": "45",
551+
"id": "47",
533552
"metadata": {},
534553
"outputs": [],
535554
"source": [
@@ -546,7 +565,7 @@
546565
{
547566
"cell_type": "code",
548567
"execution_count": null,
549-
"id": "46",
568+
"id": "48",
550569
"metadata": {},
551570
"outputs": [],
552571
"source": [
@@ -555,7 +574,7 @@
555574
},
556575
{
557576
"cell_type": "markdown",
558-
"id": "47",
577+
"id": "49",
559578
"metadata": {},
560579
"source": [
561580
"The second sampling mode is detector sampling. This will sample detector events and observable values. Detector and observable bits can always be obtained by linear transformations of the measurement bits as return by the measurement sampler.\n",
@@ -565,7 +584,7 @@
565584
{
566585
"cell_type": "code",
567586
"execution_count": null,
568-
"id": "48",
587+
"id": "50",
569588
"metadata": {},
570589
"outputs": [],
571590
"source": [
@@ -584,7 +603,7 @@
584603
{
585604
"cell_type": "code",
586605
"execution_count": null,
587-
"id": "49",
606+
"id": "51",
588607
"metadata": {},
589608
"outputs": [],
590609
"source": [
@@ -595,7 +614,7 @@
595614
},
596615
{
597616
"cell_type": "markdown",
598-
"id": "50",
617+
"id": "52",
599618
"metadata": {},
600619
"source": [
601620
"Finally, Tsim allows to compute probability values for target states via the `CompiledStateProbs` sampler."
@@ -604,7 +623,7 @@
604623
{
605624
"cell_type": "code",
606625
"execution_count": null,
607-
"id": "51",
626+
"id": "53",
608627
"metadata": {},
609628
"outputs": [],
610629
"source": [
@@ -617,7 +636,7 @@
617636
{
618637
"cell_type": "code",
619638
"execution_count": null,
620-
"id": "52",
639+
"id": "54",
621640
"metadata": {},
622641
"outputs": [],
623642
"source": [
@@ -627,7 +646,7 @@
627646
{
628647
"cell_type": "code",
629648
"execution_count": null,
630-
"id": "53",
649+
"id": "55",
631650
"metadata": {},
632651
"outputs": [],
633652
"source": [
@@ -637,7 +656,7 @@
637656
{
638657
"cell_type": "code",
639658
"execution_count": null,
640-
"id": "54",
659+
"id": "56",
641660
"metadata": {},
642661
"outputs": [],
643662
"source": [
@@ -647,7 +666,7 @@
647666
{
648667
"cell_type": "code",
649668
"execution_count": null,
650-
"id": "55",
669+
"id": "57",
651670
"metadata": {},
652671
"outputs": [],
653672
"source": [
@@ -656,7 +675,7 @@
656675
},
657676
{
658677
"cell_type": "markdown",
659-
"id": "56",
678+
"id": "58",
660679
"metadata": {},
661680
"source": [
662681
"## Visualization\n",
@@ -669,7 +688,7 @@
669688
{
670689
"cell_type": "code",
671690
"execution_count": null,
672-
"id": "57",
691+
"id": "59",
673692
"metadata": {},
674693
"outputs": [],
675694
"source": [
@@ -696,7 +715,7 @@
696715
},
697716
{
698717
"cell_type": "markdown",
699-
"id": "58",
718+
"id": "60",
700719
"metadata": {},
701720
"source": [
702721
"When `TICK` instructions are present, each tick can be shown as a 2D time slice with the `timeslice-svg` diagram. Here, `QUBIT_COORDS` annotations can be used to specify the 2D coordinates of the qubits."
@@ -705,7 +724,7 @@
705724
{
706725
"cell_type": "code",
707726
"execution_count": null,
708-
"id": "59",
727+
"id": "61",
709728
"metadata": {},
710729
"outputs": [],
711730
"source": [
@@ -714,7 +733,7 @@
714733
},
715734
{
716735
"cell_type": "markdown",
717-
"id": "60",
736+
"id": "62",
718737
"metadata": {},
719738
"source": [
720739
"With the `pyzx` argument, the circuit can be visualized using the [pyzx](https://github.com/zxcalc/pyzx) as a ZX-diagram."
@@ -723,7 +742,7 @@
723742
{
724743
"cell_type": "code",
725744
"execution_count": null,
726-
"id": "61",
745+
"id": "63",
727746
"metadata": {},
728747
"outputs": [],
729748
"source": [
@@ -732,7 +751,7 @@
732751
},
733752
{
734753
"cell_type": "markdown",
735-
"id": "62",
754+
"id": "64",
736755
"metadata": {},
737756
"source": [
738757
"The `pyzx-meas` and `pyzx-dets` diagrams show ZX diagrams where outputs represent probabilities of measurement outcomes for measurement and detector/observables, respectively."
@@ -741,7 +760,7 @@
741760
{
742761
"cell_type": "code",
743762
"execution_count": null,
744-
"id": "63",
763+
"id": "65",
745764
"metadata": {},
746765
"outputs": [],
747766
"source": [
@@ -751,7 +770,7 @@
751770
{
752771
"cell_type": "code",
753772
"execution_count": null,
754-
"id": "64",
773+
"id": "66",
755774
"metadata": {},
756775
"outputs": [],
757776
"source": [
@@ -760,7 +779,7 @@
760779
},
761780
{
762781
"cell_type": "markdown",
763-
"id": "65",
782+
"id": "67",
764783
"metadata": {},
765784
"source": [
766785
"## Detector Error Models\n",
@@ -771,7 +790,7 @@
771790
{
772791
"cell_type": "code",
773792
"execution_count": null,
774-
"id": "66",
793+
"id": "68",
775794
"metadata": {},
776795
"outputs": [],
777796
"source": [

0 commit comments

Comments
 (0)