Skip to content
2 changes: 1 addition & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1916,7 +1916,7 @@ def global_phase(self, angle):
Args:
angle (float, ParameterExpression): radians
"""
if isinstance(angle, ParameterExpression):
if isinstance(angle, ParameterExpression) and angle.parameters:
self._global_phase = angle
else:
# Set the phase to the [-2 * pi, 2 * pi] interval
Expand Down
6 changes: 6 additions & 0 deletions qiskit/dagcircuit/dagcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,12 @@ def _full_pred_succ_maps(self, pred_map, succ_map, input_circuit,
return full_pred_map, full_succ_map

def __eq__(self, other):
if (
self.global_phase != other.global_phase
or self.calibrations != other.calibrations
):
return False

return rx.is_isomorphic_node_match(self._multi_graph,
other._multi_graph,
DAGNode.semantic_eq)
Expand Down
6 changes: 4 additions & 2 deletions qiskit/transpiler/passes/basis/basis_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,14 @@ def run(self, dag):
bound_target_dag = circuit_to_dag(target_circuit)
else:
bound_target_dag = target_dag
if bound_target_dag.global_phase:
dag.global_phase += bound_target_dag.global_phase

if (len(bound_target_dag.op_nodes()) == 1
and len(bound_target_dag.op_nodes()[0].qargs) == len(node.qargs)):
dag_op = bound_target_dag.op_nodes()[0].op
dag.substitute_node(node, dag_op, inplace=True)

if bound_target_dag.global_phase:
dag.global_phase += bound_target_dag.global_phase
else:
dag.substitute_node_with_dag(node, bound_target_dag)
else:
Expand Down
3 changes: 0 additions & 3 deletions qiskit/transpiler/passes/basis/unroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,5 @@ def run(self, dag):
(str(self.basis), node.op.name))
decomposition = circuit_to_dag(node.op.definition)
unrolled_dag = self.run(decomposition) # recursively unroll ops
if unrolled_dag.global_phase:
dag.global_phase += unrolled_dag.global_phase
unrolled_dag.global_phase = 0
dag.substitute_node_with_dag(node, unrolled_dag)
return dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
upgrade:
- |
The ``DAGCircuit.__eq__`` method, which is used to check structural equality
of :class:`~qiskit.dagcircuit.DAGCircuit` and :class:`~qiskit.circuit.QuantumCircuit` instances, has been updated to
include the ``global_phase`` and ``calibrations`` attributes in fields
checked for equality.
fixes:
- |
The :class:`~qiskit.transpiler.passes.BasisTranslator` and :class:`~qiskit.transpiler.passes.Unroller` passes, in some cases, had not been
preserving the global phase of the circuit under transpilation. This has
been fixed.
3 changes: 1 addition & 2 deletions test/python/circuit/library/test_grover_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,11 @@ def test_custom_zero_reflection(self):
self.assertGroverOperatorIsCorrect(grover_op, oracle)

with self.subTest('circuits match'):
expected = QuantumCircuit(*grover_op.qregs)
expected = QuantumCircuit(*grover_op.qregs, global_phase=np.pi)
expected.compose(oracle, inplace=True)
expected.h(0) # state_in is H
expected.compose(zero_reflection, inplace=True)
expected.h(0)

self.assertEqual(expected, grover_op)

def test_num_mcx_ancillas(self):
Expand Down
4 changes: 1 addition & 3 deletions test/python/circuit/test_circuit_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit.test import QiskitTestCase
from qiskit.quantum_info import random_unitary


class TestCircuitQasm(QiskitTestCase):
Expand Down Expand Up @@ -176,8 +175,7 @@ def test_circuit_qasm_pi(self):
"""Test circuit qasm() method with pi params.
"""
circuit = QuantumCircuit(2)
circuit.append(random_unitary(4, seed=1234), [0, 1])
circuit = circuit.decompose()
circuit.cz(0, 1)

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.

Was this change made because the random unitary decomposition to qasm and back would lose the global phase and the equality would differ now? FWIW I agree using a random unitary here seems unnecessary since it's testing the pi serialization for qasm, I'm just curious.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That's right, the unitary ends up generating a non-zero global phase that's lost in the back and forth to QASM.

circuit.u(2*pi, 3*pi, -5*pi, 0)
qasm_str = circuit.qasm()
circuit2 = QuantumCircuit.from_qasm_str(qasm_str)
Expand Down
16 changes: 9 additions & 7 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ def test_parameterized_circuit_for_simulator(self):

transpiled_qc = transpile(qc, backend=BasicAer.get_backend('qasm_simulator'))

expected_qc = QuantumCircuit(qr)
expected_qc = QuantumCircuit(qr, global_phase=-1 * theta / 2.0)
expected_qc.append(U1Gate(theta), [qr[0]])

self.assertEqual(expected_qc, transpiled_qc)
Expand All @@ -455,7 +455,7 @@ def test_parameterized_circuit_for_device(self):
initial_layout=Layout.generate_trivial_layout(qr))

qr = QuantumRegister(14, 'q')
expected_qc = QuantumCircuit(qr)
expected_qc = QuantumCircuit(qr, global_phase=-1 * theta / 2.0)
expected_qc.append(U1Gate(theta), [qr[0]])

self.assertEqual(expected_qc, transpiled_qc)
Expand All @@ -472,7 +472,7 @@ def test_parameter_expression_circuit_for_simulator(self):

transpiled_qc = transpile(qc, backend=BasicAer.get_backend('qasm_simulator'))

expected_qc = QuantumCircuit(qr)
expected_qc = QuantumCircuit(qr, global_phase=-1 * square / 2.0)
expected_qc.append(U1Gate(square), [qr[0]])
self.assertEqual(expected_qc, transpiled_qc)

Expand All @@ -490,7 +490,7 @@ def test_parameter_expression_circuit_for_device(self):
initial_layout=Layout.generate_trivial_layout(qr))

qr = QuantumRegister(14, 'q')
expected_qc = QuantumCircuit(qr)
expected_qc = QuantumCircuit(qr, global_phase=-1 * square / 2.0)
expected_qc.append(U1Gate(square), [qr[0]])
self.assertEqual(expected_qc, transpiled_qc)

Expand Down Expand Up @@ -636,7 +636,7 @@ def test_hadamard_to_rot_gates(self):
qc = QuantumCircuit(qr)
qc.h(0)

expected = QuantumCircuit(qr)
expected = QuantumCircuit(qr, global_phase=np.pi/2)
expected.append(RYGate(theta=np.pi/2), [0])
expected.append(RXGate(theta=np.pi), [0])

Expand Down Expand Up @@ -982,14 +982,16 @@ def test_delay_converts_to_dt(self):
@data(1, 2, 3)
def test_no_infinite_loop(self, optimization_level):
"""Verify circuit cost always descends and optimization does not flip flop indefinitely."""

qc = QuantumCircuit(1)
qc.ry(0.2, 0)

out = transpile(qc, basis_gates=['id', 'p', 'sx', 'cx'],
optimization_level=optimization_level)

expected = QuantumCircuit(1)
# Expect a -pi/2 global phase for the U3 to RZ/SX conversion, and
# a -0.5 * theta phase for RZ to P twice, once at theta, and once at 3 pi
# for the second and third RZ gates in the U3 decomposition.
expected = QuantumCircuit(1, global_phase=-np.pi/2 - 0.5 * (0.2 + np.pi) - 0.5 * 3 * np.pi)
expected.sx(0)
expected.p(np.pi + 0.2, 0)
expected.sx(0)
Expand Down
Loading