Skip to content

Commit 6b6a7ff

Browse files
authored
Fix global phase computation in matrix gate decomposition (#7482)
Fixes #7473 Old code with `cirq.unitary(circuit)` performs the unitary assuming the qubit order is ascending based on the qubit id. (The identity operator in that code helped when some qubits were factored out during decomposition, but didn't help with ordering). Changed to `circuit.unitary(qubits, qubits)` to make the qubit order explicit. The first one defines the ordering to be the same as the decomposed matrixgate, and the second makes sure that all qubits are retained even if the decomposition factored some out)
1 parent 3031b1f commit 6b6a7ff

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

cirq-core/cirq/ops/matrix_gates.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from cirq import _import, linalg, protocols
2424
from cirq._compat import proper_repr
25-
from cirq.ops import global_phase_op, identity, phased_x_z_gate, raw_types
25+
from cirq.ops import global_phase_op, phased_x_z_gate, raw_types
2626

2727
if TYPE_CHECKING:
2828
import cirq
@@ -170,8 +170,8 @@ def _decompose_(self, qubits: tuple[cirq.Qid, ...]) -> cirq.OP_TREE:
170170
return NotImplemented
171171
# The above algorithms ignore phase, but phase is important to maintain if the gate is
172172
# controlled. Here, we add it back in with a global phase op.
173-
ident = identity.IdentityGate(qid_shape=self._qid_shape).on(*qubits) # Preserve qid order
174-
u = protocols.unitary(Circuit(ident, *decomposed)).reshape(self._matrix.shape)
173+
circuit = Circuit(*decomposed)
174+
u = circuit.unitary(qubit_order=qubits, qubits_that_should_be_present=qubits)
175175
phase_delta = linalg.phase_delta(u, self._matrix)
176176
# Phase delta is on the complex unit circle, so if real(phase_delta) >= 1, that means
177177
# no phase delta. (>1 is rounding error).

cirq-core/cirq/ops/matrix_gates_test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,16 @@ def test_matrixgate_name_serialization():
413413
gate_after_serialization3 = cirq.read_json(json_text=cirq.to_json(gate3))
414414
assert gate3._name == ''
415415
assert gate_after_serialization3._name == ''
416+
417+
418+
def test_decompose_when_qubits_not_in_ascending_order():
419+
# Previous code for preserving global phase would misorder qubits
420+
q0, q1 = cirq.LineQubit.range(2)
421+
circuit1 = cirq.Circuit()
422+
matrix = cirq.testing.random_unitary(4, random_state=0)
423+
circuit1.append(cirq.MatrixGate(matrix).on(q1, q0))
424+
u1 = cirq.unitary(circuit1)
425+
decomposed = cirq.decompose(circuit1)
426+
circuit2 = cirq.Circuit(decomposed)
427+
u2 = cirq.unitary(circuit2)
428+
np.testing.assert_allclose(u1, u2, atol=1e-14)

0 commit comments

Comments
 (0)