-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
transpile ansatz and pauli-lists separately in VQE #6454
Conversation
Couldn't we just solve this issue by transpiling the circuit before calling |
f4aec15 does so. But it is not correct if |
What if we pre-transpile but then still transpile again in the circuit sampler? Since we already did most the optimizations that should be pretty fast, no? I'm not sure the steps you outlined above are the right approach. This scenario of ansatz + Pauli expectations is very common and we should improve the transpilation in general, not only within the VQE. What about making |
I guess going forwards this can be related to #6451 |
In Macbook Pro, original UCCSD circuits are traspiled in 620 seconds. Pre-transpiled circuits are transpiled in 129 seconds. Pre-transpile takes 4 second. |
Thanks for checking the runtimes @hhorii! I agree this is quite a strong speedup and we should definitely allow to only transpile once. To keep the old behavior available, should we add a flag that allows to keep the old behavior (e.g. if you run on real HW you might want to transpile twice)? |
0338cbc
to
bab18b5
Compare
|
||
# pylint: disable=unused-argument | ||
@deprecate_arguments({"circuit_sfns": "operator"}) | ||
def sample_circuits( |
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 am wondering about the extent of the changes here. Should we be keeping sample_circuits
for people to use as it was and add a new method that takes operator to do what we want now. If I had done code that used sample_circuits - its a public interface here after all - I think the changes here means it no longer works for my existing code - deprecated means it should keep on working as it had done until we remove the deprecated function.
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.
It is true. However, I personally feel uncomfortable that this method, which has no unit tests, is public. Considering the future maintenance, I think the method should be deprecated now. I can't think of a use case for this method by itself.
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.
@woodsp-ibm Thanks a lot. I finally decided not to change this 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.
Hi @ikkoham! I have a few questions about this PR 🙂
- I'm sure I fully understand the approach, would you mind explaining it briefly? How do you know the common circuit is the right-hand side state in the composed op? What if you have multiple composed ops?
- Couldn't we just transpile the circuit in VQE and not transpile it again in the circuit sampler? Then we wouldn't have to change a lot (or maybe nothing at all) in the Circuit Sampler.
@@ -318,7 +324,7 @@ def construct_expectation( | |||
|
|||
observable_meas = self.expectation.convert(StateFn(operator, is_measurement=True)) | |||
ansatz_circuit_op = CircuitStateFn(wave_function) | |||
return observable_meas.compose(ansatz_circuit_op).reduce() |
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.
Why is the call to reduce
removed? 🙂
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 change removes copies ansatz's quantum circuit. In order to take advantage of lazy evaluation, we should reduce at a later stage. Since CircuitSampler do the reduce
, we do not need to do the reduce at this stage, and it will degrade the performance.
del self._p2v[key] | ||
del self._v2p[self._p2v[key]] | ||
del self._p2v[key] | ||
elif isinstance(key, Qubit): | ||
del self._v2p[key] | ||
del self._p2v[self._v2p[key]] | ||
del self._v2p[key] |
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 file should probably not be touched
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.
Why not? This is clearly a bug, @hhorii found. This is necessary to execute our code. Should we separate the PR?
@Cryoris Thanks. This approach is to compile ansatz circuit only once, instead of N times when N Pauli are given.
In terms of OpFlow's design, ansatz is contained in StateFn on the right side, and information about observables is contained in MeasurementFn (=~StateFn) on the left side. Also, it is not possible to create or evaluate a ComposedOp with more than three StateFn. We don't need optimize the performance except for the case which this PR supports for now.
It is my understanding that the CircuitSampler should be responsible for transpiling quantum circuits, not the VQE. |
…kit-terra into transpile_only_ansatz
@Qiskit/terra-core Is this PR mergeable? I've made both, and personally it's better to have the transpile closed in CircuitSampler. But this is a performance issue that needs to be included in the next release (0.18.0). So if committers really wants to transpile on the VQE side, I will complete #6602 asap. |
@Cryoris you had comments against this approach to start with - can you respond to the above please. |
diff_circuits.append(diff_circuit) | ||
|
||
if transpiled_common_circuit._layout is not None: | ||
layout = transpiled_common_circuit._layout.copy() |
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 suppose we need to set the "final" layout here, however, _layout
stores the initial layout of the transpiled common circuit.
Unfortunately, we have no simple way to get the final layout of a transpiled circuit so far.
The following could work (I know it's not smart. Does anyone think of any better idea?):
- Adding dummy measures to the common circuit before transpiling
- Constructing the final layout from virtuals-clbits and physical-clbits maps stored in original and transpiled measures respectively
- Removing the dummy measures from the common circuit
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.
Thank you. You are right. We assume _layout
is the final layout.
I have fixed the PR from your advice. Is this correct? 7418ac2
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 have shown how one can get the required final layout (permutation) here: #6827
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.
Thank you so much. It's really useful.
I think this solution is nice because it is common and not specific to VQE, but it points to a deficiency in the software architecture. This code has to reverse-engineer a circuit to figure out what the ansatz is, transpile that, and then glue it back. |
@ajavadia Thank you so much. However, I agree we need more refactoring here. CircuitSampler (especially cache structure) is too complicated. I think many caches should be in the operator itself (e.g. Then there's the unnecessary calculation of taking sqrt and squaring it in the current method. I think this unnecessary calculation should be removed. Also, we need an API that can take variance or standard error. With the existing CircuitSampler, I cannot create a method to use the Finally in my opinion, I thought it would be a better idea to make a major revision when the expectation value experiment class come in the future. |
@hhorii I think this can be closed right, given primitives will deal with aspects like this going forwards and VQE will be refactored to run using primitives. |
Yes, this is the logic already applied on the qiskit-ibm-runtime side (precisely, server side), so we can close it. Thank you for pointing out. |
Summary
A parameterized circuit of ansatz is transpiled once in VQE
Details and comments
A parameterized circuit of ansatz is copied to multiple circuits in OpFlow and they are transpiled though they share the same ansatz.
This PR transpiles ansatz and puli-lists separately and generates multiple circuits by combining them.
This issue will resolve a part of #6432.