Skip to content

Resolve inconsistencies in using controlled gates & controlled operations #4167

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

Merged
merged 17 commits into from
Oct 1, 2021

Conversation

tanujkhattar
Copy link
Collaborator

@tanujkhattar tanujkhattar commented Jun 7, 2021

This PR tries to resolve the inconsistencies mentioned in #4172. Specifically,

  • Equality b/w controlled TOFFOLIs 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 On PartialGate and cirq.Z(a).controlled_by(b) returning a CZ #2142, i.e. cirq.Z(q0).controlled_by(q1) == cirq.CZ(q1, q0).
  • Fixes ControlledOperation diagram draws exponent on the wrong qubits  #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).

@tanujkhattar tanujkhattar requested review from cduck, vtomole and a team as code owners June 7, 2021 16:59
@tanujkhattar tanujkhattar requested a review from dstrain115 June 7, 2021 16:59
@google-cla google-cla bot added the cla: yes Makes googlebot stop complaining. label Jun 7, 2021
Copy link
Contributor

@balopat balopat left a comment

Choose a reason for hiding this comment

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

Two comments for discussion before we move forward:

  1. This is technically a breaking change as user code might depend on the type of the controlled_by method being a ControlledGate. So we should make it very explicit in our release notes and label this PR as a breaking change.
  2. Is there really no value at all in subsequent layers of ControlledGates? It feels like a very generic structure that maybe some decomposition code could leverage. But with jumping directly to "specialized" implementation we lose this structure. Maybe could have both? I.e. from a (multi-)controlled gate we could have a method reduce_type, simplify_type or specialize_type that could return the equivalent type in the hierarchy as needed based on the underlying gate if there is one...I.e. we would do the delegation to the subgate only on demand - this pattern would be similar to simplify Sympy expressions.

@tanujkhattar tanujkhattar changed the title controlled_operation.gate() should return sub_operation.gate.controlled() [DRAFTcontrolled_operation.gate() should return sub_operation.gate.controlled() Jun 8, 2021
@tanujkhattar tanujkhattar changed the title [DRAFTcontrolled_operation.gate() should return sub_operation.gate.controlled() [DRAFT] Resolve inconsistencies with controlled gates & controlled operations Jun 8, 2021
@tanujkhattar
Copy link
Collaborator Author

Thanks for the feedback. I found some more cases and have opened #4172 to discuss the various issues related to controlled gates & operations.
I'll mark this PR as draft for now till the discussion on the issue is resolved.

@tanujkhattar tanujkhattar changed the title [DRAFT] Resolve inconsistencies with controlled gates & controlled operations [Draft] Resolve inconsistencies with controlled gates & controlled operations Jun 8, 2021
@tanujkhattar tanujkhattar marked this pull request as draft June 8, 2021 01:40
@balopat balopat self-assigned this Jul 1, 2021
@balopat balopat removed the request for review from dstrain115 July 1, 2021 16:04
@tanujkhattar tanujkhattar force-pushed the controlled_op_gate_fix branch from 053138f to 11ece2c Compare July 9, 2021 13:44
@tanujkhattar tanujkhattar changed the title [Draft] Resolve inconsistencies with controlled gates & controlled operations Resolve inconsistencies in using controlled gates & controlled operations Jul 9, 2021
@tanujkhattar tanujkhattar marked this pull request as ready for review July 9, 2021 14:09
@tanujkhattar tanujkhattar requested a review from balopat July 9, 2021 14:09
@tanujkhattar
Copy link
Collaborator Author

@balopat This is ready for review. I'm open to suggestions for a better breaking change description in the PR.

@tanujkhattar tanujkhattar added the BREAKING CHANGE For pull requests that are important to mention in release notes. label Jul 9, 2021
Copy link
Contributor

@balopat balopat left a comment

Choose a reason for hiding this comment

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

I feel like that the consistency tests should follow the pattern in cirq.testing.assert_implements_consistent_protocols -- i.e. I'd create an assertion in cirq.testing that takes a gate, and as sequence of pows, and then do the two consistency tests on the gate and the gate powers. Then I'd use this assert method for all of our gates to achieve full coverage across all our gates.

@balopat
Copy link
Contributor

balopat commented Jul 9, 2021

Re: breaking change note - looks good, but I would specifically mention in the breaking changes the consequent change in QFT and quirk diagrams controlled operations. Some people depend on diagrams for their tests...

@tanujkhattar
Copy link
Collaborator Author

@balopat I've modified the PR description and added assert_controlled_and_controlled_by_identical as suggested. PTAL.

Also, do you want me to add 100% coverage across all Cirq gates for assert_controlled_and_controlled_by_identical in this PR itself? Or could it be a follow-up PR ?

@tanujkhattar tanujkhattar requested a review from balopat July 12, 2021 19:51
@tanujkhattar
Copy link
Collaborator Author

@balopat Ping, this is ready for re-review. PTAL.

@CirqBot CirqBot added size: XL lines changed >1000 size: L 250< lines changed <1000 and removed size: XL lines changed >1000 labels Aug 12, 2021
@tanujkhattar
Copy link
Collaborator Author

@MichaelBroughton Can you please take a look at this?

@tanujkhattar
Copy link
Collaborator Author

Also added a fix for #4515 in this PR to avoid breaking the diagrams twice. See #4529 (comment) for justification.

This PR is again ready for re-review

Copy link
Collaborator

@MichaelBroughton MichaelBroughton left a comment

Choose a reason for hiding this comment

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

I'm ready to merge on this. @maffoo or @smitsanghavi , any final thoughts ?

Copy link
Collaborator

@smitsanghavi smitsanghavi left a comment

Choose a reason for hiding this comment

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

LGTM

@MichaelBroughton MichaelBroughton added the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label Oct 1, 2021
@CirqBot CirqBot added the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label Oct 1, 2021
@CirqBot CirqBot merged commit f48efe0 into quantumlib:master Oct 1, 2021
@CirqBot CirqBot removed automerge Tells CirqBot to sync and merge this PR. (If it's running.) front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. labels Oct 1, 2021
@tanujkhattar tanujkhattar deleted the controlled_op_gate_fix branch October 1, 2021 18:56
CirqBot pushed a commit that referenced this pull request Oct 12, 2021
…ers to support other operation types. (#4459)

Proliferation of `isinstance(op, GateOperation)` checks results in many inconsistencies due to different available operation types like `ControlledOperations` and `TaggedOperations`. This PR fixes #4152 and is a first step towards fixing #3556 

Note that `TaggedOperations` which were earlier ignored by the optimizers would now be considered, and hence this is potentially a breaking change if people were implicitly relying on TaggedOperations not getting compiled by the optimizers. Since the optimizer doesn't document / test this behavior, I consider it to be a bug rather than a feature and an explicit `NoCompile` tag should be implemented as part of #4253 


This PR is blocked on submitting #4167 (tests will stop failing once the PR is submitted and this rebased). 

Update: This is now ready for review.
rht pushed a commit to rht/Cirq that referenced this pull request May 1, 2023
…lib#4462)

`CX` and `CCX` gates currently print the exponent on the bottom most qubit in the circuit diagram. This PR modifies this behavior to always draw the exponent on the target qubit, which is also the expected behavior for other `ControlledOperations`. This came up in discussions on quantumlib#4167 (comment)

Note that behavior of `CZ` and `CCZ` is left unchanged, i.e. draws exponent on the bottom most qubit, since these gates are symmetrical across all applied qubits. 

BREAKING CHANGE: Tests depending upon diagrams of `CX` and `CCX` can now fail.
rht pushed a commit to rht/Cirq that referenced this pull request 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).
rht pushed a commit to rht/Cirq that referenced this pull request May 1, 2023
…ers to support other operation types. (quantumlib#4459)

Proliferation of `isinstance(op, GateOperation)` checks results in many inconsistencies due to different available operation types like `ControlledOperations` and `TaggedOperations`. This PR fixes quantumlib#4152 and is a first step towards fixing quantumlib#3556 

Note that `TaggedOperations` which were earlier ignored by the optimizers would now be considered, and hence this is potentially a breaking change if people were implicitly relying on TaggedOperations not getting compiled by the optimizers. Since the optimizer doesn't document / test this behavior, I consider it to be a bug rather than a feature and an explicit `NoCompile` tag should be implemented as part of quantumlib#4253 


This PR is blocked on submitting quantumlib#4167 (tests will stop failing once the PR is submitted and this rebased). 

Update: This is now ready for review.
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this pull request Oct 31, 2024
…lib#4462)

`CX` and `CCX` gates currently print the exponent on the bottom most qubit in the circuit diagram. This PR modifies this behavior to always draw the exponent on the target qubit, which is also the expected behavior for other `ControlledOperations`. This came up in discussions on quantumlib#4167 (comment)

Note that behavior of `CZ` and `CCZ` is left unchanged, i.e. draws exponent on the bottom most qubit, since these gates are symmetrical across all applied qubits. 

BREAKING CHANGE: Tests depending upon diagrams of `CX` and `CCX` can now fail.
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this pull request Oct 31, 2024
…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
BREAKING CHANGE For pull requests that are important to mention in release notes. cla: yes Makes googlebot stop complaining. size: L 250< lines changed <1000
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ControlledOperation diagram draws exponent on the wrong qubits Inconsistencies in using ControlledGate(s) and ControlledOperation(s)
7 participants