diff --git a/qiskit/circuit/library/templates/clifford/clifford_6_4.py b/qiskit/circuit/library/templates/clifford/clifford_6_4.py index 5377a99b413c..db7c0f2e8f14 100644 --- a/qiskit/circuit/library/templates/clifford/clifford_6_4.py +++ b/qiskit/circuit/library/templates/clifford/clifford_6_4.py @@ -11,6 +11,8 @@ # that they have been altered from the originals. +from math import pi + from qiskit.circuit.quantumcircuit import QuantumCircuit @@ -20,9 +22,10 @@ def clifford_6_4(): .. code-block:: text - ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ - q_0: ┤ S ├┤ H ├┤ S ├┤ H ├┤ S ├┤ H ├ - └───┘└───┘└───┘└───┘└───┘└───┘ + global phase: 7π/4 + ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ + q: ┤ S ├┤ H ├┤ S ├┤ H ├┤ S ├┤ H ├ + └───┘└───┘└───┘└───┘└───┘└───┘ Returns: QuantumCircuit: template as a quantum circuit. @@ -34,4 +37,6 @@ def clifford_6_4(): qc.h(0) qc.s(0) qc.h(0) + # Add a global phase of -pi/4 to get Operator(qc) == I + qc.global_phase = -pi / 4 return qc diff --git a/qiskit/circuit/library/templates/rzx/rzx_xz.py b/qiskit/circuit/library/templates/rzx/rzx_xz.py index b3c8d3adbbc0..372501ab4cdc 100644 --- a/qiskit/circuit/library/templates/rzx/rzx_xz.py +++ b/qiskit/circuit/library/templates/rzx/rzx_xz.py @@ -24,13 +24,14 @@ def rzx_xz(theta: ParameterValueType | None = None): .. code-block:: text + global phase: π ┌───┐ ┌───┐┌─────────┐┌─────────┐┌─────────┐┌──────────┐» - q_0: ┤ X ├─────────┤ X ├┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├┤0 ├» - └─┬─┘┌───────┐└─┬─┘└─────────┘└─────────┘└─────────┘│ RZX(-ϴ) │» - q_1: ──■──┤ RX(ϴ) ├──■───────────────────────────────────┤1 ├» + q_0: ┤ X ├─────────┤ X ├┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├┤0 ├» + └─┬─┘┌───────┐└─┬─┘└─────────┘└─────────┘└─────────┘│ Rzx(-ϴ) │» + q_1: ──■──┤ Rx(ϴ) ├──■───────────────────────────────────┤1 ├» └───────┘ └──────────┘» « ┌─────────┐┌─────────┐┌─────────┐ - «q_0: ┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├ + «q_0: ┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├ « └─────────┘└─────────┘└─────────┘ «q_1: ───────────────────────────────── « @@ -50,4 +51,6 @@ def rzx_xz(theta: ParameterValueType | None = None): qc.rz(np.pi / 2, 0) qc.rx(np.pi / 2, 0) qc.rz(np.pi / 2, 0) + # Gate content has unitary e^{i*pi} * I == -I; global_phase = pi makes Operator(qc) == I exactly. + qc.global_phase = np.pi return qc diff --git a/qiskit/circuit/library/templates/rzx/rzx_zz1.py b/qiskit/circuit/library/templates/rzx/rzx_zz1.py index 007717ea80f5..2532f9c6b23b 100644 --- a/qiskit/circuit/library/templates/rzx/rzx_zz1.py +++ b/qiskit/circuit/library/templates/rzx/rzx_zz1.py @@ -24,20 +24,21 @@ def rzx_zz1(theta: ParameterValueType | None = None): .. code-block:: text + global phase: π/2 » q_0: ──■────────────────────────────────────────────■───────────────────────» ┌─┴─┐┌───────┐┌────┐┌───────┐┌────┐┌────────┐┌─┴─┐┌────────┐┌─────────┐» - q_1: ┤ X ├┤ RZ(ϴ) ├┤ √X ├┤ RZ(π) ├┤ √X ├┤ RZ(3π) ├┤ X ├┤ RZ(-ϴ) ├┤ RZ(π/2) ├» + q_1: ┤ X ├┤ Rz(ϴ) ├┤ √X ├┤ Rz(π) ├┤ √X ├┤ Rz(3π) ├┤ X ├┤ Rz(-ϴ) ├┤ Rz(π/2) ├» └───┘└───────┘└────┘└───────┘└────┘└────────┘└───┘└────────┘└─────────┘» « ┌──────────┐ » «q_0: ───────────────────────────────┤0 ├──────────────────────» - « ┌─────────┐┌─────────┐┌───────┐│ RZX(-ϴ) │┌─────────┐┌─────────┐» - «q_1: ┤ RX(π/2) ├┤ RZ(π/2) ├┤ RX(ϴ) ├┤1 ├┤ RZ(π/2) ├┤ RX(π/2) ├» + « ┌─────────┐┌─────────┐┌───────┐│ Rzx(-ϴ) │┌─────────┐┌─────────┐» + «q_1: ┤ Rx(π/2) ├┤ Rz(π/2) ├┤ Rx(ϴ) ├┤1 ├┤ Rz(π/2) ├┤ Rx(π/2) ├» « └─────────┘└─────────┘└───────┘└──────────┘└─────────┘└─────────┘» « «q_0: ─────────── « ┌─────────┐ - «q_1: ┤ RZ(π/2) ├ + «q_1: ┤ Rz(π/2) ├ « └─────────┘ """ if theta is None: @@ -64,5 +65,7 @@ def rzx_zz1(theta: ParameterValueType | None = None): qc.rz(np.pi / 2, 1) qc.rx(np.pi / 2, 1) qc.rz(np.pi / 2, 1) + # Gate content has unitary e^{-i*pi/2} * I; global_phase = pi/2 makes Operator(qc) == I exactly. + qc.global_phase = np.pi / 2 return qc diff --git a/qiskit/circuit/library/templates/rzx/rzx_zz2.py b/qiskit/circuit/library/templates/rzx/rzx_zz2.py index 0bb4db011476..13e8c2bf306b 100644 --- a/qiskit/circuit/library/templates/rzx/rzx_zz2.py +++ b/qiskit/circuit/library/templates/rzx/rzx_zz2.py @@ -24,15 +24,16 @@ def rzx_zz2(theta: ParameterValueType | None = None): .. code-block:: text + global phase: π » q_0: ──■────────────■─────────────────────────────────────────────────────» ┌─┴─┐┌──────┐┌─┴─┐┌───────┐┌─────────┐┌─────────┐┌─────────┐┌───────┐» - q_1: ┤ X ├┤ P(ϴ) ├┤ X ├┤ P(-ϴ) ├┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├┤ RX(ϴ) ├» + q_1: ┤ X ├┤ P(ϴ) ├┤ X ├┤ P(-ϴ) ├┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├┤ Rx(ϴ) ├» └───┘└──────┘└───┘└───────┘└─────────┘└─────────┘└─────────┘└───────┘» « ┌──────────┐ «q_0: ┤0 ├───────────────────────────────── - « │ RZX(-ϴ) │┌─────────┐┌─────────┐┌─────────┐ - «q_1: ┤1 ├┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├ + « │ Rzx(-ϴ) │┌─────────┐┌─────────┐┌─────────┐ + «q_1: ┤1 ├┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├ « └──────────┘└─────────┘└─────────┘└─────────┘ """ if theta is None: @@ -54,5 +55,7 @@ def rzx_zz2(theta: ParameterValueType | None = None): qc.rz(np.pi / 2, 1) qc.rx(np.pi / 2, 1) qc.rz(np.pi / 2, 1) + # Gate content has unitary e^{i*pi} * I == -I; global_phase = pi makes Operator(qc) == I exactly. + qc.global_phase = np.pi return qc diff --git a/qiskit/circuit/library/templates/rzx/rzx_zz3.py b/qiskit/circuit/library/templates/rzx/rzx_zz3.py index d62a0ff6b268..a233bf86382f 100644 --- a/qiskit/circuit/library/templates/rzx/rzx_zz3.py +++ b/qiskit/circuit/library/templates/rzx/rzx_zz3.py @@ -24,15 +24,16 @@ def rzx_zz3(theta: ParameterValueType | None = None): .. code-block:: text + global phase: π » q_0: ──■─────────────■──────────────────────────────────────────────────────» ┌─┴─┐┌───────┐┌─┴─┐┌────────┐┌─────────┐┌─────────┐┌─────────┐┌───────┐» - q_1: ┤ X ├┤ RZ(ϴ) ├┤ X ├┤ RZ(-ϴ) ├┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├┤ RX(ϴ) ├» + q_1: ┤ X ├┤ Rz(ϴ) ├┤ X ├┤ Rz(-ϴ) ├┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├┤ Rx(ϴ) ├» └───┘└───────┘└───┘└────────┘└─────────┘└─────────┘└─────────┘└───────┘» « ┌──────────┐ «q_0: ┤0 ├───────────────────────────────── - « │ RZX(-ϴ) │┌─────────┐┌─────────┐┌─────────┐ - «q_1: ┤1 ├┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├ + « │ Rzx(-ϴ) │┌─────────┐┌─────────┐┌─────────┐ + «q_1: ┤1 ├┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├ « └──────────┘└─────────┘└─────────┘└─────────┘ """ if theta is None: @@ -54,5 +55,7 @@ def rzx_zz3(theta: ParameterValueType | None = None): qc.rz(np.pi / 2, 1) qc.rx(np.pi / 2, 1) qc.rz(np.pi / 2, 1) + # Gate content has unitary e^{i*pi} * I == -I; global_phase = pi makes Operator(qc) == I exactly. + qc.global_phase = np.pi return qc diff --git a/releasenotes/notes/fix-clifford-6-4-template-identity-14538.yaml b/releasenotes/notes/fix-clifford-6-4-template-identity-14538.yaml new file mode 100644 index 000000000000..931fae54e90d --- /dev/null +++ b/releasenotes/notes/fix-clifford-6-4-template-identity-14538.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed :func:`.clifford_6_4`, :func:`.rzx_xz`, :func:`.rzx_zz1`, :func:`.rzx_zz2`, + and :func:`.rzx_zz3` templates so that :class:`.TemplateOptimization` now accepts + and applies them. Each of these templates implements the identity only up to a + global phase in their gate content but was missing the compensating ``global_phase`` + field, causing :class:`.TemplateOptimization` to silently reject them on every run. + Fixes `#14538 `__. diff --git a/test/python/circuit/test_templates.py b/test/python/circuit/test_templates.py index a7085aeafafe..076d35f67e50 100644 --- a/test/python/circuit/test_templates.py +++ b/test/python/circuit/test_templates.py @@ -37,11 +37,15 @@ class TestTemplates(QiskitTestCase): @combine(template_circuit=circuits) def test_template(self, template_circuit): - """test to verify that all templates are equivalent to the identity""" + """Test that all templates are exactly equal to the identity (including global phase). + Uses strict Operator equality rather than equiv() so that a template whose + gate content carries a residual global phase (i.e. global_phase is not set + to compensate) is caught as a failure rather than silently accepted. + """ target = Operator(template_circuit) value = Operator(np.eye(2**template_circuit.num_qubits)) - self.assertTrue(target.equiv(value)) + self.assertEqual(target, value) if __name__ == "__main__": diff --git a/test/python/transpiler/test_template_matching.py b/test/python/transpiler/test_template_matching.py index 6d5916b0985e..fcb8fd717297 100644 --- a/test/python/transpiler/test_template_matching.py +++ b/test/python/transpiler/test_template_matching.py @@ -794,7 +794,6 @@ def test_circuit_global_phase_preserved_after_single_and_multiple_template_match def test_template_nonzero_global_phase_applied_to_circuit(self): """Test the template's global phase is respected (#14537).""" - template = QuantumCircuit(1) template.h(0) template.s(0)