mimiqcircuits.decomposition.basis

Decomposition bases for quantum circuits.

Available bases:
class mimiqcircuits.decomposition.basis.CanonicalBasis[source]

Bases: DecompositionBasis

Decomposition basis targeting the canonical primitive gate set.

The canonical basis decomposes all operations to a minimal set of primitives:
  • GateU: Arbitrary single-qubit unitary

  • GateCX: Two-qubit CNOT gate

  • Measure, Reset: Measurement and reset operations

  • Barrier: Scheduling barriers

  • Classical 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)

Parameters:

op (Operation) – The operation to check.

Returns:

True if the operation is terminal.

Return type:

bool

decompose(op, qubits, bits, zvars)[source]

Decompose a non-terminal operation using canonical rewrite.

Parameters:
  • op (Operation) – The operation to decompose.

  • qubits (Sequence[int]) – Qubit indices for the operation.

  • bits (Sequence[int]) – Classical bit indices for the operation.

  • zvars (Sequence[int]) – Z-variable indices for the operation.

Returns:

A Circuit containing the decomposed instructions.

Raises:

DecompositionError – If the operation cannot be decomposed.

Return type:

Circuit

class mimiqcircuits.decomposition.basis.CliffordTBasis(sk_depth=None, rotations=None)[source]

Bases: DecompositionBasis

Decomposition 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 StimBasis plus GateT and GateTDG, 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, and RPauli with a non-identity Pauli string;

  • the non-Clifford GateT and GateTDG;

  • measurements, resets and measure-and-resets in the X, Y and Z bases, MeasureXX, MeasureYY, MeasureZZ and MeasurePauli;

  • Pauli noise: PauliX, PauliY, PauliZ, Depolarizing1, Depolarizing2 and PauliNoise;

  • barriers and annotations;

  • classical operations, which StimBasis does not keep;

  • an IfStatement whose body is terminal in this basis, with any condition. StimBasis only keeps a conditional GateX, GateY or GateZ on a single bit.

Non-terminal operations are rewritten by the first rule that matches, in this order:

  1. SpecialAngleRewrite: rotations by multiples of pi/4 to exact Clifford+T.

  2. ToffoliToCliffordTRewrite: GateCCX to Clifford+T with 7 T gates.

  3. A GateU whose angles are all zero (a pure global phase) is dropped.

  4. ZYZRewrite: GateU to RZ*RY*RZ.

  5. ToZRotationRewrite: GateRX, GateRY to GateRZ and Cliffords.

  6. The rotations rule (default GridSynthRewrite): remaining GateRZ to an approximate Clifford+T sequence.

  7. CanonicalRewrite: any other operation, toward GateU and GateCX.

The rotations rule only sees angles that step 1 could not decompose exactly. The body of an IfStatement goes through the same pipeline and stays conditional. No T-count optimization is performed on the result.

Parameters:
  • sk_depth (int | None) – Use SolovayKitaevRewrite with this recursion depth as the rotations rule.

  • rotations (RewriteRule) – Rule that synthesizes the remaining Z-rotations. The default GridSynthRewrite() approximates each rotation to operator-norm error 1e-10. The rule must match GateRZ with a numeric angle and emit only gates of this basis.

Raises:

ValueError – If both sk_depth and rotations are given, or if rotations does not match GateRZ.

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
__init__(sk_depth=None, rotations=None)[source]
isterminal(op)[source]

Check if an operation is terminal in the Clifford+T basis.

Parameters:

op (Operation) – The operation to check.

Returns:

True if the operation is terminal in StimBasis, is GateT, GateTDG or a classical operation, or is an IfStatement whose body is terminal in this basis.

Return type:

bool

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:
  • op (Operation) – The operation to decompose.

  • qubits (Sequence[int]) – Qubit indices for the operation.

  • bits (Sequence[int]) – Classical bit indices for the operation.

  • zvars (Sequence[int]) – Z-variable indices for the operation.

Returns:

A Circuit containing the decomposed instructions.

Raises:

DecompositionError – If the operation cannot be decomposed.

Return type:

Circuit

class mimiqcircuits.decomposition.basis.FlattenedBasis[source]

Bases: DecompositionBasis

Flatten container operations while leaving all other operations untouched.

isterminal(op)[source]

Containers are non-terminal; all other operations are terminal.

decompose(op, qubits, bits, zvars)[source]

Decompose one container expansion step using FlattenContainers.

class mimiqcircuits.decomposition.basis.QASMBasis[source]

Bases: DecompositionBasis

Decomposition basis targeting the OpenQASM 2.0 gate library.

The terminal gates are the OpenQASM 2.0 built-ins and the gates of the qelib1.inc include 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 standard qelib1.inc.

Terminal Operations

Fundamental gates (OpenQASM 2.0 built-in):
  • GateU, GateCX

Single-qubit gates from qelib1.inc:
  • Legacy U gates: GateU3, GateU2, GateU1

  • Pauli: GateID, GateX, GateY, GateZ

  • Hadamard: GateH

  • Phase: GateS, GateSDG, GateT, GateTDG

  • Rotations: GateRX, GateRY, GateRZ

Two-qubit gates from qelib1.inc:
  • Controlled Paulis and Hadamard: GateCY, GateCZ, GateCH

  • Controlled rotations: GateCRX, GateCRY, GateCRZ

  • GateSWAP

  • Ising couplings: GateRXX, GateRZZ

Three- and four-qubit gates from qelib1.inc:
  • GateCCX, GateCSWAP, GateC3X

Non-unitary operations:
  • Measure, Reset, Barrier

  • IfStatement whose inner operation is terminal

Custom gates:
  • GateCall whose 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, …) raise DecompositionError.

MeasureReset decomposes into Measure followed by Reset. This leaves the same state and bit as its canonical decomposition, a measurement and an X conditioned 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, so WhileStatement raises DecompositionError.

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())
isterminal(op)[source]

Check if an operation is terminal in the OpenQASM 2.0 basis.

Parameters:

op (Operation) – The operation to check.

Returns:

True if the operation is in the QASM gate set.

Return type:

bool

decompose(op, qubits, bits, zvars)[source]

Decompose a non-terminal operation using canonical rewrite.

Parameters:
  • op (Operation) – The operation to decompose.

  • qubits (Sequence[int]) – Qubit indices for the operation.

  • bits (Sequence[int]) – Classical bit indices for the operation.

  • zvars (Sequence[int]) – Z-variable indices for the operation.

Returns:

A Circuit containing the decomposed instructions.

Raises:

DecompositionError – If the operation cannot be decomposed.

Return type:

Circuit

class mimiqcircuits.decomposition.basis.RuleBasis(rule)[source]

Bases: DecompositionBasis

A decomposition basis that recursively applies a single rewrite rule.

This allows any RewriteRule to 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
isterminal(op)[source]

Check if the operation is terminal (rule does not match).

Parameters:

op (Operation) – The operation to check.

Returns:

True if the rule does not match this operation.

Return type:

bool

decompose(op, qubits, bits, zvars)[source]

Apply the rewrite rule to decompose the operation.

Parameters:
  • op (Operation) – The operation to decompose.

  • qubits (Sequence[int]) – Qubit indices for the operation.

  • bits (Sequence[int]) – Classical bit indices for the operation.

  • zvars (Sequence[int]) – Z-variable indices for the operation.

Returns:

A Circuit containing the decomposed instructions.

Return type:

Circuit

__init__(rule)
class mimiqcircuits.decomposition.basis.StimBasis[source]

Bases: DecompositionBasis

Decomposition 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:

  1. A GateU whose angles are all zero (a pure global phase) is dropped.

  2. ZYZRewrite: GateU -> RZ * RY * RZ

  3. SpecialAngleRewrite (Clifford-only): Rotations at k*pi/2 -> Clifford gates

  4. CanonicalRewrite: Fallback for other gates

Non-Clifford rotations (angles not multiples of pi/2) will raise a DecompositionError.

Terminal Operations

Single-qubit Clifford gates:
  • GateID

  • Pauli: GateX, GateY, GateZ

  • Hadamard: GateH, GateHXY, GateHYZ

  • Phase gates: GateS, GateSDG

  • Square root gates: GateSX, GateSXDG, GateSY, GateSYDG

Two-qubit Clifford gates:
  • Controlled Pauli: GateCX, GateCY, GateCZ

  • Swap family: GateSWAP, GateISWAP, ISWAP†

  • GateDCX, GateECR

Pauli rotations by +-pi/2:
  • GateRXX, GateRYY, GateRZZ with angle +-pi/2

  • RPauli with 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:
  • IfStatement of GateX, GateY or GateZ conditioned on a single bit being 1. The same gate conditioned on the bit being 0 is decomposed into the gate followed by the gate conditioned on 1. Any other conditional operation has its body decomposed while staying conditional, and raises a DecompositionError if that does not lead to a conditional Pauli.

Measurements (all Pauli bases):
  • Measure, MeasureX, MeasureY

  • Two-qubit parities: MeasureXX, MeasureYY, MeasureZZ

  • Pauli products: MeasurePauli

Resets (all Pauli bases):
  • Reset, ResetX, ResetY

Measure-and-reset (all Pauli bases):
  • MeasureReset, MeasureResetX, MeasureResetY

Noise channels:
  • PauliX, PauliY, PauliZ

  • Depolarizing1, Depolarizing2

  • PauliNoise

QEC annotations:
  • Detector, ObservableInclude, QubitCoordinates

  • Barrier

Stim Gate Mapping

MIMIQ Operation

Stim Operation

GateID

I

GateX

X

GateY

Y

GateZ

Z

GateH

H

GateHXY

H_XY

GateHYZ

H_YZ

GateS

S

GateSDG

S_DAG

GateSX

SQRT_X

GateSXDG

SQRT_X_DAG

GateSY

SQRT_Y

GateSYDG

SQRT_Y_DAG

GateCX

CNOT / CX

GateCY

CY

GateCZ

CZ

GateSWAP

SWAP

GateISWAP

ISWAP

ISWAP†

ISWAP_DAG

GateDCX

DCX (custom)

GateECR

ECR (custom)

GateRXX(+-pi/2)

SQRT_XX / SQRT_XX_DAG

GateRYY(+-pi/2)

SQRT_YY / SQRT_YY_DAG

GateRZZ(+-pi/2)

SQRT_ZZ / SQRT_ZZ_DAG

RPauli(P, +-pi/2)

SPP / SPP_DAG

IfStatement(GateX(), 1)

CX rec[-k] q

IfStatement(GateY(), 1)

CY rec[-k] q

IfStatement(GateZ(), 1)

CZ rec[-k] q

Measure

M

MeasureX

MX

MeasureY

MY

MeasureXX

MXX

MeasureYY

MYY

MeasureZZ

MZZ

MeasurePauli

MPP

Reset

R

ResetX

RX

ResetY

RY

MeasureReset

MR

MeasureResetX

MRX

MeasureResetY

MRY

PauliX

X_ERROR

PauliY

Y_ERROR

PauliZ

Z_ERROR

Depolarizing1

DEPOLARIZE1

Depolarizing2

DEPOLARIZE2

PauliNoise

PAULI_CHANNEL_1, PAULI_CHANNEL_2 or E / ELSE_CORRELATED_ERROR

Detector

DETECTOR

ObservableInclude

OBSERVABLE_INCLUDE

QubitCoordinates

QUBIT_COORDS

Example

>>> 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.
isterminal(op)[source]

Check if an operation is terminal in the Stim basis.

Parameters:

op (Operation) – The operation to check.

Returns:

True if the operation is in the Stim Clifford gate set.

Return type:

bool

decompose(op, qubits, bits, zvars)[source]

Decompose a non-terminal operation toward the Stim Clifford gate set.

Applies rules in priority order:
  1. Drops a GateU whose angles are all zero (a global phase)

  2. ZYZRewrite for GateU

  3. SpecialAngleRewrite (Clifford-only) for rotations at k*pi/2

  4. CanonicalRewrite as fallback

Non-Clifford rotations (angles not multiples of pi/2) will raise an error.

Parameters:
  • op (Operation) – The operation to decompose.

  • qubits (Sequence[int]) – Qubit indices for the operation.

  • bits (Sequence[int]) – Classical bit indices for the operation.

  • zvars (Sequence[int]) – Z-variable indices for the operation.

Returns:

A Circuit containing the decomposed instructions.

Raises:

DecompositionError – If the operation cannot be decomposed to Clifford gates.

Return type:

Circuit

Modules

canonical

Canonical decomposition basis targeting GateU and GateCX.

clifford_t

Clifford+T decomposition basis.

flattened

Flattened decomposition basis.

qasm

OpenQASM 2.0 decomposition basis.

rule_basis

RuleBasis: Wrapper to use a RewriteRule as a DecompositionBasis.

stim

Stim stabilizer simulator decomposition basis.