qubasic 0.9.0__tar.gz → 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qubasic-0.9.0 → qubasic-0.10.0}/CHANGELOG.md +15 -0
- {qubasic-0.9.0/qubasic.egg-info → qubasic-0.10.0}/PKG-INFO +20 -3
- {qubasic-0.9.0 → qubasic-0.10.0}/README.md +19 -2
- {qubasic-0.9.0 → qubasic-0.10.0}/pyproject.toml +1 -1
- {qubasic-0.9.0 → qubasic-0.10.0/qubasic.egg-info}/PKG-INFO +20 -3
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic.egg-info/SOURCES.txt +1 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/__init__.py +1 -1
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/noise_mixin.py +8 -1
- qubasic-0.10.0/qubasic_core/qec.py +434 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/qol.py +2 -1
- qubasic-0.10.0/qubasic_core/resources.py +173 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/terminal.py +4 -2
- {qubasic-0.9.0 → qubasic-0.10.0}/tests/test_qubasic.py +84 -0
- qubasic-0.9.0/qubasic_core/qec.py +0 -220
- {qubasic-0.9.0 → qubasic-0.10.0}/LICENSE +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/MANIFEST.in +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/examples/bell.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/examples/grover3.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/examples/locc_teleport.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/examples/sweep_rx.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic.egg-info/dependency_links.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic.egg-info/entry_points.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic.egg-info/requires.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic.egg-info/top_level.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/__main__.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/algorithms.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/algos2.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/analysis.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/backend.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/benchmarking.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/bosonic.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/classic.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/cli.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/control_flow.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/debug.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/demos.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/dynamics.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/engine.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/engine_state.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/errors.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/exec_context.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/executor.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/expression.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/file_io.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/gates.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/help_text.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/io_protocol.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/locc.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/locc_commands.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/locc_display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/locc_engine.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/locc_execution.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/memory.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/mock_backend.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/parser.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/patterns.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/pauliprop.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/profiler.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/program_mgmt.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/protocol.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/qudits.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/scope.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/screen.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/state_display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/statements.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/strings.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/subs.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/qubasic_core/sweep.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/setup.cfg +0 -0
- {qubasic-0.9.0 → qubasic-0.10.0}/tests/test_features.py +0 -0
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0 (2026-06-19)
|
|
4
|
+
|
|
5
|
+
Completes the frontier set: fault-tolerant QEC extras and a compilation/resources
|
|
6
|
+
group. All offline on Qiskit/Aer/numpy.
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
- Surface code: `QEC SURFACE [d]`, a rotated surface code at odd distance d (validated to correct every weight-1 error).
|
|
10
|
+
- Union-find / matching decoder: exact minimum-weight matching of syndrome defects, scalable and dependency-free, selected with the `UF` flag on `LOGICAL_ERROR_RATE`. It tracks the optimal lookup decoder on the repetition and surface codes; the lookup decoder remains the default and the right choice for non-topological codes like Steane and Shor.
|
|
11
|
+
- Magic-state distillation: `DISTILL <p>` runs the 15-to-1 protocol (via the [15,11,3] Hamming detection), with cubic output-error suppression ~35 p^3.
|
|
12
|
+
- Lattice surgery: `LATTICE <a> <b>` performs the joint Zbar_A Zbar_B measurement that merges two repetition patches (the building block of a lattice-surgery CNOT).
|
|
13
|
+
- Fault-tolerant resource estimation: `RESOURCES <target_pL> <physical_p>` reports the surface-code distance, physical qubits per logical, T-count, T-factory overhead, and an approximate runtime.
|
|
14
|
+
- Calibrated device models: `DEVICE linear|ring|heavyhex|all [n] [T1us] [T2us]` builds a per-qubit thermal-relaxation noise model and coupling map for offline hardware-realistic simulation.
|
|
15
|
+
- `NOISE crosstalk <p>`: a correlated two-qubit ZZ crosstalk channel on entangling gates.
|
|
16
|
+
- `OPTIMIZE [level]`: transpiles the program and reports the depth and gate-count reduction.
|
|
17
|
+
|
|
3
18
|
## 0.9.0 (2026-06-19)
|
|
4
19
|
|
|
5
20
|
Frontier and experimental methods. All offline on Qiskit/Aer/numpy; nothing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qubasic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Quantum BASIC Interactive Terminal
|
|
5
5
|
Author-email: "Charles C. Norton" <machineelv@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -514,11 +514,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
514
514
|
## Error correction
|
|
515
515
|
|
|
516
516
|
```
|
|
517
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
518
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
517
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
518
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
519
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
519
520
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
521
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
522
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
520
523
|
```
|
|
521
524
|
|
|
525
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
526
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
527
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
528
|
+
|
|
522
529
|
## Benchmarking and verification
|
|
523
530
|
|
|
524
531
|
```
|
|
@@ -554,6 +561,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
554
561
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
555
562
|
```
|
|
556
563
|
|
|
564
|
+
## Compilation and resources
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
568
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
569
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
570
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
571
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
572
|
+
```
|
|
573
|
+
|
|
557
574
|
## Noise models
|
|
558
575
|
|
|
559
576
|
```
|
|
@@ -481,11 +481,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
481
481
|
## Error correction
|
|
482
482
|
|
|
483
483
|
```
|
|
484
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
485
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
484
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
485
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
486
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
486
487
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
488
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
489
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
487
490
|
```
|
|
488
491
|
|
|
492
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
493
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
494
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
495
|
+
|
|
489
496
|
## Benchmarking and verification
|
|
490
497
|
|
|
491
498
|
```
|
|
@@ -521,6 +528,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
521
528
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
522
529
|
```
|
|
523
530
|
|
|
531
|
+
## Compilation and resources
|
|
532
|
+
|
|
533
|
+
```
|
|
534
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
535
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
536
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
537
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
538
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
539
|
+
```
|
|
540
|
+
|
|
524
541
|
## Noise models
|
|
525
542
|
|
|
526
543
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qubasic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Quantum BASIC Interactive Terminal
|
|
5
5
|
Author-email: "Charles C. Norton" <machineelv@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -514,11 +514,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
514
514
|
## Error correction
|
|
515
515
|
|
|
516
516
|
```
|
|
517
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
518
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
517
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
518
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
519
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
519
520
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
521
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
522
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
520
523
|
```
|
|
521
524
|
|
|
525
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
526
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
527
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
528
|
+
|
|
522
529
|
## Benchmarking and verification
|
|
523
530
|
|
|
524
531
|
```
|
|
@@ -554,6 +561,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
554
561
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
555
562
|
```
|
|
556
563
|
|
|
564
|
+
## Compilation and resources
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
568
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
569
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
570
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
571
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
572
|
+
```
|
|
573
|
+
|
|
557
574
|
## Noise models
|
|
558
575
|
|
|
559
576
|
```
|
|
@@ -106,10 +106,17 @@ class NoiseMixin:
|
|
|
106
106
|
p1 = float(parts[2]) if len(parts) > 2 else 0.01
|
|
107
107
|
nm.add_all_qubit_quantum_error(reset_error(p0, p1), _1q)
|
|
108
108
|
self.io.writeln(f"NOISE reset p0={p0} p1={p1}")
|
|
109
|
+
elif ntype == 'crosstalk':
|
|
110
|
+
# Correlated (non-product) two-qubit error after each 2-qubit gate:
|
|
111
|
+
# a ZZ Pauli with probability p, otherwise identity.
|
|
112
|
+
p = float(parts[1]) if len(parts) > 1 else 0.01
|
|
113
|
+
err = pauli_error([('ZZ', p), ('II', 1 - p)])
|
|
114
|
+
nm.add_all_qubit_quantum_error(err, _2q)
|
|
115
|
+
self.io.writeln(f"NOISE crosstalk (correlated ZZ on 2-qubit gates) p={p}")
|
|
109
116
|
else:
|
|
110
117
|
self.io.writeln(f"?UNKNOWN NOISE TYPE: {ntype}")
|
|
111
118
|
self.io.writeln(" Types: depolarizing, amplitude_damping, phase_flip, thermal,")
|
|
112
|
-
self.io.writeln(" readout, combined, pauli, reset")
|
|
119
|
+
self.io.writeln(" readout, combined, pauli, reset, crosstalk")
|
|
113
120
|
return
|
|
114
121
|
self._noise_model = nm
|
|
115
122
|
self._noise_spec = rest.strip() # for SAVE round-tripping
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"""QUBASIC quantum error correction.
|
|
2
|
+
|
|
3
|
+
Stabilizer codes with an optimal (minimum-weight lookup) decoder, logical error
|
|
4
|
+
rates, and threshold sweeps, computed by classical Pauli-frame simulation (no
|
|
5
|
+
statevector needed, so it is exact and fast). Built-in codes: the repetition
|
|
6
|
+
(bit-flip) code at any odd distance, the [[7,1,3]] Steane code, and the [[9,1,3]]
|
|
7
|
+
Shor code.
|
|
8
|
+
|
|
9
|
+
QEC LIST List the built-in codes
|
|
10
|
+
QEC STEANE Show a code's stabilizers and logical operators
|
|
11
|
+
LOGICAL_ERROR_RATE STEANE 0.05 Monte-Carlo logical error rate at physical rate p
|
|
12
|
+
THRESHOLD REP 0.0 0.5 11 Sweep p and compare code distances (find the crossing)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import re
|
|
18
|
+
import itertools
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
|
|
22
|
+
# Phase-free single-qubit Pauli multiplication (we only need the group structure).
|
|
23
|
+
_PMUL = {
|
|
24
|
+
('I', 'I'): 'I', ('I', 'X'): 'X', ('I', 'Y'): 'Y', ('I', 'Z'): 'Z',
|
|
25
|
+
('X', 'I'): 'X', ('X', 'X'): 'I', ('X', 'Y'): 'Z', ('X', 'Z'): 'Y',
|
|
26
|
+
('Y', 'I'): 'Y', ('Y', 'X'): 'Z', ('Y', 'Y'): 'I', ('Y', 'Z'): 'X',
|
|
27
|
+
('Z', 'I'): 'Z', ('Z', 'X'): 'Y', ('Z', 'Y'): 'X', ('Z', 'Z'): 'I',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _anticommute(a: str, b: str) -> int:
|
|
32
|
+
"""1 if Pauli strings a and b anticommute, else 0."""
|
|
33
|
+
cnt = 0
|
|
34
|
+
for pa, pb in zip(a, b):
|
|
35
|
+
if pa != 'I' and pb != 'I' and pa != pb:
|
|
36
|
+
cnt ^= 1
|
|
37
|
+
return cnt
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _pmul(a: str, b: str) -> str:
|
|
41
|
+
return ''.join(_PMUL[(pa, pb)] for pa, pb in zip(a, b))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _weight(p: str) -> int:
|
|
45
|
+
return sum(1 for c in p if c != 'I')
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class QECMixin:
|
|
49
|
+
"""Stabilizer codes, decoding, and logical error rates for QBasicTerminal.
|
|
50
|
+
|
|
51
|
+
Requires: TerminalProtocol — uses self._eval_with_vars(), self._seed, self.io.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def _qec_code(self, name: str, distance: int = 3) -> dict:
|
|
55
|
+
"""Return a code descriptor: data qubit count, stabilizers, logical X/Z,
|
|
56
|
+
distance, and the error alphabet the decoder corrects."""
|
|
57
|
+
name = name.upper()
|
|
58
|
+
if name in ('REP', 'REPETITION', 'BITFLIP'):
|
|
59
|
+
d = distance if distance % 2 == 1 else distance + 1
|
|
60
|
+
stab = []
|
|
61
|
+
for i in range(d - 1):
|
|
62
|
+
s = ['I'] * d
|
|
63
|
+
s[i] = 'Z'; s[i + 1] = 'Z'
|
|
64
|
+
stab.append(''.join(s))
|
|
65
|
+
return {'n': d, 'stab': stab, 'lx': 'X' * d, 'lz': 'Z' + 'I' * (d - 1),
|
|
66
|
+
'd': d, 'alphabet': 'IX', 'name': f'repetition d={d}'}
|
|
67
|
+
if name == 'STEANE':
|
|
68
|
+
Hm = [[0, 0, 0, 1, 1, 1, 1], [0, 1, 1, 0, 0, 1, 1], [1, 0, 1, 0, 1, 0, 1]]
|
|
69
|
+
stab = [''.join('X' if b else 'I' for b in row) for row in Hm]
|
|
70
|
+
stab += [''.join('Z' if b else 'I' for b in row) for row in Hm]
|
|
71
|
+
return {'n': 7, 'stab': stab, 'lx': 'X' * 7, 'lz': 'Z' * 7,
|
|
72
|
+
'd': 3, 'alphabet': 'IXYZ', 'name': 'Steane [[7,1,3]]'}
|
|
73
|
+
if name == 'SHOR':
|
|
74
|
+
stab = []
|
|
75
|
+
for b in range(3):
|
|
76
|
+
base = b * 3
|
|
77
|
+
for a, c in ((base, base + 1), (base + 1, base + 2)):
|
|
78
|
+
s = ['I'] * 9; s[a] = 'Z'; s[c] = 'Z'; stab.append(''.join(s))
|
|
79
|
+
stab.append('XXXXXX' + 'III')
|
|
80
|
+
stab.append('III' + 'XXXXXX')
|
|
81
|
+
return {'n': 9, 'stab': stab, 'lx': 'X' * 9, 'lz': 'ZIIZIIZII',
|
|
82
|
+
'd': 3, 'alphabet': 'IXYZ', 'name': 'Shor [[9,1,3]]'}
|
|
83
|
+
if name in ('SURFACE', 'SURF'):
|
|
84
|
+
return self._surface_code(distance)
|
|
85
|
+
raise ValueError(f"unknown code '{name}' (try REP, STEANE, SHOR, SURFACE; QEC LIST)")
|
|
86
|
+
|
|
87
|
+
def _surface_code(self, d: int) -> dict:
|
|
88
|
+
"""Rotated surface code of odd distance d (d^2 data qubits on a d x d grid).
|
|
89
|
+
|
|
90
|
+
Bulk faces are weight-4 stabilizers alternating X/Z by checkerboard parity;
|
|
91
|
+
boundary faces are weight-2, X on the top/bottom edges and Z on the
|
|
92
|
+
left/right edges. Logical X is an X string along the top row, logical Z a
|
|
93
|
+
Z string down the left column. The construction is validated by the
|
|
94
|
+
caller's checks (it must correct every weight-1 error)."""
|
|
95
|
+
if d % 2 == 0:
|
|
96
|
+
d += 1
|
|
97
|
+
n = d * d
|
|
98
|
+
|
|
99
|
+
def idx(r, c):
|
|
100
|
+
return r * d + c
|
|
101
|
+
|
|
102
|
+
stab = []
|
|
103
|
+
for r in range(-1, d):
|
|
104
|
+
for c in range(-1, d):
|
|
105
|
+
corners = [(r, c), (r, c + 1), (r + 1, c), (r + 1, c + 1)]
|
|
106
|
+
qs = [idx(i, j) for (i, j) in corners if 0 <= i < d and 0 <= j < d]
|
|
107
|
+
if len(qs) < 2:
|
|
108
|
+
continue
|
|
109
|
+
typ = 'Z' if (r + c) % 2 == 0 else 'X'
|
|
110
|
+
if len(qs) == 4:
|
|
111
|
+
stab.append((typ, qs))
|
|
112
|
+
else:
|
|
113
|
+
on_tb = (r == -1 or r == d - 1)
|
|
114
|
+
on_lr = (c == -1 or c == d - 1)
|
|
115
|
+
if on_tb and not on_lr and typ == 'X':
|
|
116
|
+
stab.append((typ, qs))
|
|
117
|
+
elif on_lr and not on_tb and typ == 'Z':
|
|
118
|
+
stab.append((typ, qs))
|
|
119
|
+
stab_strs = []
|
|
120
|
+
for typ, qs in stab:
|
|
121
|
+
s = ['I'] * n
|
|
122
|
+
for q in qs:
|
|
123
|
+
s[q] = typ
|
|
124
|
+
stab_strs.append(''.join(s))
|
|
125
|
+
# Logical X runs down a column (between the top/bottom X boundaries);
|
|
126
|
+
# logical Z runs along a row (between the left/right Z boundaries). They
|
|
127
|
+
# cross at qubit 0 and so anticommute.
|
|
128
|
+
lx = ['I'] * n
|
|
129
|
+
for r in range(d):
|
|
130
|
+
lx[idx(r, 0)] = 'X'
|
|
131
|
+
lz = ['I'] * n
|
|
132
|
+
for c in range(d):
|
|
133
|
+
lz[idx(0, c)] = 'Z'
|
|
134
|
+
return {'n': n, 'stab': stab_strs, 'lx': ''.join(lx), 'lz': ''.join(lz),
|
|
135
|
+
'd': d, 'alphabet': 'IXYZ', 'name': f'rotated surface d={d}'}
|
|
136
|
+
|
|
137
|
+
def _qec_decoder(self, code: dict) -> dict:
|
|
138
|
+
"""Build the minimum-weight lookup decoder: syndrome -> recovery Pauli.
|
|
139
|
+
|
|
140
|
+
Enumerates every error over the code's alphabet, keeping the lowest-weight
|
|
141
|
+
representative per syndrome. Optimal for these small codes."""
|
|
142
|
+
n = code['n']
|
|
143
|
+
stab = code['stab']
|
|
144
|
+
alphabet = code['alphabet']
|
|
145
|
+
table: dict = {}
|
|
146
|
+
for combo in itertools.product(alphabet, repeat=n):
|
|
147
|
+
err = ''.join(combo)
|
|
148
|
+
synd = tuple(_anticommute(err, s) for s in stab)
|
|
149
|
+
w = _weight(err)
|
|
150
|
+
if synd not in table or w < table[synd][1]:
|
|
151
|
+
table[synd] = (err, w)
|
|
152
|
+
return {synd: err for synd, (err, _w) in table.items()}
|
|
153
|
+
|
|
154
|
+
def _random_pauli_error(self, code: dict, p: float, rng) -> str:
|
|
155
|
+
"""Sample an i.i.d. error per qubit: X for a bit-flip code, depolarizing else."""
|
|
156
|
+
n = code['n']
|
|
157
|
+
out = []
|
|
158
|
+
if code['alphabet'] == 'IX':
|
|
159
|
+
for _ in range(n):
|
|
160
|
+
out.append('X' if rng.random() < p else 'I')
|
|
161
|
+
else:
|
|
162
|
+
for _ in range(n):
|
|
163
|
+
r = rng.random()
|
|
164
|
+
if r < p:
|
|
165
|
+
out.append('XYZ'[rng.integers(3)])
|
|
166
|
+
else:
|
|
167
|
+
out.append('I')
|
|
168
|
+
return ''.join(out)
|
|
169
|
+
|
|
170
|
+
def _logical_error_rate(self, code: dict, p: float, trials: int, rng, uf: bool = False) -> float:
|
|
171
|
+
decoder = None if uf else self._qec_decoder(code)
|
|
172
|
+
stab, lx, lz = code['stab'], code['lx'], code['lz']
|
|
173
|
+
fails = 0
|
|
174
|
+
for _ in range(trials):
|
|
175
|
+
err = self._random_pauli_error(code, p, rng)
|
|
176
|
+
synd = tuple(_anticommute(err, s) for s in stab)
|
|
177
|
+
recovery = self._qec_matching_decode(code, synd) if uf \
|
|
178
|
+
else decoder.get(synd, 'I' * code['n'])
|
|
179
|
+
residual = _pmul(err, recovery)
|
|
180
|
+
if _anticommute(residual, lx) or _anticommute(residual, lz):
|
|
181
|
+
fails += 1
|
|
182
|
+
return fails / trials
|
|
183
|
+
|
|
184
|
+
def _qec_matching_decode(self, code: dict, syndrome) -> str:
|
|
185
|
+
"""Union-find / matching decoder: minimum-weight matching of syndrome
|
|
186
|
+
defects on the matching graph, correcting the connecting qubits.
|
|
187
|
+
|
|
188
|
+
Scalable alternative to the exponential lookup table (it never enumerates
|
|
189
|
+
all errors). Defects are matched to each other or to the boundary by exact
|
|
190
|
+
minimum-weight matching over shortest paths, and the path qubits flipped.
|
|
191
|
+
"""
|
|
192
|
+
import functools
|
|
193
|
+
from collections import deque
|
|
194
|
+
n = code['n']
|
|
195
|
+
stabs = code['stab']
|
|
196
|
+
xr = ['I'] * n
|
|
197
|
+
zr = ['I'] * n
|
|
198
|
+
for etype, dtype, rec in (('X', 'Z', xr), ('Z', 'X', zr)):
|
|
199
|
+
det = [i for i, s in enumerate(stabs) if set(s) - {'I'} == {dtype}]
|
|
200
|
+
defects = tuple(i for i in det if syndrome[i])
|
|
201
|
+
if not defects:
|
|
202
|
+
continue
|
|
203
|
+
adj = {i: [] for i in det}
|
|
204
|
+
adj['B'] = []
|
|
205
|
+
for q in range(n):
|
|
206
|
+
touch = [i for i in det if stabs[i][q] == dtype]
|
|
207
|
+
if len(touch) == 2:
|
|
208
|
+
adj[touch[0]].append((touch[1], q)); adj[touch[1]].append((touch[0], q))
|
|
209
|
+
elif len(touch) == 1:
|
|
210
|
+
adj[touch[0]].append(('B', q)); adj['B'].append((touch[0], q))
|
|
211
|
+
|
|
212
|
+
def bfs(src):
|
|
213
|
+
prev = {src: (None, None)}
|
|
214
|
+
dq = deque([src])
|
|
215
|
+
while dq:
|
|
216
|
+
u = dq.popleft()
|
|
217
|
+
for v, q in adj.get(u, []):
|
|
218
|
+
if v not in prev:
|
|
219
|
+
prev[v] = (u, q); dq.append(v)
|
|
220
|
+
return prev
|
|
221
|
+
|
|
222
|
+
prevs = {s: bfs(s) for s in defects}
|
|
223
|
+
|
|
224
|
+
def path_qubits(src, tgt):
|
|
225
|
+
prev = prevs[src]
|
|
226
|
+
qs, node = [], tgt
|
|
227
|
+
while node != src and prev.get(node, (None, None))[0] is not None:
|
|
228
|
+
par, q = prev[node]
|
|
229
|
+
qs.append(q); node = par
|
|
230
|
+
return qs
|
|
231
|
+
|
|
232
|
+
def dist(src, tgt):
|
|
233
|
+
return len(path_qubits(src, tgt)) if tgt in prevs[src] else 10 ** 9
|
|
234
|
+
|
|
235
|
+
@functools.lru_cache(maxsize=None)
|
|
236
|
+
def solve(rem):
|
|
237
|
+
if not rem:
|
|
238
|
+
return (0, ())
|
|
239
|
+
i, rest = rem[0], rem[1:]
|
|
240
|
+
best_c, best_m = dist(i, 'B') + solve(rest)[0], ((i, 'B'),) + solve(rest)[1]
|
|
241
|
+
for k, j in enumerate(rest):
|
|
242
|
+
sub = solve(rest[:k] + rest[k + 1:])
|
|
243
|
+
c = dist(i, j) + sub[0]
|
|
244
|
+
if c < best_c:
|
|
245
|
+
best_c, best_m = c, ((i, j),) + sub[1]
|
|
246
|
+
return (best_c, best_m)
|
|
247
|
+
|
|
248
|
+
_, matches = solve(defects)
|
|
249
|
+
for a, b in matches:
|
|
250
|
+
for q in path_qubits(a, b):
|
|
251
|
+
rec[q] = etype
|
|
252
|
+
out = []
|
|
253
|
+
for q in range(n):
|
|
254
|
+
x, z = xr[q] == 'X', zr[q] == 'Z'
|
|
255
|
+
out.append('Y' if (x and z) else 'X' if x else 'Z' if z else 'I')
|
|
256
|
+
return ''.join(out)
|
|
257
|
+
|
|
258
|
+
def cmd_distill(self, rest: str) -> None:
|
|
259
|
+
"""DISTILL <p> [trials] — 15-to-1 magic-state (T-state) distillation.
|
|
260
|
+
|
|
261
|
+
Models the protocol's error detection by the [15,11,3] Hamming code:
|
|
262
|
+
15 noisy T-states (Z error rate p), accept on a trivial syndrome, and a
|
|
263
|
+
logical output error occurs only for an undetected nonzero codeword. The
|
|
264
|
+
output error rate scales as ~35 p^3, well below the input p."""
|
|
265
|
+
parts = rest.split()
|
|
266
|
+
if not parts:
|
|
267
|
+
self.io.writeln("?USAGE: DISTILL <p> [trials]")
|
|
268
|
+
return
|
|
269
|
+
try:
|
|
270
|
+
p = float(self._eval_with_vars(parts[0], {}))
|
|
271
|
+
trials = int(parts[1]) if len(parts) > 1 else 200000
|
|
272
|
+
# [15,11,3] Hamming parity-check matrix: columns are 1..15 in binary.
|
|
273
|
+
H = np.array([[ (c >> b) & 1 for c in range(1, 16)] for b in range(4)])
|
|
274
|
+
rng = np.random.default_rng(self._seed)
|
|
275
|
+
accepted = 0
|
|
276
|
+
errors = 0
|
|
277
|
+
for _ in range(trials):
|
|
278
|
+
e = (rng.random(15) < p).astype(int)
|
|
279
|
+
synd = H.dot(e) % 2
|
|
280
|
+
if not synd.any(): # accept: trivial syndrome
|
|
281
|
+
accepted += 1
|
|
282
|
+
if e.any(): # nonzero codeword -> logical error
|
|
283
|
+
errors += 1
|
|
284
|
+
acc = accepted / trials
|
|
285
|
+
p_out = errors / accepted if accepted else 0.0
|
|
286
|
+
self.io.writeln(f"\n 15-to-1 magic-state distillation:")
|
|
287
|
+
self.io.writeln(f" input error p = {p:g}")
|
|
288
|
+
self.io.writeln(f" acceptance rate = {acc:.4f}")
|
|
289
|
+
self.io.writeln(f" output error p_out = {p_out:.3e} (~35 p^3 = {35 * p ** 3:.3e})")
|
|
290
|
+
self.io.writeln(f" suppression p/p_out= {p / p_out:.1f}x" if p_out > 0 else
|
|
291
|
+
" output error: none observed")
|
|
292
|
+
self.variables['_DISTILL_POUT'] = p_out
|
|
293
|
+
except Exception as e:
|
|
294
|
+
self.io.writeln(f"?DISTILL ERROR: {e}")
|
|
295
|
+
|
|
296
|
+
def cmd_lattice(self, rest: str) -> None:
|
|
297
|
+
"""LATTICE <stateA> <stateB> — lattice-surgery logical ZZ measurement.
|
|
298
|
+
|
|
299
|
+
Encodes two distance-3 repetition logical qubits in the given logical
|
|
300
|
+
states (0, 1, +, -), then performs a merge that measures the joint
|
|
301
|
+
operator Zbar_A Zbar_B (the basis of a lattice-surgery CNOT) via an
|
|
302
|
+
ancilla, and reports the logical parity outcome."""
|
|
303
|
+
parts = rest.split()
|
|
304
|
+
if len(parts) < 2:
|
|
305
|
+
self.io.writeln("?USAGE: LATTICE <stateA> <stateB> (states: 0, 1, +, -)")
|
|
306
|
+
return
|
|
307
|
+
from qiskit import QuantumCircuit, transpile
|
|
308
|
+
from qiskit_aer import AerSimulator
|
|
309
|
+
try:
|
|
310
|
+
sa, sb = parts[0], parts[1]
|
|
311
|
+
# 3 data qubits per patch (A: 0-2, B: 3-5) + 1 merge ancilla (6).
|
|
312
|
+
qc = QuantumCircuit(7, 1)
|
|
313
|
+
|
|
314
|
+
def encode(base, state):
|
|
315
|
+
if state in ('1',):
|
|
316
|
+
qc.x(base)
|
|
317
|
+
elif state in ('+', '-'):
|
|
318
|
+
qc.h(base)
|
|
319
|
+
if state == '-':
|
|
320
|
+
qc.z(base)
|
|
321
|
+
qc.cx(base, base + 1); qc.cx(base, base + 2) # repetition encode
|
|
322
|
+
encode(0, sa); encode(3, sb)
|
|
323
|
+
# Merge: measure Zbar_A Zbar_B = Z_{A0} Z_{B0} via an ancilla.
|
|
324
|
+
anc = 6
|
|
325
|
+
qc.h(anc)
|
|
326
|
+
qc.cz(anc, 0)
|
|
327
|
+
qc.cz(anc, 3)
|
|
328
|
+
qc.h(anc)
|
|
329
|
+
qc.measure(anc, 0)
|
|
330
|
+
backend = AerSimulator(noise_model=self._noise_model) if self._noise_model else AerSimulator()
|
|
331
|
+
counts = backend.run(transpile(qc, backend), shots=max(500, self.shots)).result().get_counts()
|
|
332
|
+
par = '+1 (even)' if counts.get('0', 0) >= counts.get('1', 0) else '-1 (odd)'
|
|
333
|
+
self.io.writeln(f"\n Lattice surgery: merge of |{sa}>_L (A) and |{sb}>_L (B)")
|
|
334
|
+
self.io.writeln(f" joint Zbar_A Zbar_B measurement -> {par} {dict(counts)}")
|
|
335
|
+
self.io.writeln(f" (a deterministic joint parity for computational inputs; the "
|
|
336
|
+
f"building block of a lattice-surgery CNOT)")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
self.io.writeln(f"?LATTICE ERROR: {e}")
|
|
339
|
+
|
|
340
|
+
# ── Commands ────────────────────────────────────────────────────────
|
|
341
|
+
|
|
342
|
+
def cmd_qec(self, rest: str) -> None:
|
|
343
|
+
"""QEC LIST | QEC <code> [distance] — show a stabilizer code.
|
|
344
|
+
|
|
345
|
+
Lists the built-in codes, or prints a code's stabilizer generators and
|
|
346
|
+
logical operators (and verifies they form a valid code)."""
|
|
347
|
+
arg = rest.strip().upper()
|
|
348
|
+
if not arg or arg == 'LIST':
|
|
349
|
+
self.io.writeln("\n Built-in QEC codes:")
|
|
350
|
+
self.io.writeln(" REP [d] repetition / bit-flip code, odd distance d (default 3)")
|
|
351
|
+
self.io.writeln(" STEANE [[7,1,3]] CSS code")
|
|
352
|
+
self.io.writeln(" SHOR [[9,1,3]] code")
|
|
353
|
+
self.io.writeln(" SURFACE [d] rotated surface code, odd distance d (default 3)")
|
|
354
|
+
self.io.writeln(" Decoders: optimal lookup (default), union-find (LOGICAL_ERROR_RATE ... UF)")
|
|
355
|
+
return
|
|
356
|
+
parts = arg.split()
|
|
357
|
+
try:
|
|
358
|
+
d = int(parts[1]) if len(parts) > 1 else 3
|
|
359
|
+
code = self._qec_code(parts[0], d)
|
|
360
|
+
except Exception as e:
|
|
361
|
+
self.io.writeln(f"?QEC ERROR: {e}")
|
|
362
|
+
return
|
|
363
|
+
self.io.writeln(f"\n {code['name']}: {code['n']} data qubits, distance {code['d']}")
|
|
364
|
+
self.io.writeln(f" Stabilizers ({len(code['stab'])}):")
|
|
365
|
+
for s in code['stab']:
|
|
366
|
+
self.io.writeln(f" {s}")
|
|
367
|
+
self.io.writeln(f" Logical X: {code['lx']}")
|
|
368
|
+
self.io.writeln(f" Logical Z: {code['lz']}")
|
|
369
|
+
# Validity self-check: logicals commute with every stabilizer and
|
|
370
|
+
# anticommute with each other.
|
|
371
|
+
ok = bool(all(not _anticommute(code['lx'], s) for s in code['stab'])
|
|
372
|
+
and all(not _anticommute(code['lz'], s) for s in code['stab'])
|
|
373
|
+
and _anticommute(code['lx'], code['lz']))
|
|
374
|
+
self.io.writeln(f" Valid code (logicals normalize the stabilizer group): {ok}")
|
|
375
|
+
|
|
376
|
+
def cmd_logical_error_rate(self, rest: str) -> None:
|
|
377
|
+
"""LOGICAL_ERROR_RATE <code> [distance] <p> [trials] — Monte-Carlo logical error rate.
|
|
378
|
+
|
|
379
|
+
Injects i.i.d. physical errors at rate p, extracts the syndrome, decodes
|
|
380
|
+
with the optimal lookup decoder, applies the recovery, and reports the
|
|
381
|
+
fraction of trials left with a logical error."""
|
|
382
|
+
parts = rest.split()
|
|
383
|
+
if len(parts) < 2:
|
|
384
|
+
self.io.writeln("?USAGE: LOGICAL_ERROR_RATE <code> [distance] <p> [trials]")
|
|
385
|
+
return
|
|
386
|
+
try:
|
|
387
|
+
name = parts[0]
|
|
388
|
+
idx = 1
|
|
389
|
+
distance = 3
|
|
390
|
+
if len(parts) > 2 and parts[1].isdigit() and float(parts[1]) >= 1:
|
|
391
|
+
distance = int(parts[1]); idx = 2
|
|
392
|
+
uf = any(t.upper() in ('UF', 'UNION-FIND', 'MATCHING') for t in parts)
|
|
393
|
+
tail = [t for t in parts[idx:] if t.upper() not in ('UF', 'UNION-FIND', 'MATCHING')]
|
|
394
|
+
p = float(self._eval_with_vars(tail[0], {}))
|
|
395
|
+
trials = int(tail[1]) if len(tail) > 1 else 20000
|
|
396
|
+
code = self._qec_code(name, distance)
|
|
397
|
+
rng = np.random.default_rng(self._seed)
|
|
398
|
+
ler = self._logical_error_rate(code, p, trials, rng, uf=uf)
|
|
399
|
+
self.io.writeln(f"\n {code['name']}: physical p={p}, {trials} trials"
|
|
400
|
+
f"{' (union-find decoder)' if uf else ' (lookup decoder)'}")
|
|
401
|
+
self.io.writeln(f" Logical error rate = {ler:.6f}")
|
|
402
|
+
self.variables['_LER'] = ler
|
|
403
|
+
except Exception as e:
|
|
404
|
+
self.io.writeln(f"?LOGICAL_ERROR_RATE ERROR: {e}")
|
|
405
|
+
|
|
406
|
+
def cmd_threshold(self, rest: str) -> None:
|
|
407
|
+
"""THRESHOLD <code> <p1> <p2> <steps> [d1 d2 ...] — sweep physical error rate.
|
|
408
|
+
|
|
409
|
+
Reports the logical error rate across [p1, p2] for several code distances
|
|
410
|
+
(default 3, 5, 7 for the repetition code), so the threshold crossing where
|
|
411
|
+
larger codes start helping is visible."""
|
|
412
|
+
parts = rest.split()
|
|
413
|
+
if len(parts) < 4:
|
|
414
|
+
self.io.writeln("?USAGE: THRESHOLD <code> <p1> <p2> <steps> [distances]")
|
|
415
|
+
return
|
|
416
|
+
try:
|
|
417
|
+
name = parts[0]
|
|
418
|
+
p1 = float(self._eval_with_vars(parts[1], {}))
|
|
419
|
+
p2 = float(self._eval_with_vars(parts[2], {}))
|
|
420
|
+
steps = int(parts[3])
|
|
421
|
+
distances = [int(x) for x in parts[4:]] if len(parts) > 4 else [3, 5, 7]
|
|
422
|
+
ps = [p1 + (p2 - p1) * i / max(1, steps - 1) for i in range(steps)]
|
|
423
|
+
codes = [self._qec_code(name, d) for d in distances]
|
|
424
|
+
rng = np.random.default_rng(self._seed)
|
|
425
|
+
trials = 8000
|
|
426
|
+
self.io.writeln(f"\n Threshold sweep ({name.upper()}), {trials} trials/point:")
|
|
427
|
+
self.io.writeln(" p " + ''.join(f" d={c['d']:<8}" for c in codes))
|
|
428
|
+
for p in ps:
|
|
429
|
+
row = f" {p:5.3f} "
|
|
430
|
+
for c in codes:
|
|
431
|
+
row += f" {self._logical_error_rate(c, p, trials, rng):<8.4f}"
|
|
432
|
+
self.io.writeln(row)
|
|
433
|
+
except Exception as e:
|
|
434
|
+
self.io.writeln(f"?THRESHOLD ERROR: {e}")
|
|
@@ -98,12 +98,13 @@ _ALL_COMMANDS = [
|
|
|
98
98
|
'MINIMIZE', 'GRADIENT', 'FIDELITY', 'TOMOGRAPHY', 'COUPLING', 'BASIS',
|
|
99
99
|
'LOADQASM', 'SET_DENSITY', 'SAVEPNG', 'PTOMOGRAPHY', 'RB', 'MEASURE',
|
|
100
100
|
'HAMILTONIAN', 'EVOLVE', 'LINDBLAD', 'CHANNEL', 'APPLYCHANNEL',
|
|
101
|
-
'QEC', 'LOGICAL_ERROR_RATE', 'THRESHOLD',
|
|
101
|
+
'QEC', 'LOGICAL_ERROR_RATE', 'THRESHOLD', 'DISTILL', 'LATTICE',
|
|
102
102
|
'XEB', 'QVOLUME', 'RBINT', 'MIRROR', 'GST', 'CONCURRENCE', 'NEGATIVITY',
|
|
103
103
|
'IQPE', 'AMPEST', 'AMPLIFY', 'QWALK', 'GRAPHSTATE', 'FEATUREMAP', 'QKERNEL',
|
|
104
104
|
'SHOR', 'HHL', 'PAULIPROP',
|
|
105
105
|
'QUDIT', 'QX', 'QZ', 'QF', 'QSUM', 'QSTATE', 'QMEASURE',
|
|
106
106
|
'BOSONIC', 'DISPLACE', 'SQUEEZE', 'CAT', 'BS', 'BSTATE',
|
|
107
|
+
'RESOURCES', 'DEVICE', 'OPTIMIZE',
|
|
107
108
|
# Gates
|
|
108
109
|
'H', 'X', 'Y', 'Z', 'S', 'T', 'SDG', 'TDG', 'SX', 'ID',
|
|
109
110
|
'RX', 'RY', 'RZ', 'P', 'U', 'CX', 'CZ', 'CY', 'CH',
|