Skip to content

Commit

Permalink
Enable qpu.backend for IonQ backends (#81)
Browse files Browse the repository at this point in the history
* add to changelog

* add custom backends to qpu class

* use any backend

* update changelog

* add backend classes

* make qpu classes visible

* add docstrings and remove os import

* include both backend methods in readme

* add backends to test

* remove byte 0xe2

* only use backend field + update docs and tests

* fix line length

* run black formatter
  • Loading branch information
splch authored Nov 2, 2023
1 parent a967df1 commit 61ddfad
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 21 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Improvements 🛠

* Use new `backend` field to specify `qpu`.
[(#81)](https://github.com/PennyLaneAI/PennyLane-IonQ/pull/81)

### Breaking changes 💔

### Deprecations 👋
Expand All @@ -16,6 +19,8 @@

This release contains contributions from (in alphabetical order):

Spencer Churchill

---
# Release 0.32.0

Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ You can instantiate the IonQ devices for PennyLane as follows:
import pennylane as qml
dev1 = qml.device('ionq.simulator', wires=2, shots=1000)
dev2 = qml.device('ionq.qpu', wires=2, shots=1000)
dev2 = qml.device('ionq.qpu', backend='aria-1', wires=2, shots=1000)
These devices can then be used just like other devices for the definition and evaluation of
quantum circuits within PennyLane. For more details and ideas, see the
Expand All @@ -119,7 +119,7 @@ to the `PennyLane documentation <https://pennylane.readthedocs.io>`_.
Contributing
============

We welcome contributionssimply fork the PennyLane-IonQ repository, and then make a
We welcome contributions-simply fork the PennyLane-IonQ repository, and then make a
`pull request <https://help.github.com/articles/about-pull-requests/>`_ containing your contribution.
All contributers to PennyLane-IonQ will be listed as contributors on the releases.

Expand Down
7 changes: 4 additions & 3 deletions doc/devices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,17 @@ directly in PennyLane by specifying ``"ionq.simulator"``:
Trapped-Ion QPU
---------------

This device provides access to IonQ's trapped-ion QPU.
This device provides access to IonQ's trapped-ion QPUs.
Once the plugin has been installed, you can use this device
directly in PennyLane by specifying ``"ionq.qpu"``:
directly in PennyLane by specifying ``"ionq.qpu"`` with a
``"backend"`` from `available backends <https://docs.ionq.com/#tag/jobs>`_:

.. code-block:: python
import pennylane as qml
from pennylane_ionq import ops
dev = qml.device("ionq.qpu", wires=2)
dev = qml.device("ionq.qpu", backend="harmony", wires=2)
@qml.qnode(dev)
def circuit(x, y):
Expand Down
33 changes: 27 additions & 6 deletions pennylane_ionq/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
"""
This module contains the device class for constructing IonQ devices for PennyLane.
"""
import itertools
import functools
import warnings
import os, warnings
from time import sleep

import numpy as np
Expand Down Expand Up @@ -137,7 +135,11 @@ def apply(self, operations, **kwargs):
warnings.warn("Circuit is empty. Empty circuits return failures. Submitting anyway.")

for i, operation in enumerate(operations):
if i > 0 and operation.name in {"BasisState", "QubitStateVector", "StatePrep"}:
if i > 0 and operation.name in {
"BasisState",
"QubitStateVector",
"StatePrep",
}:
raise DeviceError(
f"The operation {operation.name} is only supported at the beginning of a circuit."
)
Expand Down Expand Up @@ -269,6 +271,7 @@ class QPUDevice(IonQDevice):
or iterable that contains unique labels for the subsystems as numbers (i.e., ``[-1, 0, 2]``)
or strings (``['ancilla', 'q1', 'q2']``).
gateset (str): the target gateset, either ``"qis"`` or ``"native"``.
backend (str): Optional specifier for an IonQ backend. Can be ``"harmony"``, ``"aria-1"``, etc.
shots (int, list[int]): Number of circuit evaluations/random samples used to estimate
expectation values of observables. If ``None``, the device calculates probability, expectation values,
and variances analytically. If an integer, it specifies the number of samples to estimate these quantities.
Expand All @@ -279,8 +282,26 @@ class QPUDevice(IonQDevice):
name = "IonQ QPU PennyLane plugin"
short_name = "ionq.qpu"

def __init__(self, wires, *, target="qpu", gateset="qis", shots=1024, api_key=None):
super().__init__(wires=wires, target=target, gateset=gateset, shots=shots, api_key=api_key)
def __init__(
self,
wires,
*,
target="qpu",
backend=None,
gateset="qis",
shots=1024,
api_key=None,
):
self.backend = backend
if self.backend is not None:
target += "." + self.backend
super().__init__(
wires=wires,
target=target,
gateset=gateset,
shots=shots,
api_key=api_key,
)

def generate_samples(self):
"""Generates samples from the qpu.
Expand Down
6 changes: 2 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@
"maintainer_email": "[email protected]",
"url": "http://xanadu.ai",
"license": "Apache License 2.0",
"packages": [
"pennylane_ionq"
],
"packages": ["pennylane_ionq"],
"entry_points": {
"pennylane.plugins": [
"ionq.simulator = pennylane_ionq:SimulatorDevice",
"ionq.qpu = pennylane_ionq:QPUDevice"
"ionq.qpu = pennylane_ionq:QPUDevice",
]
},
"description": "PennyLane plugin for IonQ",
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
# List of all devices that do *not* support analytic expectation
# value computation. This generally includes hardware devices
# and hardware simulators.
hw_devices = [SimulatorDevice]
hw_devices = [SimulatorDevice, QPUDevice]

# List of all device shortnames
shortnames = [d.short_name for d in analytic_devices + hw_devices]
Expand Down
23 changes: 18 additions & 5 deletions tests/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ def mock_submit_job(*args):
dev.apply([])

def test_failedcircuit(self, monkeypatch):

monkeypatch.setattr(
requests, "post", lambda url, timeout, data, headers: (url, data, headers)
)
Expand Down Expand Up @@ -182,6 +181,23 @@ def test_prob_no_results(self, d):
dev = qml.device(d, wires=1, shots=1)
assert dev.prob is None

@pytest.mark.parametrize(
"backend", ["harmony", "aria-1", "aria-2", "forte-1", None]
)
def test_backend_initialization(self, backend):
"""Test that the device initializes with the correct backend."""
if backend:
dev = qml.device(
"ionq.qpu",
wires=2,
shots=1000,
backend=backend,
)
assert dev.backend == backend
else:
dev = qml.device("ionq.qpu", wires=2, shots=1000)
assert dev.backend == None


class TestJobAttribute:
"""Tests job creation with mocked submission."""
Expand Down Expand Up @@ -246,7 +262,7 @@ def mock_submit_job(*args):
pass

mocker.patch("pennylane_ionq.device.IonQDevice._submit_job", mock_submit_job)
dev = IonQDevice(wires=(0,1,2), gateset="native")
dev = IonQDevice(wires=(0, 1, 2), gateset="native")

with qml.tape.QuantumTape() as tape:
GPI(0.1, wires=[0])
Expand Down Expand Up @@ -275,6 +291,3 @@ def mock_submit_job(*args):
"targets": [1, 2],
"phases": [0.2, 0.3],
}



0 comments on commit 61ddfad

Please sign in to comment.