diff --git a/qiskit/circuit/library/standard_gates/equivalence_library.py b/qiskit/circuit/library/standard_gates/equivalence_library.py index c4619ca27858..93e772ff842d 100644 --- a/qiskit/circuit/library/standard_gates/equivalence_library.py +++ b/qiskit/circuit/library/standard_gates/equivalence_library.py @@ -189,6 +189,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): cphase_to_cu1.append(CU1Gate(theta), [0, 1]) _sel.add_equivalence(CPhaseGate(theta), cphase_to_cu1) +# CPhaseGate +# +# global phase: ϴ/4 +# ┌─────────┐ +# q_0: ─■──── q_0: ─■─────────┤ Rz(ϴ/2) ├ +# │P(ϴ) ≡ │ZZ(-ϴ/2) ├─────────┤ +# q_1: ─■──── q_1: ─■─────────┤ Rz(ϴ/2) ├ +# └─────────┘ +theta = Parameter("theta") +cphase_to_rzz = QuantumCircuit(2, global_phase=theta / 4) +cphase_to_rzz.rzz(-theta / 2, 0, 1) +cphase_to_rzz.rz(theta / 2, 0) +cphase_to_rzz.rz(theta / 2, 1) +_sel.add_equivalence(CPhaseGate(theta), cphase_to_rzz) + # RGate # # ┌────────┐ ┌───────────────────────┐ @@ -394,6 +409,19 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): def_rzx.append(inst, qargs, cargs) _sel.add_equivalence(RZXGate(theta), def_rzx) +# RZXGate to RZZGate +# ┌─────────┐ +# q_0: ┤0 ├ q_0: ──────■─────────── +# │ Rzx(ϴ) │ ≡ ┌───┐ │ZZ(ϴ) ┌───┐ +# q_1: ┤1 ├ q_1: ┤ H ├─■──────┤ H ├ +# └─────────┘ └───┘ └───┘ +theta = Parameter("theta") +rzx_to_rzz = QuantumCircuit(2) +rzx_to_rzz.h(1) +rzx_to_rzz.rzz(theta, 0, 1) +rzx_to_rzz.h(1) +_sel.add_equivalence(RZXGate(theta), rzx_to_rzz) + # RYGate # @@ -654,6 +682,21 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True): rzz_to_rzx.h(1) _sel.add_equivalence(RZZGate(theta), rzz_to_rzx) +# RZZ to CPhase +# +# global phase: ϴ/2 +# ┌───────┐ +# q_0: ─■───── q_0: ─■────────┤ Rz(ϴ) ├ +# │ZZ(ϴ) ≡ │P(-2*ϴ) ├───────┤ +# q_1: ─■───── q_1: ─■────────┤ Rz(ϴ) ├ +# └───────┘ +theta = Parameter("theta") +rzz_to_cphase = QuantumCircuit(2, global_phase=theta / 2) +rzz_to_cphase.cp(-theta * 2, 0, 1) +rzz_to_cphase.rz(theta, 0) +rzz_to_cphase.rz(theta, 1) +_sel.add_equivalence(RZZGate(theta), rzz_to_cphase) + # RZZ to RYY q = QuantumRegister(2, "q") theta = Parameter("theta") diff --git a/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml b/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml new file mode 100644 index 000000000000..9f4d9d384172 --- /dev/null +++ b/releasenotes/notes/cphase-rzz-equivalence-e8afc37b71a74366.yaml @@ -0,0 +1,17 @@ +--- +features_circuits: + - | + The standard equivalence library (:data:`.SessionEquivalenceLibrary`) now has rules that can + directly convert between Qiskit's standard-library 2q continuous Ising-type interactions (e.g. + :class:`.CPhaseGate`, :class:`.RZZGate`, :class:`.RZXGate`, and so on) using local equivalence + relations. Previously, several of these conversions would go via a 2-CX form, which resulted + in less efficient circuit generation. + + .. note:: + + In general, the :class:`.BasisTranslator` is not guaranteed to find the "best" equivalence + relation for a given :class:`.Target`, but will always find an equivalence if one exists. We + rely on more expensive resynthesis and gate-optimization passes in the transpiler to improve + the output. These passes are currently not as effective for basis sets with a continuously + parametrized two-qubit interaction as they are for discrete super-controlled two-qubit + interactions. diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index a517d5d1e4a4..03a041355b87 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -1438,7 +1438,6 @@ def test_control_zero_operand_gate(self, num_ctrl_qubits): @data( RXGate, RYGate, - RZGate, RXXGate, RYYGate, RZXGate,