Open karalekas opened 5 years ago
Is this still open and what are some suggested modules to look at in order to fix this?
Yes, as far as I know this is still an issue. I'm actually not sure what correct fix here is though.
I'd recommend starting in the QuantumComputer.run
method in pyquil/api/_quantum_computer.py
, then follow along with the call graph into the corresponding QAM
and QVM
classes in pyquil/api/_qam.py
and pyquil/api/_qvm.py
, respectively.
Let us know if you have questions. Happy to review a PR or discuss in this thread.
Cool cool, off the top of my head, sounds like some state is cached or not cleared. Will check it out.
So here's what I found. As suspected, some state is not being reset. When qvm.run
starts, it sets the status to running
and does not reset this after the error. So I manually called qvm.reset()
but this means you could lose all the computed in-memory data so far like connection
, compiler
etc. unless there's a way that those can be quickly reconfigured by injecting their dependencies...
What should probably be happening is that when qvm.run
fails on an empty Program
, the status should be reset immediately. This can be done by wrapping the assert
in a try except
?
# https://sourcegraph.com/github.com/rigetti/pyquil/-/blob/pyquil/api/_qam.py#L58
def load(self, executable: Union[BinaryExecutableResponse, PyQuilExecutableResponse]) -> "QAM":
"""
Initialize a QAM into a fresh state.
:param executable: Load a compiled executable onto the QAM.
"""
self.status: str
if self.status == "loaded":
warnings.warn("Overwriting previously loaded executable.")
assert self.status in ["connected", "done", "loaded"]
# ^^^ this AssertionError should be handled ^^^
Or better still, status should only be set to running
when load()
is complete.
https://sourcegraph.com/github.com/rigetti/pyquil/-/blob/pyquil/api/_quantum_computer.py#L133
Here's my version of the snippet from the first comment on this issue:
from pyquil import get_qc, Program
qvm = get_qc('9q-qvm')
try:
qvm.run(Program())
except:
print("bad happened")
# set my debugger to watch the qvm variable and saw that qvm.qam.status remained 'running'
qvm.reset() # will revert status to 'connected'
qvm.run(Program('X 0'))
print(qvm)
# prints 9q-qvm
Those are my thoughts and there are probably better solutions. But it all centers around resetting the status of the machine.
What should probably be happening is that when
qvm.run
fails on an emptyProgram
, the status should be reset immediately.
I'm not sure I like the idea of calling reset
automatically in these cases. For example QAM.reset
also resets the _memory_results
dictionary, which would wipe out any accumulated state from previous runs. otoh, we apparently call reset
on every compile
when the underlying QAM
is a QPU
, so maybe it's not the end of the world.
Personally, I think a better approach would be to change all the assert
s that are validating the state transitions inside the QAM
class to instead raise an exception with a more helpful error message telling the user they can call qc.reset
themselves if they want, but that they will lose any accumulated state. So for example the line
assert self.status in ["connected", "done", "loaded"]
would change to something like
if self.status not in ["connected", "done", "loaded"]:
raise QAMStateTransitionError(current=self.status, expected= ["connected", "done", "loaded"])
or something like that.
Another option would be to add a check at the top of the compile
method and raise an error there if the user tries to compile an empty program. That won't work for the example in the original bug description which is passing a bare Program
to qc.run
without first compiling, but technically that appears to be breaking the interface, as qc.run
is declared to take an executable, not a Program
.
There is a larger (philosophical) question of why attempting to run an empty program should be an error, but it seems we've already made that choice, so I'm happy to stick with it.
There is a larger (philosophical) question of why attempting to run an empty program should be an error, but it seems we've already made that choice, so I'm happy to stick with it.
I may have spoken too soon! It seems there is some debate about this very topic: https://github.com/rigetti/pyquil/pull/1182#issuecomment-597918021
Yes, I prefer this approach too.
would change to something like
if self.status not in ["connected", "done", "loaded"]: raise QAMStateTransitionError(current=self.status, expected= ["connected", "done", "loaded"])
Along the lines of what I was thinking when I wrote
This can be done by wrapping the assert in a try except?
What would the next steps be
QAMStateTransitionError
exceptionrun()
function in _quantum_computer.py
I think a two-pronged approach makes sense, namely:
Program
.reset
to put the QuantumComputer
or QAM
back into a useable state.Regarding (1), I think adding a check near the top of QuantumComputer.compile
and raising an exception if program
is empty makes sense. This won't prevent the error in the original example, which never calls compile
, but the docstring for QuantumComputer.run
says that the caller is responsible for compiling the executable
argument, so I think the compile
method is a reasonable place to do the empty-program check.
Regarding (2), maybe a new exception class is overkill and we can just pass a helpful error message to the existing assert
statements.
So next steps might be something like:
QuantumComputer.compile
that raises ValueError
if program
is an empty Program
.pyquil/_api/_qam.py
module, something like _QAM_BAD_STATE_ERR_MSG = "Invalid QAM state. The requested operation cannot be performed. You can call QAM.reset or QuantumComputer.reset to reset the state.
assert self.status ...
in pyquil/_api/_qam.py
and pyquil/pyqvm.py
with assert self.status ..., _QAM_BAD_STATE_ERR_MSG
.Hello, has this issue been resolved? If not, I'd like to work on it.
Hey, @CaineArdayfio. This is still an open issue. Take a look at https://github.com/rigetti/pyquil/issues/1034#issuecomment-598976922 for some suggestions on how to tackle this. :D
Pre-Report Checklist
Issue Description
Running an empty
Program
results in an error and then puts theQuantumComputer
in a bad state.How to Reproduce
Code Snippet
then
Error Output
then
Environment Context
Operating System: Debian Buster
Python Version (
python -V
): 3.6.9Quilc Version (
quilc --version
): 1.12.0QVM Version (
qvm --version
): 1.12.0