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

DefGate broken in the NumpyWavefunctionSimulator #1059

Closed
josh146 opened this issue Oct 18, 2019 · 4 comments · Fixed by #1067
Closed

DefGate broken in the NumpyWavefunctionSimulator #1059

josh146 opened this issue Oct 18, 2019 · 4 comments · Fixed by #1067
Assignees
Labels
bug 🐛 An issue that needs fixing.
Milestone

Comments

@josh146
Copy link

josh146 commented Oct 18, 2019

Issue Description

DefGate seems to be broken in NumpyWavefunctionSimulator.

How to Reproduce

Code Snippet

Use any custom gate definition. Here I just copied from http://docs.rigetti.com/en/stable/basics.html#defining-parametric-gates.

from pyquil import Program
from pyquil.quilatom import Parameter, quil_sin, quil_cos 
from pyquil.quilbase import DefGate
from pyquil.gates import X, Y, Z, H, PHASE, RX, RY, RZ, CZ, SWAP, CNOT
import numpy as np 
 
# Define the new gate from a matrix 
theta = Parameter('theta') 
crx = np.array([ 
    [1, 0, 0, 0], 
    [0, 1, 0, 0], 
    [0, 0, quil_cos(theta / 2), -1j * quil_sin(theta / 2)], 
    [0, 0, -1j * quil_sin(theta / 2), quil_cos(theta / 2)] 
]) 
 
gate_definition = DefGate('CRX', crx, [theta]) 
CRX = gate_definition.get_constructor() 
 
# Create our program and use the new parametric gate 
p = Program() 
p += [gate_definition, CRX(np.pi/2)(0, 1)] 
p += H(0) 
p += CRX(np.pi/2)(0, 1)

from pyquil.numpy_simulator import NumpyWavefunctionSimulator
from pyquil.pyqvm import PyQVM

qc = PyQVM(n_qubits=2, quantum_simulator_type=NumpyWavefunctionSimulator)
qc.execute(p).wf_simulator.wf.flatten()

Error Output

KeyError                                  Traceback (most recent call last)
<ipython-input-14-a45963b2b08a> in <module>
----> 1 qc.execute(p).wf_simulator.wf.flatten()

~/miniconda3/envs/py36/lib/python3.6/site-packages/pyquil/pyqvm.py in execute(self, program)
    449         halted = len(program) == 0
    450         while not halted:
--> 451             halted = self.transition()
    452 
    453         return self

~/miniconda3/envs/py36/lib/python3.6/site-packages/pyquil/pyqvm.py in transition(self)
    282                                                  qubits=[q.index for q in instruction.qubits])
    283             else:
--> 284                 self.wf_simulator.do_gate(gate=instruction)
    285 
    286             for noise_type, noise_prob in self.post_gate_noise_probabilities.items():

~/miniconda3/envs/py36/lib/python3.6/site-packages/pyquil/numpy_simulator.py in do_gate(self, gate)
    266         :return: ``self`` to support method chaining.
    267         """
--> 268         gate_matrix, qubit_inds = _get_gate_tensor_and_qubits(gate=gate)
    269         # Note to developers: you can use either einsum- or tensordot- based functions.
    270         # tensordot seems a little faster, but feel free to experiment.

~/miniconda3/envs/py36/lib/python3.6/site-packages/pyquil/numpy_simulator.py in _get_gate_tensor_and_qubits(gate)
    160     """
    161     if len(gate.params) > 0:
--> 162         matrix = QUANTUM_GATES[gate.name](*gate.params)
    163     else:
    164         matrix = QUANTUM_GATES[gate.name]

KeyError: 'CRX'

Environment Context

Operating System: Ubuntu 18.04.1

Python Version (python -V): 3.6.8

Quilc Version (quilc --version): latest rigetti/qvm docker image

QVM Version (qvm --version): latest rigetti/quilc docker image

Python Environment Details (pip freeze or conda list):

pyquil==2.12.0
numpy==1.16.4
scipy==1.3.0
@appleby
Copy link
Contributor

appleby commented Oct 18, 2019

Hi, thanks for reporting this.

I am not super familiar with the PyQVM API, but it looks like there are several things going on.

  1. PyQVM doesn't support parametric defgates. There is code in the PyQVM class to detect parametric defgates and report a sane error, but calling execute in this way appears to circumvent it. So this is probably a bug.

  2. PyQVM implements the "Quantum Abstract Machine" (QAM) interface, and I suspect you're meant to either interact with it via the QAM interface, or else indirectly via a Quantum Computer. Neither of those classes implement an execute method, so perhaps that method should "private" to the PyQVM class. This is just a guess though.

  3. If instead of calling execute directly, you follow a procedure similar to the one outlined in the QuantumComputer docs, then you'll get an explicit NotImplementedError: PyQVM does not support parameterized DEFGATEs. For example, if you replace the final two lines of your example code with the following:

from pyquil import get_qc
qc = get_qc('2q-pyqvm')
ro = p.declare('ro', 'BIT', 1)
p += MEASURE(1, ro[0])
compiled_program = qc.compile(p)
results = qc.run(compiled_program)
  1. You might reasonably expect PyQVM to not throw an error about the parametric DEFGATE if you're passing it a compiled program that no longer contains any references to said parametric gate other than the DEFGATE form itself. But for all I know, that is expected behavior.

@josh146
Copy link
Author

josh146 commented Oct 18, 2019

If instead of calling execute directly, you follow a procedure similar to the one outlined in the QuantumComputer docs, then you'll get an explicit NotImplementedError: PyQVM does not support parameterized DEFGATEs.

Ah, that's good to know!

PyQVM doesn't support parametric defgates.

I should clarify, that the reason I noticed this was that non-parametrized DEFGATEs used to work in the PyQVM --- they work in PyQuil 2.10, for example. We rely on this feature over in https://github.com/rigetti/pennylane-forest to compute multi-qubit arbitrary expectation values.

@josh146
Copy link
Author

josh146 commented Oct 18, 2019

For example, using

theta = 0.543

U = np.array([ 
    [1, 0, 0, 0], 
    [0, 1, 0, 0], 
    [0, 0, np.cos(theta / 2), -1j * np.sin(theta / 2)], 
    [0, 0, -1j * np.sin(theta / 2), np.cos(theta / 2)] 
]) 
 
gate_definition = DefGate('U_test', U) 
U_test = gate_definition.get_constructor() 

I get the same error as above in the latest PyQuil PyQVM, but it works fine in 2.10.

@appleby
Copy link
Contributor

appleby commented Oct 18, 2019

I see. Yes, looking at the git history, the behavior of execute w.r.t. defgates did likely change recently. As a (partial) workaround, calling the PyQVM via QAM interface methods load and run should still work in the presence of non-parametric defgates, or indeed via the QuantumComputer interfaces. Note that these reset the wavefunction and memory registers each time they are called though.

Full example calling PyQVM via QAM interface:

import numpy as np

from pyquil import Program
from pyquil.quilbase import DefGate
from pyquil.numpy_simulator import NumpyWavefunctionSimulator
from pyquil.pyqvm import PyQVM

theta = 0.543

U = np.array([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, np.cos(theta / 2), -1j * np.sin(theta / 2)],
    [0, 0, -1j * np.sin(theta / 2), np.cos(theta / 2)]
])

gate_definition = DefGate('U_test', U)
U_test = gate_definition.get_constructor()

p = Program()
p += gate_definition
p += U_test(0, 1)
ro = p.declare('ro', 'BIT', 2)
p += MEASURE(0, ro[0])
p += MEASURE(1, ro[1])

qam = PyQVM(n_qubits=2, quantum_simulator_type=NumpyWavefunctionSimulator)
qam.load(p)
qam.run()
qam.read_memory(region_name="ro")

Or via the QuantumComputer interface (building on the last example):

from pyquil import get_qc
qc = get_qc('2q-pyqvm')
p = Program()
p += gate_definition
p += U_test(0, 1)
qc.run_and_measure(p, trials=1)

appleby added a commit that referenced this issue Oct 20, 2019
In #874, PyQVM was changed to remove the restriction for
run-and-measure style programs. In the process, PyQVM.execute lost the
ability to execute programs with user defined gates, which apparently
broke pennylane-forest's PyQVM support.

This commit re-instates the block of code for extracting defined_gates
from the Program passed to PyQVM.execute, and with it the ability to
execute Programs with (non-parametric) defgates.

Fixes #1059

See also: PennyLaneAI/pennylane-rigetti#22
appleby added a commit that referenced this issue Oct 20, 2019
In #874, PyQVM was changed to remove the restriction for
run-and-measure style programs. In the process, PyQVM.execute lost the
ability to execute programs with user defined gates, which apparently
broke pennylane-forest's PyQVM support.

This commit reinstates the block of code for extracting defined_gates
from the Program passed to PyQVM.execute, and with it the ability to
execute Programs with (non-parametric) defgates.

Fixes #1059

See also: PennyLaneAI/pennylane-rigetti#22
@karalekas karalekas added this to the v2.13 milestone Oct 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 An issue that needs fixing.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants