mimiqcircuits.decomposition.basis¶
Decomposition bases for quantum circuits.
- Available bases:
CanonicalBasis: Decomposes to GateU + GateCX (default)CliffordTBasis: Decomposes to Clifford+T gate setFlattenedBasis: Flattens container operationsQASMBasis: Decomposes to OpenQASM 2.0 gate setStimBasis: Decomposes to Stim Clifford gate setRuleBasis: Wraps a RewriteRule as a DecompositionBasis
- class mimiqcircuits.decomposition.basis.CanonicalBasis[source]¶
Bases:
DecompositionBasisDecomposition basis targeting the canonical primitive gate set.
- The canonical basis decomposes all operations to a minimal set of primitives:
GateU: Arbitrary single-qubit unitaryGateCX: Two-qubit CNOT gateMeasure,Reset: Measurement and reset operationsBarrier: Scheduling barriersClassical operations, annotations, noise channels
This is the default basis used by
decompose().Example
>>> from mimiqcircuits import Circuit, GateH, GateCCX >>> from mimiqcircuits.decomposition import decompose, CanonicalBasis >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instruction: └── H @ q[0] >>> c.push(GateCCX(), 0, 1, 2) 3-qubit circuit with 2 instructions: ├── H @ q[0] └── C₂X @ q[0:1], q[2] >>> decomposed = decompose(c, CanonicalBasis()) >>> # All gates are now GateU or GateCX
- isterminal(op)[source]¶
Check if an operation is terminal in the canonical basis.
- Terminal operations include:
Core gates: GateU, GateCX
Measurement/reset: Measure, Reset and variants
Control flow: Barrier, IfStatement (if inner op is terminal)
Classical operations, annotations
Noise channels, expectation values
Z-register operations: Add, Multiply, Pow
Delay (timing information)
- decompose(op, qubits, bits, zvars)[source]¶
Decompose a non-terminal operation using canonical rewrite.
- Parameters:
- Returns:
A Circuit containing the decomposed instructions.
- Raises:
DecompositionError – If the operation cannot be decomposed.
- Return type:
- class mimiqcircuits.decomposition.basis.CliffordTBasis(sk_depth=None, rotations=None)[source]¶
Bases:
DecompositionBasisDecomposition basis targeting the Clifford+T gate set.
Clifford+T is the standard universal gate set of error-corrected quantum computing. The terminal operations of this basis are those of
StimBasisplusGateTandGateTDG, so the two bases always keep the same Clifford and stabilizer operations:single-qubit Cliffords:
GateID,GateX,GateY,GateZ,GateH,GateHXY,GateHYZ,GateS,GateSDG,GateSX,GateSXDG,GateSY,GateSYDG;two-qubit Cliffords:
GateCX,GateCY,GateCZ,GateSWAP,GateISWAP,GateISWAPDG,GateDCX,GateECR;Pauli rotations by
+-pi/2:GateRXX,GateRYY,GateRZZ, andRPauliwith a non-identity Pauli string;the non-Clifford
GateTandGateTDG;measurements, resets and measure-and-resets in the X, Y and Z bases,
MeasureXX,MeasureYY,MeasureZZandMeasurePauli;Pauli noise:
PauliX,PauliY,PauliZ,Depolarizing1,Depolarizing2andPauliNoise;barriers and annotations;
classical operations, which
StimBasisdoes not keep;an
IfStatementwhose body is terminal in this basis, with any condition.StimBasisonly keeps a conditionalGateX,GateYorGateZon a single bit.
Non-terminal operations are rewritten by the first rule that matches, in this order:
SpecialAngleRewrite: rotations by multiples ofpi/4to exact Clifford+T.ToffoliToCliffordTRewrite:GateCCXto Clifford+T with 7 T gates.A
GateUwhose angles are all zero (a pure global phase) is dropped.ZYZRewrite:GateUtoRZ*RY*RZ.ToZRotationRewrite:GateRX,GateRYtoGateRZand Cliffords.The
rotationsrule (defaultGridSynthRewrite): remainingGateRZto an approximate Clifford+T sequence.CanonicalRewrite: any other operation, towardGateUandGateCX.
The
rotationsrule only sees angles that step 1 could not decompose exactly. The body of anIfStatementgoes through the same pipeline and stays conditional. No T-count optimization is performed on the result.- Parameters:
sk_depth (int | None) – Use
SolovayKitaevRewritewith this recursion depth as therotationsrule.rotations (RewriteRule) – Rule that synthesizes the remaining Z-rotations. The default
GridSynthRewrite()approximates each rotation to operator-norm error1e-10. The rule must matchGateRZwith a numeric angle and emit only gates of this basis.
- Raises:
ValueError – If both
sk_depthandrotationsare given, or ifrotationsdoes not matchGateRZ.
Decomposing an operation that no rule handles, such as a noise channel other than the Pauli ones above, raises a
DecompositionError.Example
>>> from mimiqcircuits import Circuit, GateH, GateT, GateRZ >>> from mimiqcircuits.decomposition import decompose, CliffordTBasis >>> from mimiqcircuits.decomposition import GridSynthRewrite >>> from symengine import pi >>> c = Circuit() >>> c.push(GateRZ(pi/4), 0) # special angle, decomposed exactly 1-qubit circuit with 1 instruction: └── RZ((1/4)*pi) @ q[0] >>> decomposed = decompose(c, CliffordTBasis())
>>> # An arbitrary angle is approximated to 1e-10 by gridsynth >>> c2 = Circuit() >>> c2.push(GateRZ(0.123), 0) 1-qubit circuit with 1 instruction: └── RZ(0.123) @ q[0] >>> decomposed2 = decompose(c2, CliffordTBasis())
>>> # A looser error bound per rotation gives fewer T gates >>> basis = CliffordTBasis(rotations=GridSynthRewrite(epsilon=1e-6)) >>> decomposed3 = decompose(c2, basis)
>>> # Solovay-Kitaev instead of gridsynth >>> decomposed4 = decompose(c2, CliffordTBasis(sk_depth=0))
- rotations: RewriteRule¶
- decompose(op, qubits, bits, zvars)[source]¶
Decompose a non-terminal operation toward Clifford+T.
Applies the rules listed in the class docstring, in that order.
- Parameters:
- Returns:
A Circuit containing the decomposed instructions.
- Raises:
DecompositionError – If the operation cannot be decomposed.
- Return type:
- class mimiqcircuits.decomposition.basis.FlattenedBasis[source]¶
Bases:
DecompositionBasisFlatten container operations while leaving all other operations untouched.
- class mimiqcircuits.decomposition.basis.QASMBasis[source]¶
Bases:
DecompositionBasisDecomposition basis targeting the OpenQASM 2.0 gate library.
The terminal gates are the OpenQASM 2.0 built-ins and the gates of the
qelib1.incinclude file that have a direct MIMIQ counterpart, so a decomposed circuit can be written as OpenQASM 2.0 and read back by any parser that ships the standardqelib1.inc.Terminal Operations¶
- Fundamental gates (OpenQASM 2.0 built-in):
GateU,GateCX
- Single-qubit gates from qelib1.inc:
Legacy U gates:
GateU3,GateU2,GateU1Pauli:
GateID,GateX,GateY,GateZHadamard:
GateHPhase:
GateS,GateSDG,GateT,GateTDGRotations:
GateRX,GateRY,GateRZ
- Two-qubit gates from qelib1.inc:
Controlled Paulis and Hadamard:
GateCY,GateCZ,GateCHControlled rotations:
GateCRX,GateCRY,GateCRZGateSWAPIsing couplings:
GateRXX,GateRZZ
- Three- and four-qubit gates from qelib1.inc:
GateCCX,GateCSWAP,GateC3X
- Non-unitary operations:
Measure,Reset,BarrierIfStatementwhose inner operation is terminal
- Custom gates:
GateCallwhose declaration contains only terminal operations
Every other operation is decomposed through
CanonicalRewrite. Operations that OpenQASM 2.0 cannot express and that have no decomposition into the gates above (noise channels, classical operations, annotations, Z-register operations, …) raiseDecompositionError.MeasureResetdecomposes intoMeasurefollowed byReset. This leaves the same state and bit as its canonical decomposition, a measurement and anXconditioned on its outcome, and unlike that conditional it can be written for a circuit of any number of bits. OpenQASM 2.0 has no loops, soWhileStatementraisesDecompositionError.Example
>>> from mimiqcircuits import Circuit, GateH, GateCCX >>> from mimiqcircuits.decomposition import decompose, QASMBasis >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instruction: └── H @ q[0] >>> c.push(GateCCX(), 0, 1, 2) 3-qubit circuit with 2 instructions: ├── H @ q[0] └── C₂X @ q[0:1], q[2] >>> # Decompose to QASM-compatible gates >>> qasm_circuit = decompose(c, QASMBasis())
See also
- decompose(op, qubits, bits, zvars)[source]¶
Decompose a non-terminal operation using canonical rewrite.
- Parameters:
- Returns:
A Circuit containing the decomposed instructions.
- Raises:
DecompositionError – If the operation cannot be decomposed.
- Return type:
- class mimiqcircuits.decomposition.basis.RuleBasis(rule)[source]¶
Bases:
DecompositionBasisA decomposition basis that recursively applies a single rewrite rule.
This allows any
RewriteRuleto be used directly as a decomposition basis. The rule is applied recursively until no more operations match.An operation is terminal if the rule does not match it.
- Parameters:
rule (RewriteRule) – The rewrite rule to apply.
Example
>>> from mimiqcircuits import Circuit, GateH >>> from mimiqcircuits.decomposition import decompose, RuleBasis, ZYZRewrite >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instruction: └── H @ q[0] >>> # Decompose using ZYZ rewrite rule >>> decomposed = decompose(c, RuleBasis(ZYZRewrite()))
- rule: RewriteRule¶
- decompose(op, qubits, bits, zvars)[source]¶
Apply the rewrite rule to decompose the operation.
- Parameters:
- Returns:
A Circuit containing the decomposed instructions.
- Return type:
- __init__(rule)¶
- class mimiqcircuits.decomposition.basis.StimBasis[source]¶
Bases:
DecompositionBasisDecomposition basis targeting the Stim stabilizer simulator gate set.
Stim is a high-performance stabilizer circuit simulator by Craig Gidney. It supports only Clifford gates, stabilizer operations, noise channels, and quantum error correction annotations.
Decomposition Pipeline¶
The decomposition follows this priority order:
A
GateUwhose angles are all zero (a pure global phase) is dropped.ZYZRewrite:
GateU->RZ * RY * RZSpecialAngleRewrite (Clifford-only): Rotations at
k*pi/2-> Clifford gatesCanonicalRewrite: Fallback for other gates
Non-Clifford rotations (angles not multiples of pi/2) will raise a
DecompositionError.Terminal Operations¶
- Single-qubit Clifford gates:
GateIDPauli:
GateX,GateY,GateZHadamard:
GateH,GateHXY,GateHYZPhase gates:
GateS,GateSDGSquare root gates:
GateSX,GateSXDG,GateSY,GateSYDG
- Two-qubit Clifford gates:
Controlled Pauli:
GateCX,GateCY,GateCZSwap family:
GateSWAP,GateISWAP,ISWAP†GateDCX,GateECR
- Pauli rotations by +-pi/2:
GateRXX,GateRYY,GateRZZwith angle +-pi/2RPauliwith angle +-pi/2 and a non-identity Pauli string
Angles are compared modulo 2*pi, since a rotation by 3*pi/2 equals a rotation by -pi/2 up to a global phase. Other angles are decomposed.
- Feedback:
IfStatementofGateX,GateYorGateZconditioned on a single bit being1. The same gate conditioned on the bit being0is decomposed into the gate followed by the gate conditioned on1. Any other conditional operation has its body decomposed while staying conditional, and raises aDecompositionErrorif that does not lead to a conditional Pauli.
- Measurements (all Pauli bases):
Measure,MeasureX,MeasureYTwo-qubit parities:
MeasureXX,MeasureYY,MeasureZZPauli products:
MeasurePauli
- Resets (all Pauli bases):
Reset,ResetX,ResetY
- Measure-and-reset (all Pauli bases):
MeasureReset,MeasureResetX,MeasureResetY
- Noise channels:
PauliX,PauliY,PauliZDepolarizing1,Depolarizing2PauliNoise
- QEC annotations:
Detector,ObservableInclude,QubitCoordinatesBarrier
Stim Gate Mapping¶
MIMIQ Operation
Stim Operation
GateIDIGateXXGateYYGateZZGateHHGateHXYH_XYGateHYZH_YZGateSSGateSDGS_DAGGateSXSQRT_XGateSXDGSQRT_X_DAGGateSYSQRT_YGateSYDGSQRT_Y_DAGGateCXCNOT/CXGateCYCYGateCZCZGateSWAPSWAPGateISWAPISWAPISWAP†ISWAP_DAGGateDCXDCX(custom)GateECRECR(custom)GateRXX(+-pi/2)SQRT_XX/SQRT_XX_DAGGateRYY(+-pi/2)SQRT_YY/SQRT_YY_DAGGateRZZ(+-pi/2)SQRT_ZZ/SQRT_ZZ_DAGRPauli(P, +-pi/2)SPP/SPP_DAGIfStatement(GateX(), 1)CX rec[-k] qIfStatement(GateY(), 1)CY rec[-k] qIfStatement(GateZ(), 1)CZ rec[-k] qMeasureMMeasureXMXMeasureYMYMeasureXXMXXMeasureYYMYYMeasureZZMZZMeasurePauliMPPResetRResetXRXResetYRYMeasureResetMRMeasureResetXMRXMeasureResetYMRYPauliXX_ERRORPauliYY_ERRORPauliZZ_ERRORDepolarizing1DEPOLARIZE1Depolarizing2DEPOLARIZE2PauliNoisePAULI_CHANNEL_1,PAULI_CHANNEL_2orE/ELSE_CORRELATED_ERRORDetectorDETECTORObservableIncludeOBSERVABLE_INCLUDEQubitCoordinatesQUBIT_COORDSExample
>>> from mimiqcircuits import Circuit, GateH, GateS, GateCX >>> from mimiqcircuits.decomposition import decompose, StimBasis >>> from symengine import pi >>> # Decompose Clifford circuit to Stim-compatible gates >>> c = Circuit() >>> c.push(GateH(), 0) 1-qubit circuit with 1 instruction: └── H @ q[0] >>> c.push(GateS(), 0) 1-qubit circuit with 2 instructions: ├── H @ q[0] └── S @ q[0] >>> c.push(GateCX(), 0, 1) 2-qubit circuit with 3 instructions: ├── H @ q[0] ├── S @ q[0] └── CX @ q[0], q[1] >>> decomposed = decompose(c, StimBasis())
>>> # RZ(pi/2) = S is Clifford, so this works >>> from mimiqcircuits import GateRZ >>> c2 = Circuit() >>> c2.push(GateRZ(pi/2), 0) 1-qubit circuit with 1 instruction: └── RZ((1/2)*pi) @ q[0] >>> decomposed2 = decompose(c2, StimBasis())
Note
- Non-Clifford rotations will raise a DecompositionError::
>>> from mimiqcircuits import * >>> c3 = Circuit() >>> c3.push(GateRZ(pi/4), 0) # T gate is non-Clifford 1-qubit circuit with 1 instruction: └── RZ((1/4)*pi) @ q[0] >>> decompose(c3, StimBasis()) # raises DecompositionError doctest: +ELLIPSIS Traceback (most recent call last): ... mimiqcircuits.decomposition.abstract.DecompositionError: Rotation RZ cannot be decomposed into the Stim basis. Only rotations with angles that are multiples of pi/2 are Clifford gates.
See also
- decompose(op, qubits, bits, zvars)[source]¶
Decompose a non-terminal operation toward the Stim Clifford gate set.
- Applies rules in priority order:
Drops a GateU whose angles are all zero (a global phase)
ZYZRewrite for GateU
SpecialAngleRewrite (Clifford-only) for rotations at k*pi/2
CanonicalRewrite as fallback
Non-Clifford rotations (angles not multiples of pi/2) will raise an error.
- Parameters:
- Returns:
A Circuit containing the decomposed instructions.
- Raises:
DecompositionError – If the operation cannot be decomposed to Clifford gates.
- Return type:
Modules
Canonical decomposition basis targeting GateU and GateCX. |
|
Clifford+T decomposition basis. |
|
Flattened decomposition basis. |
|
OpenQASM 2.0 decomposition basis. |
|
RuleBasis: Wrapper to use a RewriteRule as a DecompositionBasis. |
|
Stim stabilizer simulator decomposition basis. |