diff --git a/src/qibo/transpiler/decompositions.py b/src/qibo/transpiler/decompositions.py index 780aa42c99..29d691402a 100644 --- a/src/qibo/transpiler/decompositions.py +++ b/src/qibo/transpiler/decompositions.py @@ -387,6 +387,12 @@ def _u3_to_gpi2(t, p, l): lambda gate: two_qubit_decomposition(0, 1, gate.matrix(backend), backend=backend), ) +# temporary CNOT decompositions for CNOT, CZ, SWAP +cnot_dec_temp = GateDecompositions() +cnot_dec_temp.add(gates.CNOT, [gates.CNOT(0, 1)]) +cnot_dec_temp.add(gates.CZ, [gates.H(1), gates.CNOT(0, 1), gates.H(1)]) +cnot_dec_temp.add(gates.SWAP, [gates.CNOT(0, 1), gates.CNOT(1, 0), gates.CNOT(0, 1)]) + # register other optimized gate decompositions opt_dec = GateDecompositions() opt_dec.add( diff --git a/src/qibo/transpiler/unroller.py b/src/qibo/transpiler/unroller.py index a14aca382d..9032e5e306 100644 --- a/src/qibo/transpiler/unroller.py +++ b/src/qibo/transpiler/unroller.py @@ -4,7 +4,14 @@ from qibo.config import raise_error from qibo.models import Circuit from qibo.transpiler._exceptions import DecompositionError -from qibo.transpiler.decompositions import cz_dec, gpi2_dec, iswap_dec, opt_dec, u3_dec +from qibo.transpiler.decompositions import ( + cnot_dec_temp, + cz_dec, + gpi2_dec, + iswap_dec, + opt_dec, + u3_dec, +) class NativeGates(Flag): @@ -22,6 +29,7 @@ class NativeGates(Flag): - :class:`qibo.gates.gates.U3` - :class:`qibo.gates.gates.CZ` - :class:`qibo.gates.gates.iSWAP` + - :class:`qibo.gates.gates.CNOT` """ I = auto() @@ -32,6 +40,7 @@ class NativeGates(Flag): U3 = auto() CZ = auto() iSWAP = auto() + CNOT = auto() # For testing purposes @classmethod def default(cls): @@ -240,6 +249,13 @@ def _translate_two_qubit_gates(gate: gates.Gate, native_gates: NativeGates): iswap_decomposed.append(g_translated) return iswap_decomposed + # For testing purposes + # No CZ, iSWAP gates in the native gate set + # Decompose CNOT, CZ, SWAP gates into CNOT gates + if native_gates & NativeGates.CNOT: + return cnot_dec_temp(gate) + raise_error( - DecompositionError, "Use only CZ and/or iSWAP as native gates" + DecompositionError, + "Use only CZ and/or iSWAP as native gates. CNOT is allowed in circuits where the two-qubit gates are limited to CZ, CNOT, and SWAP.", ) # pragma: no cover diff --git a/tests/test_transpiler_unroller.py b/tests/test_transpiler_unroller.py index 61e2c11fc1..474d2c50a3 100644 --- a/tests/test_transpiler_unroller.py +++ b/tests/test_transpiler_unroller.py @@ -121,3 +121,36 @@ def test_measurements_non_comp_basis(): assert isinstance(transpiled_circuit.queue[2], gates.M) # After transpiling the measurement gate should be in the computational basis assert transpiled_circuit.queue[2].basis == [] + + +def test_temp_cnot_decomposition(): + from qibo.transpiler.pipeline import Passes + + circ = Circuit(2) + circ.add(gates.H(0)) + circ.add(gates.CNOT(0, 1)) + circ.add(gates.SWAP(0, 1)) + circ.add(gates.CZ(0, 1)) + circ.add(gates.M(0, 1)) + + glist = [gates.GPI2, gates.RZ, gates.Z, gates.M, gates.CNOT] + native_gates = NativeGates(0).from_gatelist(glist) + + custom_pipeline = Passes([Unroller(native_gates=native_gates)]) + transpiled_circuit, _ = custom_pipeline(circ) + + # H + assert transpiled_circuit.queue[0].name == "z" + assert transpiled_circuit.queue[1].name == "gpi2" + # CNOT + assert transpiled_circuit.queue[2].name == "cx" + # SWAP + assert transpiled_circuit.queue[3].name == "cx" + assert transpiled_circuit.queue[4].name == "cx" + assert transpiled_circuit.queue[5].name == "cx" + # CZ + assert transpiled_circuit.queue[6].name == "z" + assert transpiled_circuit.queue[7].name == "gpi2" + assert transpiled_circuit.queue[8].name == "cx" + assert transpiled_circuit.queue[9].name == "z" + assert transpiled_circuit.queue[10].name == "gpi2"