Skip to content

Make all non-analytical gate decompositions respect global phase #5420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cirq-core/cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -862,11 +862,11 @@ def _decompose_(self, qubits):

if self._exponent == 1:
yield cirq.Y(q) ** 0.5
yield cirq.XPowGate(global_shift=-0.25).on(q)
yield cirq.XPowGate(global_shift=-0.25 + self.global_shift).on(q)
return

yield YPowGate(exponent=0.25).on(q)
yield XPowGate(exponent=self._exponent).on(q)
yield XPowGate(exponent=self._exponent, global_shift=self.global_shift).on(q)
yield YPowGate(exponent=-0.25).on(q)

def _circuit_diagram_info_(
Expand Down Expand Up @@ -1134,7 +1134,7 @@ def _decompose_into_clifford_with_qubits_(self, qubits):
def _decompose_(self, qubits):
c, t = qubits
yield YPowGate(exponent=-0.5).on(t)
yield CZ(c, t) ** self._exponent
yield cirq.CZPowGate(exponent=self._exponent, global_shift=self.global_shift).on(c, t)
yield YPowGate(exponent=0.5).on(t)

def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
Expand Down
4 changes: 1 addition & 3 deletions cirq-core/cirq/ops/common_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ def test_phase_insensitive_eigen_gates_consistent_protocols(eigen_gate_type):

@pytest.mark.parametrize('eigen_gate_type', [cirq.CNotPowGate, cirq.HPowGate])
def test_phase_sensitive_eigen_gates_consistent_protocols(eigen_gate_type):
cirq.testing.assert_eigengate_implements_consistent_protocols(
eigen_gate_type, ignoring_global_phase=True
)
cirq.testing.assert_eigengate_implements_consistent_protocols(eigen_gate_type)


def test_cz_init():
Expand Down
7 changes: 2 additions & 5 deletions cirq-core/cirq/ops/phased_iswap_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ def test_phased_iswap_has_consistent_protocols(phase_exponent, exponent, global_
cirq.testing.assert_implements_consistent_protocols(
cirq.PhasedISwapPowGate(
phase_exponent=phase_exponent, exponent=exponent, global_shift=global_shift
),
ignoring_global_phase=False,
)
)


Expand Down Expand Up @@ -206,6 +205,4 @@ def test_givens_rotation_equivalent_circuit():

@pytest.mark.parametrize('angle_rads', (-np.pi / 5, 0.4, 2, np.pi))
def test_givens_rotation_has_consistent_protocols(angle_rads):
cirq.testing.assert_implements_consistent_protocols(
cirq.givens(angle_rads), ignoring_global_phase=False
)
cirq.testing.assert_implements_consistent_protocols(cirq.givens(angle_rads))
4 changes: 1 addition & 3 deletions cirq-core/cirq/ops/swap_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,4 @@ def test_riswap_hamiltonian(angle_rads):

@pytest.mark.parametrize('angle_rads', (-np.pi / 5, 0.4, 2, np.pi))
def test_riswap_has_consistent_protocols(angle_rads):
cirq.testing.assert_implements_consistent_protocols(
cirq.riswap(angle_rads), ignoring_global_phase=False
)
cirq.testing.assert_implements_consistent_protocols(cirq.riswap(angle_rads))
21 changes: 16 additions & 5 deletions cirq-core/cirq/ops/three_qubit_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
raw_types,
swap_gates,
raw_types,
global_phase_op,
)

if TYPE_CHECKING:
Expand Down Expand Up @@ -117,8 +118,13 @@ def _decompose_(self, qubits):

p = common_gates.T**self._exponent
sweep_abc = [common_gates.CNOT(a, b), common_gates.CNOT(b, c)]

return [
global_phase = 1j ** (2 * self.global_shift * self._exponent)
global_phase_operation = (
[global_phase_op.global_phase_operation(global_phase)]
if protocols.is_parameterized(global_phase) or abs(global_phase - 1.0) > 0
else []
)
return global_phase_operation + [
p(a),
p(b),
p(c),
Expand Down Expand Up @@ -337,8 +343,13 @@ def _decompose_(self, qubits):
]
phase_solutions = phase_matrix_inverse.dot(shifted_angles_tail)
p_gates = [pauli_gates.Z ** (solution / np.pi) for solution in phase_solutions]

return [
global_phase = 1j ** (2 * self._diag_angles_radians[0] / np.pi)
global_phase_operation = (
[global_phase_op.global_phase_operation(global_phase)]
if protocols.is_parameterized(global_phase) or abs(global_phase - 1.0) > 0
else []
)
return global_phase_operation + [
p_gates[0](a),
p_gates[1](b),
p_gates[2](c),
Expand Down Expand Up @@ -460,7 +471,7 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs') -> np.ndarray:
def _decompose_(self, qubits):
c1, c2, t = qubits
yield common_gates.H(t)
yield CCZ(c1, c2, t) ** self._exponent
yield CCZPowGate(exponent=self._exponent, global_shift=self.global_shift).on(c1, c2, t)
yield common_gates.H(t)

def _circuit_diagram_info_(
Expand Down
22 changes: 9 additions & 13 deletions cirq-core/cirq/ops/three_qubit_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,21 @@

@pytest.mark.parametrize('eigen_gate_type', [cirq.CCXPowGate, cirq.CCZPowGate])
def test_eigen_gates_consistent_protocols(eigen_gate_type):
cirq.testing.assert_eigengate_implements_consistent_protocols(
eigen_gate_type, ignoring_global_phase=True
)
cirq.testing.assert_eigengate_implements_consistent_protocols(eigen_gate_type)


@pytest.mark.parametrize(
'gate,ignoring_global_phase',
'gate',
(
(cirq.CSWAP, False),
(cirq.ThreeQubitDiagonalGate([2, 3, 5, 7, 11, 13, 17, 19]), True),
(cirq.ThreeQubitDiagonalGate([0, 0, 0, 0, 0, 0, 0, 0]), True),
(cirq.CCX, False),
(cirq.CCZ, False),
(cirq.CSWAP),
(cirq.ThreeQubitDiagonalGate([2, 3, 5, 7, 11, 13, 17, 19])),
(cirq.ThreeQubitDiagonalGate([0, 0, 0, 0, 0, 0, 0, 0])),
(cirq.CCX),
(cirq.CCZ),
),
)
def test_consistent_protocols(gate, ignoring_global_phase):
cirq.testing.assert_implements_consistent_protocols(
gate, ignoring_global_phase=ignoring_global_phase
)
def test_consistent_protocols(gate):
cirq.testing.assert_implements_consistent_protocols(gate)


def test_init():
Expand Down