QuantumCircuit has no attribute 'save_statevector'

15
open
teaguetomesh
teaguetomesh
Posted 1 year ago

QuantumCircuit has no attribute 'save_statevector' #6346

Information

  • Qiskit Terra version: 0.17.1
  • Python version: 3.7.9
  • Operating system: macOS Big Sur 11.3

What is the current behavior?

Unable to apply the save_statevector instruction to a newly created QuantumCircuit. Doing so throws an error: AttributeError: 'QuantumCircuit' object has no attribute 'save_statevector'

However, if I first simulate a circuit without the save_statevector instruction, then everything works as intended and I can go back and apply the save_statevector instruction.

Steps to reproduce the problem

from qiskit import QuantumCircuit
circ = qk.QuantumCircuit(2)
circ.h(circ.qubits)
circ.save_statevector()

What is the expected behavior?

I should be able to apply the save_statevector instruction to my quantum circuit.

yaelbh
yaelbh
Created 1 year ago

Same for pershot: yes, everything is related to the simulator only. Still there is no reason not to be able to build a circuit with these instructions, especially if Aer was imported. A call to get_backend is not a declaration "Attention! We are using a simulator, allow simulator instructions from now on!".

WiFisunset
WiFisunset
Created 1 year ago

@yaelbh I see what you mean, but Python as a language is line-by-line execution. So if the line save_unitary(pershot=True) were called, then Python is expecting a simulator when executing that line.

So when 'get_backend' is called before the save state, python knows what to execute pershot due to 'get_backend' being executed previously. That may be the issue (the way python executes the code).

Same for pershot: yes, everything is related to the simulator only. Still there is no reason not to be able to build a circuit with these instructions, especially if Aer was imported. A call to get_backend is not a declaration "Attention! We are using a simulator, allow simulator instructions from now on!".

Screenshot_20210505-035142

mtreinish
mtreinish
Created 1 year ago

The solution is to change Terra code such that qc.save_unitary() is possible anytime, regardless of whether the simulator was called. An error will be invoked if one tries to run or transpile the circuit with a backend that doesn't support the save_unitary instruction.

I disagree with this, the semantics of the save state instructions are very specific to aer, and don't apply to simulators more broadly (as they all work differently). Instructions do not need to live in terra, unless we want them to be a common interface for everything.

As for the import error I think the point of confusion is that:

from qiskit import Aer

does not actually import qiskit-aer the package which means the monkey patching that aer does on import is not run. qiskit.Aer is a lazy loading alias for qiskit.providers.aer.Aer. Just importing qiskit.Aerdoesn't actually import the aer package just that wrapper. This is why running qiskit.Aer.get_backend() works because the wrapper will import qiskit.providers.aer.Aer under the covers to alias the call to get_backend().

As @nonhermitian mentioned it's an unfortunate consequence of the use of namespace packaging combined with how we build the combined documentation for the metapackage that the monkey patching that aer does to add the circuit methods happens before the docs are built, so they show up as if they're actually methods of the QuantumCircuit class.

I believe the fix here is simply to modify the docstrings for the save_* instruction functions to highlight qiskit.providers.aer must be imported for the instructions to work. Ideally in the summary line so it shows up in the methods table too.

yaelbh
yaelbh
Created 1 year ago

@mtreinish I agree that the fix for now is to document the need to import qiskit.providers.aer. Still in the long term we should further fix get_backend. This is a query, and as such, according to the command-query separation principle, should not do anything but returning the backend. It is allowed, internally, to perform lazy evaluations, as long as they are not exposed to the user, which is not the case here.

WiFisunset
WiFisunset
Created 1 year ago

does not actually import qiskit-aer the package which means the monkey patching that aer does on import is not run. qiskit.Aer is a lazy loading alias for qiskit.providers.aer.Aer. Just importing qiskit.Aerdoesn't actually import the aer package just that wrapper. This is why running qiskit.Aer.get_backend() works because the wrapper will import qiskit.providers.aer.Aer under the covers to alias the call to get_backend().

I believe the fix here is simply to modify the docstrings for the save_* instruction functions to highlight qiskit.providers.aer must be imported for the instructions to work. Ideally in the summary line so it shows up in the methods table too.

I ran the code as intended, but this time imported via (from qiskit.providers.aer import Aer), and the code works. I'll update my pull request to reflect that in fix https://github.com/Qiskit/qiskit-tutorials/pull/1176.

qiskit poviders aer fix

@yaelbh I've been thinking about the issue you're raising, and trying to find a solution for it. So to start I looked at the following to see how any change would affect get_backend (https://qiskit.org/documentation/stubs/qiskit.providers.aer.AerProvider.html#qiskit.providers.aer.AerProvider.get_backend and also, https://qiskit.org/documentation/stubs/qiskit.providers.Backend.html#qiskit.providers.Backend).

And it seems get_backend accepts keyword or named arguments through **kwargs, and then returns the backend which is then initialized (based off of what named arguement for the backend was requested; ex: 'unitary_simulator'). So get backends job seems to be 2 things, the first is to take a name argument to determine what simulator to initialize, and then to return that initialized backend. I'm not sure if the two tasks can or should be separated though (I'm not sure what that would impact overall).

get_backend backend class

Next