uniqc.compile.decompose module

IR-level decomposition of OriginIR-native gates to lower-level equivalents.

Two decomposition targets share the same helper infrastructure:

QASM 2.0 target (decompose_for_qasm2())

Rewrites RPhi, RPhi90, RPhi180, PHASE2Q, UU15 into gates in qelib1.inc so that cloud parsers (Quafu / QuarkStudio / IBM) accept the output without custom gate ... { ... } blocks.

Official OriginIR target (decompose_for_originir())

Rewrites all OriginIR-ext gates (above plus ECR, ISWAP, XX, YY, ZZ, XY) into the strict official OriginIR gate set (H, X, Y, Z, S, SX, T, I, RX, RY, RZ, U1, U2, U3, CNOT, CZ, SWAP, TOFFOLI, CSWAP) for submission to OriginQ cloud.

Gate

Replacement (official OriginIR opcode names)

RPhi

RZ(-phi); RX(theta); RZ(phi)

RPhi90

RZ(-phi); RX(pi/2); RZ(phi)

RPhi180

RZ(-phi); RX(pi); RZ(phi)

PHASE2Q

U1(t1) q1; U1(t2) q2; CU1(tzz) (q1->q2)

UU15

U3 U3; XX; YY; ZZ; U3 U3 (KAK form)

ECR

X q2; RX(π/2) q1; CNOT q1→q2; S† q1; RX(-π/2) q2; X q1

ISWAP

S q1; S q2; H q1; CNOT q1→q2; CNOT q2→q1; H q2

XX

H q1; H q2; CNOT q1→q2; RZ(θ) q2; CNOT q1→q2; H q1; H q2

YY

RX(π/2) q1,q2; CNOT q1→q2; RZ(θ) q2; CNOT q1→q2; RX(-π/2) q1,q2

ZZ

CNOT q1→q2; RZ(θ) q2; CNOT q1→q2

XY

XX(-θ/2); YY(-θ/2)

The decomposition preserves the dagger flag by reversing the replacement sequence and negating angle parameters where appropriate. Gate instances wrapped with control_qubits are not currently decomposed; doing so requires lifting each replacement gate to its controlled form, which is out of scope for this pass — call compile() explicitly first if you need that.

uniqc.compile.decompose.decompose_for_originir(circuit)[source]

Return a new Circuit with OriginIR-ext gates decomposed.

All OriginIR-ext-only gates (ECR, ISWAP, XX, YY, ZZ, XY, RPhi, RPhi90, RPhi180, PHASE2Q, UU15) are rewritten into mathematically equivalent sequences of official OriginIR gates. The original circuit is not mutated.

When the input contains no extended gate, the original circuit is returned unchanged (no copy).

Examples

>>> from uniqc.circuit_builder import Circuit
>>> c = Circuit(2)
>>> c.iswap(0, 1)
>>> c.xx(0, 1, 0.5)
>>> c2 = decompose_for_originir(c)
>>> {op[0] for op in c2.opcode_list}.isdisjoint(ORIGINIR_EXT_DECOMPOSABLE_GATES)
True
Parameters:

circuit (Circuit)

Return type:

Circuit

uniqc.compile.decompose.decompose_for_qasm2(circuit)[source]

Return a new Circuit with QASM2-unrepresentable gates rewritten.

The original circuit is not mutated. When the input contains no gate in QASM2_UNREPRESENTABLE_GATES, this returns a shallow copy.

Examples

>>> from uniqc.circuit_builder import Circuit
>>> c = Circuit(2)
>>> c.rphi(0, 0.4, 0.7)
>>> c.add_gate("PHASE2Q", [0, 1], params=[0.1, 0.2, 0.3])
>>> c2 = decompose_for_qasm2(c)
>>> {op[0] for op in c2.opcode_list}.isdisjoint({"RPhi", "PHASE2Q"})
True
Parameters:

circuit (Circuit)

Return type:

Circuit

uniqc.compile.decompose.decompose_opcode_for_originir(op)[source]

Return replacement opcodes for op if it is an OriginIR-ext-only gate.

Returns [op] unchanged when op is already an official OriginIR gate. Raises NotImplementedError when the gate is extended but wrapped with control_qubits.

Parameters:

op (tuple[str, int | list[int], int | list[int] | None, float | list[float] | tuple[float, ...] | None, bool, int | list[int]])

Return type:

list[tuple[str, int | list[int], int | list[int] | None, float | list[float] | tuple[float, …] | None, bool, int | list[int]]]

uniqc.compile.decompose.decompose_opcode_for_qasm2(op)[source]

Return replacement opcodes for op if it is QASM2-unrepresentable.

Returns [op] unchanged when op is already a QASM2-friendly opcode. Raises NotImplementedError when the gate is in QASM2_UNREPRESENTABLE_GATES but is wrapped with control_qubits (controlled-RPhi / controlled-UU15 etc. require a more general lift that this lightweight pass does not provide).

Parameters:

op (tuple[str, int | list[int], int | list[int] | None, float | list[float] | tuple[float, ...] | None, bool, int | list[int]])

Return type:

list[tuple[str, int | list[int], int | list[int] | None, float | list[float] | tuple[float, …] | None, bool, int | list[int]]]