ProjectQ icon indicating copy to clipboard operation
ProjectQ copied to clipboard

Bizarre IndexError if attempt to measure a qubit after a Control block

Open refi64 opened this issue 4 years ago • 3 comments

Repro:

from projectq.ops import X, Measure
import projectq
import projectq.meta

eng = projectq.MainEngine()
q0 = eng.allocate_qubit()

with projectq.meta.Control(eng, q0):
    X | q0

# eng.flush()
Measure | q0
print(int(q0))

This yields:

Traceback (most recent call last):
  File "bell_state.py", line 18, in <module>
    Measure | q0
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/ops/_gates.py", line 284, in __or__
    apply_command(cmd)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/ops/_command.py", line 58, in apply_command
    engine.receive([cmd])
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_main.py", line 266, in receive
    self.send(command_list)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_main.py", line 288, in send
    raise compact_exception  # use verbose=True for more info
IndexError: list index out of range
 raised in:
'  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_optimize.py", line 136, in _optimize'
'    if inv == self._l[idx][i + 1]:'

With verbose=True:

Traceback (most recent call last):
  File "bell_state.py", line 18, in <module>
    Measure | q0
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/ops/_gates.py", line 284, in __or__
    apply_command(cmd)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/ops/_command.py", line 58, in apply_command
    engine.receive([cmd])
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_main.py", line 266, in receive
    self.send(command_list)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_main.py", line 275, in send
    self.next_engine.receive(command_list)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_tagremover.py", line 58, in receive
    self.send([cmd])
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_basics.py", line 185, in send
    self.next_engine.receive(command_list)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_optimize.py", line 244, in receive
    self._cache_cmd(cmd)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_optimize.py", line 224, in _cache_cmd
    self._check_and_send()
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_optimize.py", line 196, in _check_and_send
    self._optimize(i)
  File "/var/home/ryan/.virtualenvs/projectq/lib/python3.7/site-packages/projectq/cengines/_optimize.py", line 136, in _optimize
    if inv == self._l[idx][i + 1]:
IndexError: list index out of range

Of course, eng.flush() fixes the issue, but this should probably raise that relevant exception instead of the more obscure IndexError...

On that note, is there a reason why this doesn't work:

from projectq.ops import X, Measure
import projectq
import projectq.meta

eng = projectq.MainEngine()
q0 = eng.allocate_qubit()

X | q0
eng.flush()
Measure | q0
assert int(q0) == 1  # okay
# should flip q0 back to 0, since it being 1 should enter the control block
with projectq.meta.Control(eng, q0):
    X | q0

eng.flush()
Measure | q0
assert int(q0) == 0  # fail

EDIT: I just realized my eng.flush()'s were before the Measure statements in order to avoid the crash, but aren't they supposed to be after?

EDIT 2: The same crash can be reproduced via CNOT | (q0, q0).

refi64 avatar Oct 28 '19 19:10 refi64

eng.flush() statements need to be put before accessing the result of some measurements.

Now, I am not sure having a CNOT gate with identical control and target qubits makes a lot of sense, because by definition, the control target should not be modified after the application of the gate. Also, it is usually understood that 2-qubit gate get applied on two different qubits.

It is true, however, that ProjectQ currently does not checks whether control and target qubits are disjoints.

Takishima avatar Oct 29 '19 10:10 Takishima

Yeah identical qubits in a CNOT isn't useful or even allowed by most frameworks, but crashing with an obscure IndexError isn't very helpful in that case either...

refi64 avatar Oct 29 '19 12:10 refi64

Yeah identical qubits in a CNOT isn't useful or even allowed by most frameworks, but crashing with an obscure IndexError isn't very helpful in that case either...

I agree! So I'll keep this issue open until we fix this (hopefully sometime soon)

Takishima avatar Oct 29 '19 12:10 Takishima