-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
base: main
Are you sure you want to change the base?
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.
With various conversions of DAGCircuit to QuantumCircuitData to CircuitData in Rust, it's best to make sure that the global phases appearing in circuits/control-flow subcircuits are tracked correctly
… ops when calls from annotated plugin
…fiers; adding test
This leads to significantly improved synthesis results when adding multiple controls to a gate. Previously, first controlling a CX with 2 controls, and then controlling the results with 3 controls, first resulted in expanding the CCCX gates into single- and two-qubits gates, adding controls to each of these gates, and then expanding each of these controlled gates. Now, a single MCX gate will be produced, which will then be expanded using the best MCX synthesis algorithm available.
…or control modifiers
This is a simplified version from the unused code from the OptimizeAnnotated transpiler pass. It's especially useful for controlled QFT-adder and similar circuits.
This allows to let the default QFT-based adder plugins to create the inverse QFTGate as an AnnotatedOperation, allowing to exploit optimizations in the HighLevelSynthesis transpiler pass
One or more of the following people are relevant to this code:
|
…ed gates from add_control, but with the twist that some other high-level gate names are also supported; fixing failing tests that are synthesized differently (and actually better) using the new flow
…lier synthesis algorithm, and not the synthesis of the underlying QFT gate.
Pull Request Test Coverage Report for Build 13516621530Details
💛 - Coveralls |
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.
That's a great PR! see some comments and suggestions below.
@@ -109,10 +109,10 @@ def control( | |||
|
|||
global_phase = 0 | |||
|
|||
basis = ["p", "u", "x", "z", "y", "h", "sx", "sxdg", "rx", "ry", "rz", "cx"] | |||
basis = ["p", "u", "x", "z", "y", "h", "sx", "sxdg", "rx", "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.
we should check (in a follow-up PR) what happens with other controlled gates, such as:
cy, ch, cp, crx, cry, crz, cs, csdg, cswap, csx, csxdg, cu,
as well as ccx, ccz, c3x, c4x, c3sx.
Will adding them here improve the total CX cost?
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.
btw, I really don't like the fact that we're copying this array in different part of the code.
I would suggest to set it somewhere and use it, see e.g. the CollectClifford
transpiler pass:
clifford_gate_names = ( |
@@ -187,7 +187,7 @@ def apply_basic_controlled_gate(circuit, gate, controls, target): | |||
This implements multi-control operations for the following basis gates: | |||
["p", "u", "x", "z", "y", "h", "sx", "sxdg", "rx", "ry", "rz", "cx"] | |||
["p", "u", "x", "z", "y", "h", "sx", "sxdg", "rx", "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.
see my comment about this array above.
@@ -230,6 +230,14 @@ def apply_basic_controlled_gate(circuit, gate, controls, target): | |||
controls[:] + [target[0]], # CX has two targets | |||
target[1], | |||
) | |||
elif gate.name == "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.
btw, what is the improvement in cx-cost of adding cz
here?
if not isinstance(high_level_object, AnnotatedOperation): | ||
return None | ||
|
||
# Combine the modifiers. If the were no modifiers, or the modifiers magically canceled out, |
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.
the --> there
# (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 = { |
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.
see my comment on the array above
""" | ||
res = False | ||
|
||
if inst1.qubits != inst2.qubits or inst1.clbits != inst2.clbits or inst1.params != inst2.params: |
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.
in standard gates, usually the params of the inverse would be different than the params of the original gate,
for example: the inverse of rz(t) is rz(-t).
it does make sense however to check that both params have the same number of params.
""" | ||
Decomposes a circuit ``A`` into 3 sub-circuits ``P``, ``Q``, ``R`` such that | ||
``A = P -- Q -- R`` and ``R = P^{-1}``. | ||
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.
can you do it more efficiently if you generate the circuit "P - R" and check if some transpiler passes return it to identity?
e.g. InverseCancellation, CommutativeInverseCancellation, CommutativeCancellation, RemoveIdentityEquivalent
|
||
class TestHighLevelSynthesisQuality(QiskitTestCase): | ||
"""Test the "quality" of circuits produced by HighLevelSynthesis.""" | ||
|
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 there tests that use several modifiers? the QFT-adder should use both conjuage and control, right?
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.
perhaps this example is also relevant for the conjugate modifier (since ccx gate is self-conjugate):
#6740
qc = QuantumCircuit(gate.num_qubits) | ||
qc.append(gate, qc.qubits) | ||
qct = HighLevelSynthesis(basis_gates=["cx", "u"], qubits_initially_zero=False)(qc) | ||
self.assertLessEqual(qct.count_ops()["cx"], 450) |
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.
is this bound optimal? (assuming that the QFT requires 198). what is the formula for the CX count?
is the bound of 198 for QFT optimal? is there a formula for the CX count?
Summary
This PR significantly improves the high-level-synthesis plugin for synthesizing
AnnotatedOperations
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.Details and comments
Here are the experiments for the following 9 simple quantum circuits:
We are going to transpile these circuits with
HighLevelSynthesis(basis_gates=["cx", "u"])
.MAIN:
THIS PR:
Takeaways: (1) this PR improves the synthesis for almost all of the examples, with especial gains for hierarchical circuits with controlled operations represented as annotated operations; (2) using annotated operations for representing controlled gates is the right way to go forward, as this easily enables reductions and optimizations not available otherwise.