Skip to content
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

Avoid circuit<->dag conversion overhead in basis translator #9680

Closed
mtreinish opened this issue Feb 28, 2023 · 1 comment · Fixed by #10707
Closed

Avoid circuit<->dag conversion overhead in basis translator #9680

mtreinish opened this issue Feb 28, 2023 · 1 comment · Fixed by #10707
Assignees
Labels

Comments

@mtreinish
Copy link
Member

What should we add?

Right now in the basis translator we spend a large portion of time (roughly 1/3rd of the typical runtime) converting back and forth between QuantumCircuit and DAGCircuit. This is mostly of this is to support calling assign_parameters() which only exists on a circuit, but the transpiler only works with DAGCircuit. This ends up being fairly high overhead because we deepcopy instructions multiple times as we go back and forth

We should be able to avoid all this overhead by doing parameter assignment directly in the DAGCircuit which would probably require porting the equivalent of ParameterTable and the matching assignment functions to DAGCircuit (or potentially bypassing the traditional parameter assignment mechanisms as we don't need the full flexibility for this).

@jakelishman
Copy link
Member

Some thoughts, copied from #10275:

I'm not certain that giving DAGCircuit the ability to assign parameters is going to be the cleanest way forwards to improving this. The way QuantumCircuit manages its ParameterTable is only realistically possible because QuantumCircuit is (nearly) an additive-only interface with a single call point that's allowed to add instructions to a circuit (QuantumCircuit._append, give or take). DAGCircuit has many many methods to add potentially parametrised instructions, but further, it's got a lot of methods that can replace operations with arbitrary other blocks that would also need updating. The root of the issue is that ParameterTable+QuantumCircuit has a strong requirement on data coherence in a way that it'll be very tricky and bug-prone to do in DAGCircuit.

@mtreinish mtreinish self-assigned this Aug 24, 2023
mtreinish added a commit to mtreinish/qiskit-core that referenced this issue Aug 24, 2023
This commit updates the internal logic for doing basis translation with
equivalence rules that involve parameter expressions. Previously the
basis translator would first construct an unbound DAGCircuit from the
equivalence library search, the it would convert that DAGCircuit into a
QuantumCircuit, bind the parameters, and finally convert the
QuantumCircuit back to a DAGCircuit for inline replacement. This was
needlessly inefficient, especially considering the original unbound
DAGCircuit was built from a QuamtumCircuit object. This meant in the
case of each gate being translated with a parameterized equivalence
rule the BasisTranslator was doing:

QuantumCircuit -> DAGCircuit -> QuantumCircuit -> DAGCircuit

just to be able to replace a node. This ends up being the primary
performance bottleneck for the pass because while each conversion of a
typically very small circuit is fairly quick in aggregate it takes a
large amount of time as the number of gates in the circuit grows.

This commit attempts to address this performance overhead by removing
the last QuantumCircuit -> DAGCircuit conversion by directly binding the
parameters on a copy of the DAGCircuit. Since the equivalence library
use case is very constrained in how parameter expressions are
constructed we're able to inline the binding on a copy of the
DAGCircuit. This still has a fair amount of overhead as we still need to
iterate over the DAGCircuit and copy it, but we're able to avoid one set
of copies and circuit iteration by doing the binding this way.

Fixes Qiskit#9680
github-merge-queue bot pushed a commit that referenced this issue Oct 18, 2023
* Inline parameter binding as part of BasisTranslator

This commit updates the internal logic for doing basis translation with
equivalence rules that involve parameter expressions. Previously the
basis translator would first construct an unbound DAGCircuit from the
equivalence library search, the it would convert that DAGCircuit into a
QuantumCircuit, bind the parameters, and finally convert the
QuantumCircuit back to a DAGCircuit for inline replacement. This was
needlessly inefficient, especially considering the original unbound
DAGCircuit was built from a QuamtumCircuit object. This meant in the
case of each gate being translated with a parameterized equivalence
rule the BasisTranslator was doing:

QuantumCircuit -> DAGCircuit -> QuantumCircuit -> DAGCircuit

just to be able to replace a node. This ends up being the primary
performance bottleneck for the pass because while each conversion of a
typically very small circuit is fairly quick in aggregate it takes a
large amount of time as the number of gates in the circuit grows.

This commit attempts to address this performance overhead by removing
the last QuantumCircuit -> DAGCircuit conversion by directly binding the
parameters on a copy of the DAGCircuit. Since the equivalence library
use case is very constrained in how parameter expressions are
constructed we're able to inline the binding on a copy of the
DAGCircuit. This still has a fair amount of overhead as we still need to
iterate over the DAGCircuit and copy it, but we're able to avoid one set
of copies and circuit iteration by doing the binding this way.

Fixes #9680

* Handle parameter substition individually

In the case we're substituting a parameter expression in the replacement
circuit with another parameter expression we need to handle each sub
parameter in the expression individually to either bind it to a value or
substitute it with the replacement expression. Previously we tried to
either call ParameterExpression.bind or ParameterExpression.subs, but
subs can only be used if all the parameters in an expression are
unbound. This commit replaces the use of subs with a loop over the
parameters and calls ParameterExpression.assign, which handles the type
based dispatch for a single parameter. The case when the full
substitution is bound is handled using bind as before, since that can be
done in a single call.

* Update qiskit/transpiler/passes/basis/basis_translator.py

Co-authored-by: Julien Gacon <[email protected]>

* Use zip instead of zip_longest

* Adjust global phase type casting

---------

Co-authored-by: Julien Gacon <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants