-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Describe your design idea/issue
All other cases of .controlled()
in Cirq, as well as the ControlledGate
constructor, do their best to flatten the layers of control where possible. The one exception is CX/CZ.controlled(...)
, where ...
is a non-default set of control values.
for cv in [1, 0]:
for g in [cirq.X, cirq.CX, cirq.CCX, cirq.Z, cirq.CZ, cirq.CCZ]:
print()
for i in range(5):
print(repr(g.controlled(i, [cv] * i)))
Output:
cirq.X
cirq.CNOT
cirq.TOFFOLI
cirq.ControlledGate(sub_gate=cirq.X, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=4)
cirq.CNOT
cirq.TOFFOLI
cirq.ControlledGate(sub_gate=cirq.X, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=4)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=5)
cirq.TOFFOLI
cirq.ControlledGate(sub_gate=cirq.X, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=4)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=5)
cirq.ControlledGate(sub_gate=cirq.X, num_controls=6)
cirq.Z
cirq.CZ
cirq.CCZ
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=4)
cirq.CZ
cirq.CCZ
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=4)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=5)
cirq.CCZ
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=3)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=4)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=5)
cirq.ControlledGate(sub_gate=cirq.Z, num_controls=6)
cirq.X
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,),)),control_qid_shape=(2,))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,))),control_qid_shape=(2, 2))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,), (0,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,))),control_qid_shape=(2, 2, 2, 2))
cirq.CNOT
cirq.ControlledGate(sub_gate=cirq.CNOT, control_values=cirq.ProductOfSums(((0,),)),control_qid_shape=(2,))
cirq.ControlledGate(sub_gate=cirq.CNOT, control_values=cirq.ProductOfSums(((0,), (0,))),control_qid_shape=(2, 2))
cirq.ControlledGate(sub_gate=cirq.CNOT, control_values=cirq.ProductOfSums(((0,), (0,), (0,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.CNOT, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,))),control_qid_shape=(2, 2, 2, 2))
cirq.TOFFOLI
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (1,), (1,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.X, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2, 2, 2))
cirq.Z
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,),)),control_qid_shape=(2,))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,))),control_qid_shape=(2, 2))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,), (0,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,))),control_qid_shape=(2, 2, 2, 2))
cirq.CZ
cirq.ControlledGate(sub_gate=cirq.CZ, control_values=cirq.ProductOfSums(((0,),)),control_qid_shape=(2,))
cirq.ControlledGate(sub_gate=cirq.CZ, control_values=cirq.ProductOfSums(((0,), (0,))),control_qid_shape=(2, 2))
cirq.ControlledGate(sub_gate=cirq.CZ, control_values=cirq.ProductOfSums(((0,), (0,), (0,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.CZ, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,))),control_qid_shape=(2, 2, 2, 2))
cirq.CCZ
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (1,), (1,))),control_qid_shape=(2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2, 2))
cirq.ControlledGate(sub_gate=cirq.Z, control_values=cirq.ProductOfSums(((0,), (0,), (0,), (0,), (1,), (1,))),control_qid_shape=(2, 2, 2, 2, 2, 2))
The CX
and CZ
in the nontrivial control value cases end up with ControlledGates that wrap CX/CZ
, instead of having the ControlGate absorb the outer control layer like everywhere else. Beyond the inconsistency, multiple layers of control are futzy to work with, awkward to understand, and harder to decompose. (Hence the isinstance(subgate, CZ)
in ControlledGate._decompose_
).
Making this consistent seems worthwhile, and given the behavior of most cases, it seems like this was the original goal, but it just got lost in the special nontrivial control values cases.
I'm pretty sure this is just modifying the CX/CZPowGate.controlled
methods and adding unit tests, so marking as good first issue.