-
Notifications
You must be signed in to change notification settings - Fork 981
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
Inconsistencies in using ControlledGate(s) and ControlledOperation(s) #4172
Labels
area/gates
kind/design-issue
A conversation around design
needs agreed design
We want to do this, but it needs an agreed upon design before implementation
triage/accepted
there is consensus amongst maintainers that this is a real bug or a reasonable feature to add
Comments
tanujkhattar
added
kind/design-issue
A conversation around design
triage/discuss
Needs decision / discussion, bring these up during Cirq Cynque
labels
Jun 8, 2021
Discussed on Cirq Cynque:
|
balopat
added
needs agreed design
We want to do this, but it needs an agreed upon design before implementation
triage/accepted
there is consensus amongst maintainers that this is a real bug or a reasonable feature to add
and removed
triage/discuss
Needs decision / discussion, bring these up during Cirq Cynque
labels
Jun 9, 2021
I have a related point that may or may not make sense to be part of #4167. I consider GlobalPhase to be part of the C*Z family and would expect op = cirq.GlobalPhaseOperation(-1).controlled_by(cirq.LineQubit(0))
assert np.allclose(cirq.unitary(op), cirq.unitary(cirq.Z))
print(op) # C(0, -1)
print(type(op)) # cirq.ControlledOperation |
CirqBot
pushed a commit
that referenced
this issue
Oct 1, 2021
…ions (#4167) This PR tries to resolve the inconsistencies mentioned in #4172. Specifically, - Equality b/w controlled `TOFFOLI`s with different qubit ordering on controls, i.e. `TOFFOLI(a,b,c).controlled_by(d) == TOFFOLI(d,b,c).controlled_by(a)` (and other 3Q controlled gates like CCZ, CSWAP). To achieve this, we override the `controlled` method on `CCX`, `CCZ` etc. to return a `ControlledGate` with `sub_gate = X` in case of `CCX` s.t. `TOFFOLI(a,b,c).controlled_by(d) == CCCX(a, b, d, c) == TOFFOLI(d,b,c).controlled_by(a)` instead of `CTOFFOLI` - `gate_operation.controlled_by` now forwards the request to `gate.controlled` to first create a controlled gate and then apply it on qubits to create a `ControlledOperation`. This solves the original use case of adding specialized controls, requested in #2142, i.e. `cirq.Z(q0).controlled_by(q1) == cirq.CZ(q1, q0)`. - Fixes #4515 Note, this is a breaking change because - `gate_operation.controlled_by()` can now return a `cirq.GateOperation` instead of `cirq.ControlledOperation` in cases where the underlying gates have specialized `gate.controlled()` implementations. - This also leads to a change in diagram of the controlled gates with specialized controlled implementations. For eg: Controlled S gate is now plotted as `CZPowGate` (`@ --- @ ** 0.5`) instead of `ControlledOperation` with Z ** 0.5 as subgate(`@ ---- S`) - `op.controlled_by` for 3Q gates like `CCX`, `CCZ`, `CSWAP` will now return `ControlledOperation` with `sub_operation = <underlying non-controlled gate>`. Eg: `CCCX` (i.e. `sub_gate = X`) instead of `CTOFFOLI` (i.e. `sub_gate = TOFFOLI`) etc. - Diagrams for `ControlledOperations` will now always have the exponent drawn on the target qubit (in case of multi qubit `sub_operation`, the exponent will always be on the first qubit if not the underlying gate does not explicitly specify a target index).
rht
pushed a commit
to rht/Cirq
that referenced
this issue
May 1, 2023
…ions (quantumlib#4167) This PR tries to resolve the inconsistencies mentioned in quantumlib#4172. Specifically, - Equality b/w controlled `TOFFOLI`s with different qubit ordering on controls, i.e. `TOFFOLI(a,b,c).controlled_by(d) == TOFFOLI(d,b,c).controlled_by(a)` (and other 3Q controlled gates like CCZ, CSWAP). To achieve this, we override the `controlled` method on `CCX`, `CCZ` etc. to return a `ControlledGate` with `sub_gate = X` in case of `CCX` s.t. `TOFFOLI(a,b,c).controlled_by(d) == CCCX(a, b, d, c) == TOFFOLI(d,b,c).controlled_by(a)` instead of `CTOFFOLI` - `gate_operation.controlled_by` now forwards the request to `gate.controlled` to first create a controlled gate and then apply it on qubits to create a `ControlledOperation`. This solves the original use case of adding specialized controls, requested in quantumlib#2142, i.e. `cirq.Z(q0).controlled_by(q1) == cirq.CZ(q1, q0)`. - Fixes quantumlib#4515 Note, this is a breaking change because - `gate_operation.controlled_by()` can now return a `cirq.GateOperation` instead of `cirq.ControlledOperation` in cases where the underlying gates have specialized `gate.controlled()` implementations. - This also leads to a change in diagram of the controlled gates with specialized controlled implementations. For eg: Controlled S gate is now plotted as `CZPowGate` (`@ --- @ ** 0.5`) instead of `ControlledOperation` with Z ** 0.5 as subgate(`@ ---- S`) - `op.controlled_by` for 3Q gates like `CCX`, `CCZ`, `CSWAP` will now return `ControlledOperation` with `sub_operation = <underlying non-controlled gate>`. Eg: `CCCX` (i.e. `sub_gate = X`) instead of `CTOFFOLI` (i.e. `sub_gate = TOFFOLI`) etc. - Diagrams for `ControlledOperations` will now always have the exponent drawn on the target qubit (in case of multi qubit `sub_operation`, the exponent will always be on the first qubit if not the underlying gate does not explicitly specify a target index).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
area/gates
kind/design-issue
A conversation around design
needs agreed design
We want to do this, but it needs an agreed upon design before implementation
triage/accepted
there is consensus amongst maintainers that this is a real bug or a reasonable feature to add
We currently have
ControlledGate
andControlledOperation
as generic types which are useful to represent controlled versions of an underlyingsub_type
. For many common gates, we also have explicit types defined for controlled versions of those gates (eg:X
,CX
,CCX
etc.).The general pattern to get a
controlled_gate
from agate
is to callgate.controlled()
and to get acontrolled_operation
from anoperation
, one should calloperation.controlled_by()
.There are a few inconsistencies in user experience while dealing with these types, which should be fixed. Some examples are as follows:
Equality of
ControlledOperations
with explicitly defined controlled types assubtype
Issue: Both
op1
andop2
are same operations (control on qubits1, 2, 3, 4
and target on0
), but the equality tests false because their subtypes & controls are different (TOFFOLI(3, 4, 0)
vsTOFFOLI(2, 1, 0)
).Proposed Solution: If
num_controls > 2
,cirq.X.controlled()
should return acirq.ControlledGate(sub_gate = 'X', num_controls = num_controls)
instead of first converting to aTOFFOLI
. Similar changes to should be done for other gates likeZ
,CZ
,CX
etc.gate.controlled().on()
andgate.on().controlled_by()
should return the same operations.Issue: Both
op1
andop2
are the same operations, but their types are different. We have custom overrides forgate.controlled
for many common gates to return specialized versions of the controlled gate, but these overrides are ignored when we callcontrolled_by
from the corresponding operation.Proposed Solution:
GateOperation
should override thecontrolled_by
function to first construct thecontrolled_gate
viagate.controlled()
and then apply this controlled_gate on qubits to get acontrolled_operation
.Controlled Gates / Ops which have specific types defined should always use/return them by default
It would be nice if can make it harder for instances like
cirq.ControlledGate(sub_gate = cirq.X, num_controls = 1)
to exist, and always havecirq.CNOT
in it's place. Maybe by constructing the controlled gates / ops via a factory that always forwards the requests togate.controlled / op.controlled_by
?Update: Part of #3242
The text was updated successfully, but these errors were encountered: