-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Improve annotated plugin #13916
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
Improve annotated plugin #13916
Conversation
The interface is now quite ugly, and we also have an extra isinstance check for each gate, we will see if it can be removed.
This argument is not needed as the qubit tracker already restricts allowed ancilla qubits.
…st for deciding which gates have efficient synthesis algorithms for their controlled versions
|
Thanks @ShellyGarion for the review. I have addressed your review comments, please take another look! Update: I have also improved/updated this PR's summary and release notes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still need to look more carefully into the code and tests.
How do we decide which gates to include in EFFICIENTLY_CONTROLLED_GATES and in the HLS plugin?
| "ry", | ||
| "rz", | ||
| "cx", | ||
| "cz", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that some gates should be added here:
- s and sdg are missing (since we have cs and csdg).
- swap (since we have cswap)
- u1 and u3 (since we have cu1 and cu3)
- should we also add here ccx, c3x ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good question, also related to your question on how to decide which gates to include in this list.
Let's try to think through this together, taking the SGate as a perfect example. What happens when we call SGate().control(num_ctrl_qubits)? We can check that SGate implements its own control method, which returns CSGate when num_ctrl_qubits==1 and falls back on the general Gate.control mechanism otherwise. The latter calls this code in the _add_control module. Since SGate is currently not in the EFFICIENTLY_CONTROLLED_GATES, we are going to unroll it into this set using UnrollCustomDefinitions and BasisTranslator passes, which will produce (a circuit containing) a single PhaseGate. Now, PhaseGate is in EFFICIENTLY_CONTROLLED_GATES and the method apply_basic_controlled_gate will be used, producing an MCPhase gate. I would claim that this is the best we can do from the efficiency perspective (modulo to how then an MCPhase gets synthesized), so technically we do not need to add an SGate to the list above. On the other hand, adding it to the list would avoid the need to run the unroller pass, and since SGate is a very common gate it might make sense to add it to the list from the perspective of efficiency.
Summarizing, we probably want to consider the gates above + other standard gates and see if we should add them to the list. We should also decide which part should be handled by a gate's native control mechanism vs. apply_basic_controlled_gate, hopefully avoiding any kind of duplication. I suggest to do this as a follow up.
| @@ -24,21 +24,47 @@ | |||
| from ._utils import _ctrl_state_to_int | |||
|
|
|||
|
|
|||
| # The list of gates whose controlled versions have efficient synthesis algorithms. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean controlled or multi-controlled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By "controlled" I mean "controlled with an arbitrary number of qubits". And this is what we generally mean when we say "controlled" in Qiskit, as reflected in the names Gate.control, _add_control, etc.
| # (including annotated operations) as the HighLevelSynthesis transpiler pass will | ||
| # recursively re-synthesize this circuit, However, we should always guarantee that some | ||
| # progress is made. | ||
| basis = set(EFFICIENTLY_CONTROLLED_GATES + ["annotated", "mcx", "qft"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these the only relevant gates? how about mcphase? or mcrz/mcry/mcrx?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also a great question. For MCPhaseGate, we don't have a plugin mechanism (correct?), so the definition circuit will be used. Can we do something better using ancillas? Is an MCPhaseGate used when constructing more complex circuits? If yes, then it could make sense to first unroll a more complex circuit to a circuit with MCPhaseGate, then apply the best known algorithm for MCPhaseGate. There is also a question on whether we need a native MCPhaseGate at all, as opposed to a controlled phase gate. Bottom-line: I agree that we should think about the above, but I would not like to add more gates here without concrete use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about adders? maybe in the future? say someone wants to add a controlled adder (w/o specifying the method)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! there is a minor misprint, but this PR is ready to go.
| # (including annotated operations) as the HighLevelSynthesis transpiler pass will | ||
| # recursively re-synthesize this circuit, However, we should always guarantee that some | ||
| # progress is made. | ||
| basis = set(EFFICIENTLY_CONTROLLED_GATES + ["annotated", "mcx", "qft"]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about adders? maybe in the future? say someone wants to add a controlled adder (w/o specifying the method)
|
|
||
| # all gates with the plugins we check, including an expected operation | ||
| plugins = [("cumulative_h18", "ch"), ("qft_r17", "mcphase")] | ||
| # For each pliugin, we check the presence of an expected operation after |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pliugin --> plugin
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for spotting this :) fixed in 29cd6d7
Hmm, that's an interesting point: while we try to make sure that the default plugins use the best synthesis algorithm for each high-level-gate in the circuit, these "locally best" choices might not be the overall best, taking the rest of the circuit and/or the following transpilation into account. I don't see an immediate solution to this, and I am afraid that there is only so much we can do automatically... |
Summary
This PR significantly improves the high-level-synthesis plugin for synthesizing
AnnotatedOperationobjects and in particular the synthesis of hierarchical circuits involving controlled subcircuits. Addresses #13566.Should be rebased on top of #13813.Does not need #13870, but serves as a basis to that PR explaining why we want to change the default handling of controlled gates to annotated gates.In addition, the PR improves synthesis of multi-controlled CZ-gates and synthesis of controlled QFT-adders.
Details and comments
Multi-controlled X-gates
Here are experiments for the following 4 simple quantum circuits. All of these circuits are equivalent to a 6-controlled X-gate, however they are constructed in somewhat different ways:
circuit1is a 6-controlled X-gate;circuit2is a 5-controlled CX-gate;circuit3is a 2-controlled quantum circuit that contains a 3-controlled CX-gate;circuit4is the same ascircuit3, however the controls are added as annotations rather than being eagerly synthesized.We are going to transpile these circuits with
HighLevelSynthesis(basis_gates=["cx", "u"]).MAIN:
THIS PR:
As we can see, both
circuit1andcircuit2are efficiently synthesized before and after this PR (note that the synthesis algorithm uses available ancillary qubits). However, the hierarchicalcircuit3is synthesized very poorly: due to eagerly synthesizing control logic, we first construct the circuit for a 3-controlled CX-gate, and then control every gate in this circuit using 2 additional controls. To improve the above, we need to do two things: create controlled gates as annotated gates (usingannotated=True) and improving theHighLevelSynthesispass to handle annotated operations, which is done in this PR by improving theAnnotatedSynthesisDefaultplugin. With both of these changes,circuit4is synthesized just as efficiently ascircuit1andcircuit2.Multi-controlled Z-gates
We repeat experiment with multi-controlled Z-gates instead of multi-controlled X-gates. Let circuits 5, 6, 7, 8 be the versions of circuits 1, 2, 3, 4 with Z/CZ gates instead of X/CX. One important difference is that we don't have native
MCZgates in Qiskit as compared to nativeMCX-gates, and in particular we don't have dedicated plugins forMCZ-gates. In theory, a multi-controlled Z-gate is equivalent to a multi-controlled X-gate with just two additional H-gates, and so we should get the same quality of results as above.MAIN:
THIS PR:
However, in practice
circuit6is worse thancircuit2: this is because aCZ-gate is translated to aCX-gatewith 2 Hadamards, and adding 5-controls creates two 5-controlled Hadamard gates instead of their non-controlled versions. This PR improves this behavior by providing an explicit decomposition for multiply-controlledCZ-gates in_add_control.py, similarly to how other controlled gates are currently handled. As before, creating a hierarchical circuit usingannotated=Trueand using the improvedAnnotatedSynthesisDefaultplugin allows to synthesizecircuit8using30CX-gates as compared to1586.Controlled QFT-adders
A long discussed optimization (actually available as a part of unused by default
OptimizeAnnotatedtranspiler pass) is to simplifycontrol-[U -- V -- U^{-1}]toU -- [control-V] -- U^{-1}. This immediately applies to controlled QFT-adders, where the logic is precisely of this form:control-[QFT -- V -- QFT^{-1}]. WithAnnotatedSynthesisDefaultadapting two simple optimizations fromOptimizeAnnotatedpass and after allowing in the construction of the QFT-based adder to create the inverseQFT^{-1}as annotated (hence a new argument toadder_qft_d00), a controlled QFT-adder can be synthesized much more efficiently than before:MAIN:
THIS PR: