From 507a0c154e006c94e62e96c3d9238300a3e6ff58 Mon Sep 17 00:00:00 2001 From: Dave Bacon Date: Fri, 26 Jun 2020 08:17:19 -0700 Subject: [PATCH 1/2] Only override control when global phase is zero --- cirq/ops/common_gates.py | 28 ++++++++++++++++++++++++---- cirq/ops/common_gates_test.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/cirq/ops/common_gates.py b/cirq/ops/common_gates.py index c32e1afa39e..24e753d9b40 100644 --- a/cirq/ops/common_gates.py +++ b/cirq/ops/common_gates.py @@ -136,11 +136,16 @@ def controlled(self, a generic qudit) and where the control is satisfied by the qubit being ON, as opposed to OFF. + Note that this only transforms into a CXPowGate (or controlled version + of that gate) if the global shift of the XPowGate is 0, otherwise + it produces a normal ControlledGate. + (Note that a CXPowGate is, by definition, a controlled-XPowGate.) """ result = super().controlled(num_controls, control_values, control_qid_shape) - if (isinstance(result, controlled_gate.ControlledGate) and + if (self._global_shift == 0 and + isinstance(result, controlled_gate.ControlledGate) and result.control_values[-1] == (1,) and result.control_qid_shape[-1] == 2): return cirq.CXPowGate(exponent=self._exponent, @@ -454,11 +459,16 @@ def controlled(self, a generic qudit) and where the control is satisfied by the qubit being ON, as opposed to OFF. + Note that this only transforms into a CZPowGate (or controlled version + of that gate) if the global shift of the ZPowGate is 0, otherwise + it produces a normal ControlledGate. + (Note that a CZPowGate is, by definition, a controlled-ZPowGate.) """ result = super().controlled(num_controls, control_values, control_qid_shape) - if (isinstance(result, controlled_gate.ControlledGate) and + if (self._global_shift == 0 and + isinstance(result, controlled_gate.ControlledGate) and result.control_values[-1] == (1,) and result.control_qid_shape[-1] == 2): return cirq.CZPowGate(exponent=self._exponent, @@ -805,11 +815,16 @@ def controlled(self, a generic qudit) and where the control is satisfied by the qubit being ON, as opposed to OFF. + Note that this only transforms into a CCZPowGate (or controlled version + of that gate) if the global shift of the CZPowGate is 0, otherwise + it produces a normal ControlledGate. + (Note that a CCZPowGate is, by definition, a controlled-CZPowGate.) """ result = super().controlled(num_controls, control_values, control_qid_shape) - if (isinstance(result, controlled_gate.ControlledGate) and + if (self._global_shift == 0 and + isinstance(result, controlled_gate.ControlledGate) and result.control_values[-1] == (1,) and result.control_qid_shape[-1] == 2): return cirq.CCZPowGate(exponent=self._exponent, @@ -971,11 +986,16 @@ def controlled(self, a generic qudit) and where the control is satisfied by the qubit being ON, as opposed to OFF. + Note that this only transforms into a CCXPowGate (or controlled version + of that gate) if the global shift of the CXPowGate is 0, otherwise + it produces a normal ControlledGate. + (Note that a CCXPowGate is, by definition, a controlled-CXPowGate.) """ result = super().controlled(num_controls, control_values, control_qid_shape) - if (isinstance(result, controlled_gate.ControlledGate) and + if (self._global_shift == 0 and + isinstance(result, controlled_gate.ControlledGate) and result.control_values[-1] == (1,) and result.control_qid_shape[-1] == 2): return cirq.CCXPowGate(exponent=self._exponent, diff --git a/cirq/ops/common_gates_test.py b/cirq/ops/common_gates_test.py index 7a268572e00..c6610c09701 100644 --- a/cirq/ops/common_gates_test.py +++ b/cirq/ops/common_gates_test.py @@ -183,6 +183,35 @@ def test_specialized_control(input_gate, specialized_output): input_gate, num_controls=3, control_qid_shape=(3, 2, 4)) +@pytest.mark.parametrize( + 'gate, specialized_type', + [(cirq.ZPowGate(global_shift=-0.5, exponent=0.5), cirq.CZPowGate), + (cirq.CZPowGate(global_shift=-0.5, exponent=0.5), cirq.CCZPowGate), + (cirq.XPowGate(global_shift=-0.5, exponent=0.5), cirq.CXPowGate), + (cirq.CXPowGate(global_shift=-0.5, exponent=0.5), cirq.CCXPowGate)]) +def test_no_specialized_control_for_global_shift_non_zero( + gate, specialized_type): + assert not isinstance(gate.controlled(), specialized_type) + + +@pytest.mark.parametrize( + 'gate, matrix', + [(cirq.ZPowGate(global_shift=-0.5, exponent=1), np.diag([1, 1, -1j, 1j])), + (cirq.CZPowGate(global_shift=-0.5, + exponent=1), np.diag([1, 1, 1, 1, -1j, -1j, -1j, 1j])), + (cirq.XPowGate(global_shift=-0.5, exponent=1), + np.block([[np.eye(2), np.zeros( + (2, 2))], [np.zeros( + (2, 2)), np.array([[0, -1j], [-1j, 0]])]])), + (cirq.CXPowGate(global_shift=-0.5, exponent=1), + np.block([[np.diag([1, 1, 1, 1, -1j, -1j]), + np.zeros((6, 2))], + [np.zeros( + (2, 6)), np.array([[0, -1j], [-1j, 0]])]]))]) +def test_global_phase_controlled_gate(gate, matrix): + np.testing.assert_equal(cirq.unitary(gate.controlled()), matrix) + + def test_rot_gates_eq(): eq = cirq.testing.EqualsTester() gates = [ From 380cd8d1b4a28a34c69e825b4c29869bead188b2 Mon Sep 17 00:00:00 2001 From: Dave Bacon Date: Mon, 29 Jun 2020 16:09:05 -0700 Subject: [PATCH 2/2] Combine doc string paragraphs --- cirq/ops/common_gates.py | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/cirq/ops/common_gates.py b/cirq/ops/common_gates.py index 24e753d9b40..bbb7b630006 100644 --- a/cirq/ops/common_gates.py +++ b/cirq/ops/common_gates.py @@ -134,11 +134,9 @@ def controlled(self, This behavior only occurs when the last control qubit is a default-type control qubit. A default-type control qubit is one with shape of 2 (not a generic qudit) and where the control is satisfied by the qubit being - ON, as opposed to OFF. - - Note that this only transforms into a CXPowGate (or controlled version - of that gate) if the global shift of the XPowGate is 0, otherwise - it produces a normal ControlledGate. + ON, as opposed to OFF. Note also that this only transforms into a + CXPowGate (or controlled version of that gate) if the global shift on + the XPowGate is 0, otherwise it produces a normal ControlledGate. (Note that a CXPowGate is, by definition, a controlled-XPowGate.) """ @@ -457,11 +455,9 @@ def controlled(self, This behavior only occurs when the last control qubit is a default-type control qubit. A default-type control qubit is one with shape of 2 (not a generic qudit) and where the control is satisfied by the qubit being - ON, as opposed to OFF. - - Note that this only transforms into a CZPowGate (or controlled version - of that gate) if the global shift of the ZPowGate is 0, otherwise - it produces a normal ControlledGate. + ON, as opposed to OFF. Note also that this only transforms into a + CZPowGate (or controlled version of that gate) if the global shift of + the ZPowGate is 0, otherwise it produces a normal ControlledGate. (Note that a CZPowGate is, by definition, a controlled-ZPowGate.) """ @@ -813,11 +809,9 @@ def controlled(self, This behavior only occurs when the last control qubit is a default-type control qubit. A default-type control qubit is one with shape of 2 (not a generic qudit) and where the control is satisfied by the qubit being - ON, as opposed to OFF. - - Note that this only transforms into a CCZPowGate (or controlled version - of that gate) if the global shift of the CZPowGate is 0, otherwise - it produces a normal ControlledGate. + ON, as opposed to OFF. Note also that this only transforms into a + CCZPowGate (or controlled version of that gate) if the global shift of + the CZPowGate is 0, otherwise it produces a normal ControlledGate. (Note that a CCZPowGate is, by definition, a controlled-CZPowGate.) """ @@ -984,11 +978,9 @@ def controlled(self, This behavior only occurs when the last control qubit is a default-type control qubit. A default-type control qubit is one with shape of 2 (not a generic qudit) and where the control is satisfied by the qubit being - ON, as opposed to OFF. - - Note that this only transforms into a CCXPowGate (or controlled version - of that gate) if the global shift of the CXPowGate is 0, otherwise - it produces a normal ControlledGate. + ON, as opposed to OFF. Note also that this only transforms into a + CCXPowGate (or controlled version of that gate) if the global shift of + the CXPowGate is 0, otherwise it produces a normal ControlledGate. (Note that a CCXPowGate is, by definition, a controlled-CXPowGate.) """