Skip to content

Commit

Permalink
Update from lattice-based to device-based naming (#51)
Browse files Browse the repository at this point in the history
* Update naming

* Update QVM init

* Update qpu

* Fix connection loading

* Update tests

* Fix examples

* Fix test

* Add connection to another device

* Run tests only on 4q-qvm

* Remove keyword arguments in docstring as they are no longer used
  • Loading branch information
trbromley committed May 27, 2020
1 parent d2e3870 commit 3ae4aff
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 143 deletions.
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ You can instantiate these devices for PennyLane as follows:
dev_simulator = qml.device('forest.wavefunction', wires=2)
dev_pyqvm = qml.device('forest.qvm', device='2q-pyqvm', shots=1000)
dev_qvm = qml.device('forest.qvm', device='2q-qvm', shots=1000)
dev_qpu = qml.device('forest.qpu', device='Aspen-0-12Q-A', shots=1000)
dev_qpu = qml.device('forest.qpu', device='Aspen-8', shots=1000)
These devices can then be used just like other devices for the definition and evaluation of QNodes within PennyLane. For more details, see the `plugin usage guide <https://pennylane-forest.readthedocs.io/en/latest/usage.html>`_ and refer to the PennyLane documentation.

Expand Down
12 changes: 6 additions & 6 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ You can instantiate these devices in PennyLane as follows:
>>> dev_simulator = qml.device('forest.wavefunction', wires=2)
>>> dev_pyqvm = qml.device('forest.qvm', device='2q-pyqvm', shots=1000)
>>> dev_qvm = qml.device('forest.qvm', device='2q-qvm', shots=1000)
>>> dev_qpu = qml.device('forest.qpu', device='Aspen-0-12Q-A', shots=1000)
>>> dev_qpu = qml.device('forest.qpu', device='Aspen-8', shots=1000)



Expand Down Expand Up @@ -166,13 +166,13 @@ The ``forest.qvm`` device provides an interface between PennyLane and the Forest

Note that, unlike ``forest.wavefunction``, you do not pass the number of wires - this is inferred automatically from the requested quantum computer topology.

>>> dev = qml.device('forest.qvm', device='Aspen-1-16Q-A')
>>> dev = qml.device('forest.qvm', device='Aspen-8')
>>> dev.num_wires
16

In addition, you may also request a QVM with noise models to better simulate a physical QPU; this is done by passing the keyword argument ``noisy=True``:

>>> dev = qml.device('forest.qvm', device='Aspen-1-16Q-A', noisy=True)
>>> dev = qml.device('forest.qvm', device='Aspen-8', noisy=True)

Note that only the `default noise models <http://docs.rigetti.com/en/stable/noise.html>`_ provided by pyQuil are currently supported.

Expand All @@ -190,11 +190,11 @@ When initializing the ``forest.qvm`` device, the following required keyword argu
The name or topology of the quantum computer to initialize.

* ``Nq-qvm``: for a fully connected/unrestricted N-qubit QVM
* ``9q-qvm-square``: a :math:`9\times 9` lattice.
* ``Nq-pyqvm`` or ``9q-pyqvm-square``, for the same as the above but run
* ``9q-square-qvm``: a :math:`9\times 9` lattice.
* ``Nq-pyqvm`` or ``9q-square-pyqvm``, for the same as the above but run
via the built-in pyQuil pyQVM device.
* Any other supported Rigetti device architecture, for
example a QPU lattice such as ``'Aspen-1-16Q-A'``.
example a QPU lattice such as ``'Aspen-8'``.
* Graph topology (as a ``networkx.Graph`` object) representing the device architecture.


Expand Down
2 changes: 1 addition & 1 deletion examples/Readout Error Mitigation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"metadata": {},
"outputs": [],
"source": [
"device_name = 'Aspen-4-4Q-A'"
"device_name = 'Aspen-8'"
]
},
{
Expand Down
6 changes: 3 additions & 3 deletions examples/q1-rotation-aspen-qpu-momentum-optimizer.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### create forest QPU device, using the Aspen-1-15Q-A lattice"
"### create forest QPU device, using Aspen-8"
]
},
{
Expand All @@ -136,10 +136,10 @@
"metadata": {},
"outputs": [],
"source": [
"# note that, for this example, we can book any QPU lattice, not necessarily just Aspen-1-15Q-A\n",
"# note that, for this example, we can book any available device, not necessarily just Aspen-8\n",
"\n",
"dev = qml.device('forest.qpu', \n",
" device='Aspen-1-15Q-A', \n",
" device='Aspen-8', \n",
" shots=100,\n",
" active_reset=True)"
]
Expand Down
49 changes: 12 additions & 37 deletions pennylane_forest/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,6 @@ class ForestDevice(QubitDevice):
shots (int): Number of circuit evaluations/random samples used
to estimate expectation values of observables.
For simulator devices, 0 means the exact EV is returned.
Keyword args:
forest_url (str): the Forest URL server. Can also be set by
the environment variable ``FOREST_URL``, or in the ``~/.qcs_config``
configuration file. Default value is ``"https://forest-server.qcs.rigetti.com"``.
qvm_url (str): the QVM server URL. Can also be set by the environment
variable ``QVM_URL``, or in the ``~/.forest_config`` configuration file.
Default value is ``"http://127.0.0.1:5000"``.
quilc_url (str): the compiler server URL. Can also be set by the environment
variable ``QUILC_URL``, or in the ``~/.forest_config`` configuration file.
Default value is ``"http://127.0.0.1:6000"``.
"""
pennylane_requires = ">=0.9"
version = __version__
Expand All @@ -188,35 +177,21 @@ class ForestDevice(QubitDevice):
def __init__(self, wires, shots=1000, analytic=False, **kwargs):
super().__init__(wires, shots, analytic=analytic)
self.analytic = analytic
self.forest_url = kwargs.get("forest_url", pyquil_config.forest_url)
self.qvm_url = kwargs.get("qvm_url", pyquil_config.qvm_url)
self.compiler_url = kwargs.get("compiler_url", pyquil_config.quilc_url)

self.connection = ForestConnection(
sync_endpoint=self.qvm_url,
compiler_endpoint=self.compiler_url,
forest_cloud_endpoint=self.forest_url,
)

# The following environment variables are deprecated I think

# api_key (str): the Forest API key. Can also be set by the environment
# variable ``FOREST_API_KEY``, or in the ``~/.qcs_config`` configuration file.
# user_id (str): the Forest user ID. Can also be set by the environment
# variable ``FOREST_USER_ID``, or in the ``~/.qcs_config`` configuration file.
# qpu_url (str): the QPU server URL. Can also be set by the environment
# variable ``QPU_URL``, or in the ``~/.forest_config`` configuration file.

# if 'api_key' in kwargs:
# os.environ['FOREST_API_KEY'] = kwargs['api_key']
self.reset()

# if 'user_id' in kwargs:
# os.environ['FOREST_USER_ID'] = kwargs['user_id']
@staticmethod
def _get_connection(**kwargs):
forest_url = kwargs.get("forest_url", pyquil_config.forest_url)
qvm_url = kwargs.get("qvm_url", pyquil_config.qvm_url)
compiler_url = kwargs.get("compiler_url", pyquil_config.quilc_url)

# if 'qpu_url' in kwargs:
# os.environ['QPU_URL'] = kwargs['qpu_url']
connection = ForestConnection(
sync_endpoint=qvm_url,
compiler_endpoint=compiler_url,
forest_cloud_endpoint=forest_url,
)

self.reset()
return connection

@property
def program(self):
Expand Down
9 changes: 5 additions & 4 deletions pennylane_forest/qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,7 @@ def __init__(
if shots <= 0:
raise ValueError("Number of shots must be a positive integer.")

aspen_match = re.match(r"Aspen-\d+-([\d]+)Q", device)
num_wires = int(aspen_match.groups()[0])

super(QVMDevice, self).__init__(num_wires, shots, **kwargs)
self.connection = super()._get_connection(**kwargs)

if load_qc:
self.qc = get_qc(device, as_qvm=False, connection=self.connection)
Expand All @@ -152,6 +149,10 @@ def __init__(
if timeout is not None:
self.qc.compiler.client.timeout = timeout

num_wires = len(self.qc.qubits())

super(QVMDevice, self).__init__(num_wires, shots, **kwargs)

self.active_reset = active_reset
self.symmetrize_readout = symmetrize_readout
self.calibrate_readout = calibrate_readout
Expand Down
31 changes: 7 additions & 24 deletions pennylane_forest/qvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ class QVMDevice(ForestDevice):
device (Union[str, nx.Graph]): the name or topology of the device to initialise.
* ``Nq-qvm``: for a fully connected/unrestricted N-qubit QVM
* ``9q-qvm-square``: a :math:`9\times 9` lattice.
* ``Nq-pyqvm`` or ``9q-pyqvm-square``, for the same as the above but run
* ``9q-square-qvm``: a :math:`9\times 9` lattice.
* ``Nq-pyqvm`` or ``9q-square-pyqvm``, for the same as the above but run
via the built-in pyQuil pyQVM device.
* Any other supported Rigetti device architecture.
* Graph topology representing the device architecture.
Expand Down Expand Up @@ -106,28 +106,7 @@ def __init__(self, device, *, shots=1000, noisy=False, **kwargs):
if analytic:
raise ValueError("QVM device cannot be run in analytic=True mode.")

# get the number of wires
if isinstance(device, nx.Graph):
# load a QVM based on a graph topology
num_wires = device.number_of_nodes()
elif isinstance(device, str):
# the device string must match a valid QVM device, i.e.
# N-qvm, or 9q-square-qvm, or Aspen-1-16Q-A
wire_match = re.search(r"(\d+)(q|Q)", device)

if wire_match is None:
# with the current Rigetti naming scheme, this error should never
# appear as long as the QVM quantum computer has the correct name
raise ValueError("QVM device string does not indicate the number of qubits!")

num_wires = int(wire_match.groups()[0])
else:
raise ValueError(
"Required argument device must be a string corresponding to "
"a valid QVM quantum computer, or a NetworkX graph object."
)

super().__init__(num_wires, shots, analytic=analytic, **kwargs)
self.connection = super()._get_connection(**kwargs)

# get the qc
if isinstance(device, nx.Graph):
Expand All @@ -137,6 +116,10 @@ def __init__(self, device, *, shots=1000, noisy=False, **kwargs):
elif isinstance(device, str):
self.qc = get_qc(device, as_qvm=True, noisy=noisy, connection=self.connection)

num_wires = len(self.qc.qubits())

super().__init__(num_wires, shots, analytic=analytic, **kwargs)

if timeout is not None:
self.qc.compiler.client.timeout = timeout

Expand Down
1 change: 1 addition & 0 deletions pennylane_forest/wavefunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class WavefunctionDevice(ForestDevice):

def __init__(self, wires, *, shots=1000, analytic=True, **kwargs):
super().__init__(wires, shots, analytic, **kwargs)
self.connection = super()._get_connection(**kwargs)
self.qc = WavefunctionSimulator(connection=self.connection)
self._state = None

Expand Down

0 comments on commit 3ae4aff

Please sign in to comment.