Skip to content

Commit

Permalink
Tape mode (#68)
Browse files Browse the repository at this point in the history
* Wires

* pull PennyLane master

* grad fixes

* use PennyLane branch for tape mode with updated hash

* errors and xfail

* disable linting

* format

* Update docs: remove qpu, add warning for converter

* remove further qpu refs, update warning message

* condition for raising an error to use QPU and converter

* comment flaky

* format and linting

* no lint disabling
  • Loading branch information
antalszava committed Feb 1, 2021
1 parent 3ee122b commit 38ec98c
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 36 deletions.
11 changes: 5 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ PennyLane Forest Plugin
.. header-start-inclusion-marker-do-not-remove
Contains the PennyLane Forest plugin. This plugin allows different Rigetti devices to work with
PennyLane --- the wavefunction simulator, the Quantum Virtual Machine (QVM), and Quantum Processing
Units (QPUs).
PennyLane --- the wavefunction simulator, and the Quantum Virtual Machine (QVM).

`pyQuil <https://pyquil.readthedocs.io>`_ is a Python library for quantum programming using the
quantum instruction language (Quil) --- resulting quantum programs can be executed using the
Expand All @@ -47,10 +46,10 @@ The plugin documentation can be found here: `<https://pennylane-forest.readthedo
Features
========

* Provides four devices to be used with PennyLane: ``forest.numpy_wavefunction``,
``forest.wavefunction``, ``forest.qvm``, and ``forest.qpu``. These provide access to the pyQVM
Numpy wavefunction simulator, Forest wavefunction simulator, quantum virtual machine (QVM), and
quantum processing unit (QPU) respectively.
* Provides three devices to be used with PennyLane: ``forest.numpy_wavefunction``,
``forest.wavefunction``, and ``forest.qvm``. These provide access to the pyQVM
Numpy wavefunction simulator, Forest wavefunction simulator, and quantum
virtual machine (QVM) respectively.


* All provided devices support all core qubit PennyLane operations and observables.
Expand Down
2 changes: 2 additions & 0 deletions doc/devices/qpu.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
:orphan:

The QPU device
==============

Expand Down
8 changes: 1 addition & 7 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ Currently, PennyLane-Forest provides these Forest devices for PennyLane:
:description: Forest's QVM and pyQuil pyQVM simulator.
:link: devices/qvm.html

.. devicegalleryitem::
:name: 'forest.qpu'
:description: Forest's QPU hardware devices.
:link: devices/qpu.html

.. raw:: html

<div style='clear:both'></div>
Expand Down Expand Up @@ -79,11 +74,10 @@ Tutorials that originally showcase the forest device are the demos on
devices/numpy_wavefunction
devices/wavefunction
devices/qvm
devices/qpu

.. toctree::
:maxdepth: 1
:caption: API
:hidden:

code
code
1 change: 0 additions & 1 deletion pennylane_forest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
===============
"""
from .ops import CPHASE, ISWAP, PSWAP
from .qpu import QPUDevice
from .qvm import QVMDevice
from .wavefunction import WavefunctionDevice
from .numpy_wavefunction import NumpyWavefunctionDevice
Expand Down
25 changes: 25 additions & 0 deletions pennylane_forest/converter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import warnings
from collections.abc import Sequence
import pkg_resources
from packaging import version

import numpy as np
import pennylane as qml
Expand Down Expand Up @@ -327,6 +329,13 @@ class ProgramLoader:
_matrix_dictionary = pyquil.simulation.matrices.QUANTUM_GATES

def __init__(self, program):
pl_version = pkg_resources.get_distribution("pennylane").version
if version.parse(pl_version) >= version.parse("0.14.0.dev"):
raise ValueError(
"The PyQuil program conversion feature is not \
supported with PennyLane version 0.14.0 and higher."
)

self.program = program
self.qubits = program.get_qubits()

Expand Down Expand Up @@ -585,6 +594,12 @@ def load_program(program: pyquil.Program):
Every variable that is present in the Program and that is not used as the target
register of a measurement has to be provided in the ``parameter_map`` of the template.
.. warning::
Starting from version 0.14.0 of PennyLane and PennyLane-Forest,
converting from Forest is not supported.
Args:
program (pyquil.Program): The program that should be loaded
Expand All @@ -606,6 +621,11 @@ def load_quil(quil_str: str):
Every variable that is present in the Program and that is not used as the target
register of a measurement has to be provided in the ``parameter_map`` of the template.
.. warning::
Starting from version 0.14.0 of PennyLane and PennyLane-Forest,
converting from Forest is not supported.
Args:
quil_str (str): The program that should be loaded
Expand All @@ -627,6 +647,11 @@ def load_quil_from_file(file_path: str):
Every variable that is present in the Program and that is not used as the target
register of a measurement has to be provided in the ``parameter_map`` of the template.
.. warning::
Starting from version 0.14.0 of PennyLane and PennyLane-Forest,
converting from Forest is not supported.
Args:
file_path (str): The path to the quil file that should be loaded
Expand Down
8 changes: 8 additions & 0 deletions pennylane_forest/qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"""
import re
import warnings
import pkg_resources
from packaging import version

import numpy as np
from pyquil import get_qc
Expand Down Expand Up @@ -100,6 +102,12 @@ def __init__(
calibrate_readout="plus-eig",
**kwargs,
):
pl_version = pkg_resources.get_distribution("pennylane").version
if version.parse(pl_version) >= version.parse("0.14.0.dev"):
raise ValueError(
"Using the QPU via PennyLane-Forest is being deprecated \
with PennyLane version 0.14.0 and higher."
)

if readout_error is not None and load_qc:
raise ValueError("Readout error cannot be set on the physical QPU")
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pyquil>=2.16
git+https://github.com/PennyLaneAI/pennylane.git
networkx
flaky
flaky
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"packages": ["pennylane_forest"],
"entry_points": {
"pennylane.plugins": [
"forest.qpu = pennylane_forest:QPUDevice",
"forest.qvm = pennylane_forest:QVMDevice",
"forest.wavefunction = pennylane_forest:WavefunctionDevice",
"forest.numpy_wavefunction = pennylane_forest:NumpyWavefunctionDevice",
Expand Down
7 changes: 6 additions & 1 deletion tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pennylane_forest.converter import *


@pytest.mark.xfail
class TestProgramConverter:
"""Test that PyQuil Program instances are properly converted."""

Expand Down Expand Up @@ -643,6 +644,7 @@ def test_forked_gate_error(self):
load_program(program)(wires=range(3))


@pytest.mark.xfail
class TestQuilConverter:
"""Test that quil instances passed as string are properly converted."""

Expand Down Expand Up @@ -921,6 +923,7 @@ def test_convert_program_with_defgates(self):
assert np.array_equal(converted.data, expected.data)


@pytest.mark.xfail
class TestQuilFileConverter:
"""Test that quil files are properly converted."""

Expand Down Expand Up @@ -952,6 +955,7 @@ def test_convert_simple_program(self):
assert converted.data == expected.data


@pytest.mark.xfail
class TestInspectionProperties:
"""Test that the inspection properties of ProgramLoader return the expected values."""

Expand Down Expand Up @@ -1030,6 +1034,7 @@ def test_str(self):
assert str(loader) == "PennyLane Program Loader for PyQuil Program:\n" + str(loader.program)


@pytest.mark.xfail
class TestIntegration:
"""Test that the program loader integrates properly with PennyLane."""

Expand Down Expand Up @@ -1220,7 +1225,7 @@ def circuit_reg(a):

return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

assert np.array_equal(circuit.jacobian([angle]), circuit_reg.jacobian([angle]))
assert np.array_equal(qml.jacobian([angle]), circuit_reg.jacobian([angle]))

THETA = np.linspace(0.11, 3, 5)
PHI = np.linspace(0.32, 3, 5)
Expand Down
20 changes: 10 additions & 10 deletions tests/test_gradients.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_simulator_qvm_default_agree(tol, qvm, compiler):
dev2 = qml.device("forest.wavefunction", wires=w)
dev3 = qml.device("forest.qvm", device="9q-square-qvm", shots=5000)

in_state = np.zeros([w])
in_state = np.zeros([w], requires_grad=False)
in_state[0] = 1
in_state[1] = 1

Expand All @@ -32,17 +32,17 @@ def func(x, y):
func2 = qml.QNode(func, dev2)
func3 = qml.QNode(func, dev3)

params = [0.2, 0.453]
params = [np.array(0.2, requires_grad=True), np.array(0.453, requires_grad=True)]

# check all evaluate to the same value
# NOTE: we increase the tolerance when using the QVM
assert np.all(np.abs(func1(*params) - func2(*params)) <= tol)
assert np.all(np.abs(func1(*params) - func3(*params)) <= 0.1)
assert np.all(np.abs(func2(*params) - func3(*params)) <= 0.1)

df1 = qml.grad(func1, argnum=[0, 1])
df2 = qml.grad(func2, argnum=[0, 1])
df3 = qml.grad(func3, argnum=[0, 1])
df1 = qml.grad(func1)
df2 = qml.grad(func2)
df3 = qml.grad(func3)

# check all gradients evaluate to the same value
# NOTE: we increase the tolerance when using the QVM
Expand All @@ -62,24 +62,24 @@ def test_gradient_with_custom_operator(qvm, compiler):

def func(x, y):
"""Reference QNode"""
qml.BasisState(np.array([1, 1]), wires=0)
qml.BasisState(np.array([1, 1], requires_grad=False), wires=0)
qml.RY(x, wires=0)
qml.RX(y, wires=1)
PSWAP(0.432, wires=[0, 1])
PSWAP(np.array(0.432, requires_grad=False), wires=[0, 1])
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(1))

func2 = qml.QNode(func, dev2)
func3 = qml.QNode(func, dev3)

params = [0.2, 0.453]
params = [np.array(0.2, requires_grad=True), np.array(0.453, requires_grad=True)]

# check all evaluate to the same value
# NOTE: we increase the tolerance when using the QVM
assert np.all(np.abs(func2(*params) - func3(*params)) <= 0.1)

df2 = qml.grad(func2, argnum=[0, 1])
df3 = qml.grad(func3, argnum=[0, 1])
df2 = qml.grad(func2)
df3 = qml.grad(func3)

# check all gradients evaluate to the same value
# NOTE: we increase the tolerance when using the QVM
Expand Down
21 changes: 12 additions & 9 deletions tests/test_qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
TEST_QPU_LATTICES = ["4q-qvm"]


@pytest.mark.xfail
class TestQPUIntegration(BaseTest):
"""Test the wavefunction simulator works correctly from the PennyLane frontend."""

Expand Down Expand Up @@ -66,7 +67,8 @@ def test_qpu_args(self):
with pytest.raises(ValueError, match="Device has a fixed number of"):
qml.device("forest.qpu", device=device, shots=5, wires=range(100), load_qc=False)

@flaky(max_runs=10, min_passes=3)
# As tests are expected to fail, the flaky decorators were marked as comments
#@flaky(max_runs=10, min_passes=3)
@pytest.mark.parametrize(
"obs", [qml.PauliX(0), qml.PauliZ(0), qml.PauliY(0), qml.Hadamard(0), qml.Identity(0)]
)
Expand Down Expand Up @@ -113,7 +115,7 @@ def circuit_obs(param):

assert np.allclose(res, exp, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
@pytest.mark.parametrize(
"obs", [qml.PauliX(0), qml.PauliZ(0), qml.PauliY(0), qml.Hadamard(0), qml.Identity(0)]
)
Expand Down Expand Up @@ -161,6 +163,7 @@ def circuit_obs(param):
assert np.allclose(res, exp, atol=2e-2)


@pytest.mark.xfail
class TestQPUBasic(BaseTest):
"""Unit tests for the QPU (as a QVM)."""

Expand Down Expand Up @@ -302,7 +305,7 @@ def circuit_Zmi():
assert np.allclose(results[:3], 1.0, atol=2e-2)
assert np.allclose(results[3:], -1.0, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
def test_multi_qub_no_readout_errors(self):
"""Test the QPU plugin with no readout errors or correction"""
device = np.random.choice(TEST_QPU_LATTICES)
Expand All @@ -328,7 +331,7 @@ def circuit():

assert np.isclose(result, 0.5, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
def test_multi_qub_readout_errors(self):
"""Test the QPU plugin with readout errors"""
device = np.random.choice(TEST_QPU_LATTICES)
Expand All @@ -353,7 +356,7 @@ def circuit():

assert np.isclose(result, 0.38, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
def test_multi_qub_readout_correction(self):
"""Test the QPU plugin with readout errors and correction"""
device = np.random.choice(TEST_QPU_LATTICES)
Expand All @@ -378,7 +381,7 @@ def circuit():

assert np.isclose(result, 0.5, atol=3e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
def test_2q_gate(self):
"""Test that the two qubit gate with the PauliZ observable works correctly.
Expand All @@ -404,7 +407,7 @@ def circuit():

assert np.allclose(circuit(), 0.0, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
def test_2q_gate_pauliz_identity_tensor(self):
"""Test that the PauliZ tensor Identity observable works correctly.
Expand All @@ -429,7 +432,7 @@ def circuit():

assert np.allclose(circuit(), 0.0, atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
@pytest.mark.parametrize("a", np.linspace(-0.5, 2, 6))
def test_2q_gate_pauliz_pauliz_tensor(self, a):
"""Test that the PauliZ tensor PauliZ observable works correctly.
Expand Down Expand Up @@ -458,7 +461,7 @@ def circuit(x):
# Check that repeated calling of the QNode works correctly
assert np.allclose(circuit(a), np.cos(a), atol=2e-2)

@flaky(max_runs=10, min_passes=3)
#@flaky(max_runs=10, min_passes=3)
@pytest.mark.parametrize("a", np.linspace(-np.pi / 2, 0, 3))
@pytest.mark.parametrize("b", np.linspace(0, np.pi / 2, 3))
def test_2q_circuit_pauliz_pauliz_tensor(self, a, b):
Expand Down

0 comments on commit 38ec98c

Please sign in to comment.