Skip to content
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
28 changes: 20 additions & 8 deletions cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,16 @@ 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.
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.)
"""
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,
Expand Down Expand Up @@ -452,13 +455,16 @@ 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.
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.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like the above two paragraphs can actually be combined more concisely into a single paragraph listing the preconditions for the specialization to occur.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Combined for this and all other gates.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was suggesting more along the lines of:

This method will specialize the control only if:
1. global shift is 0
2. the last of the controls is a default-type control qubit (followed by the clarifying what that means)

It would make the prerequisites clearer to the reader. But it's a minor documentation nit and not worth blocking the PR.

(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,
Expand Down Expand Up @@ -803,13 +809,16 @@ 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.
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.)
"""
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,
Expand Down Expand Up @@ -969,13 +978,16 @@ 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.
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.)
"""
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,
Expand Down
29 changes: 29 additions & 0 deletions cirq/ops/common_gates_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down