On PartialGate and cirq.Z(a).controlled_by(b) returning a CZ
See original GitHub issueI’ve been experimenting with whether it’s feasible to have special cases for controlled_by
. By having specific classes (GateOperation
, ControlledGate
, ZPowGate
) override their controlled_by
method, and preferentially calling this method instead of ControlledOperation
’s constructor in a few places, we can do things like have Z.controlled_by(x) turn into a CZ.
The main decide is that, in order for it to really work, it is necessary to introduce a PartialGate
class that has some of the qubits specified. Otherwise it is not possible for cirq.Z.controlled_by(q)
to return a CZ that has the control filled in but not the target. This situation arises in the code path within GateOperation
.
An alternative could be to have Gate.controlled_by
take an integer for the number of controls, and return a gate without them specified.
I’m a bit worried that this partial gate concept will start appearing in more places as the code base grows. It’s particularly tricky at the moment because it’s ambiguous whether gate.num_qubits()
is the number of qubits to pass in order to get an operation (relevant to on(...)
) or the number of qubits that will be present in the final operation (relevant to _unitary_
).
Issue Analytics
- State:
- Created 4 years ago
- Comments:10 (3 by maintainers)
Currently I’m leaning towards have
Gate.controlled(control_count: int=1)
instead ofPartialGate
. I don’t think that partial gate muddies the concept of what an operation is, but it does muddy the concept of what a gate is (e.g. thenum_qubits
method becoming ambiguous).FYI,
cirq.Z(a).controlled_by(b)
does not returnCZ(b, a)
after this change. It still returns aControlledOperation
. This is because only specialization on gates was added butGateOperation
scontrolled_by
was not overridden to first call the underlying gate’sgate.controlled
and then construct the operation. See #4172 for more details.