Skip to content
Open
11 changes: 8 additions & 3 deletions qiskit/circuit/library/templates/clifford/clifford_6_4.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
# that they have been altered from the originals.


from math import pi

from qiskit.circuit.quantumcircuit import QuantumCircuit


Expand All @@ -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.
Expand All @@ -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
11 changes: 7 additions & 4 deletions qiskit/circuit/library/templates/rzx/rzx_xz.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ├»
└───────┘ └──────────┘»
Comment on lines -28 to 32
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! The circuit drawer indeed draws "Rz" instead of "RZ".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this drawings should be fixed in all the RZX templates, not only the ones that had global phase issues.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ShellyGarion, would you like to open a "good first issue" about this?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is already a PR to orgaize the template library #16131 , so let's move this comment there.

« ┌─────────┐┌─────────┐┌─────────┐
«q_0: ┤ RZ(π/2) ├┤ RX(π/2) ├┤ RZ(π/2) ├
«q_0: ┤ Rz(π/2) ├┤ Rx(π/2) ├┤ Rz(π/2) ├
« └─────────┘└─────────┘└─────────┘
«q_1: ─────────────────────────────────
«
Expand All @@ -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
11 changes: 7 additions & 4 deletions qiskit/circuit/library/templates/rzx/rzx_zz1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
9 changes: 6 additions & 3 deletions qiskit/circuit/library/templates/rzx/rzx_zz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
9 changes: 6 additions & 3 deletions qiskit/circuit/library/templates/rzx/rzx_zz3.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/Qiskit/qiskit/issues/14538>`__.
Comment on lines +4 to +9
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the sentence: Each of these templates implements the identity only up to a global phase..., is it clear that "only up to the global phase" was before the fix, while now the templates implement the identity exactly?

8 changes: 6 additions & 2 deletions test/python/circuit/test_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__":
Expand Down
1 change: 0 additions & 1 deletion test/python/transpiler/test_template_matching.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down