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

Update plugin for ProjectQ v0.5.1 support, including IBM API v2 #62

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@

### Documentation

* The documentation theme has been updated, and the documentation structure
reorganized.
[(#60)](https://github.com/XanaduAI/pennylane-pq/pull/60)

### Bug fixes

* Updated the plugin to use the latest IBMQBackend from ProjectQ.
[(#62)](https://github.com/XanaduAI/pennylane-pq/pull/61)

### Contributors

This release contains contributions from (in alphabetical order):

Maria Schuld

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add yourself @josh146 :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆 Oddly enough, the tests now pass for me locally, but not on travis...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that Travis' token expired?

---

# Release 0.8.0
Expand Down
23 changes: 11 additions & 12 deletions pennylane_pq/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,9 @@ class ProjectQIBMBackend(_ProjectQDevice):
(instead of using the IBM simulator)
num_runs (int): Number of runs to collect statistics (default is 1024).
Is equivalent to but takes preference over the shots parameter.
user (string): IBM Quantum Experience user name
password (string): IBM Quantum Experience password
device (string): Device to use (‘ibmqx4’, or ‘ibmqx5’) if
:code:`use_hardware` is set to True. Default is 'ibmqx4'.
token (string): IBM Quantum Experience API token
device (string): IBMQ backend to use (ibmq_16_melbourne’, ‘ibmqx2’, 'ibmq_rome' 'ibmq_qasm_simulator') if
:code:`use_hardware` is set to True. Default is '‘ibmqx5’'.
retrieve_execution (int): Job ID to retrieve instead of re-running
a circuit (e.g., if previous run timed out).
verbose (bool): If True, log messages are printed and exceptions are more verbose.
Expand All @@ -391,7 +390,7 @@ class ProjectQIBMBackend(_ProjectQDevice):
.. code-block:: python

import pennylane as qml
dev = qml.device('projectq.ibm', wires=XXX, user="XXX", password="XXX")
dev = qml.device('projectq.ibm', wires=XXX, token="XXX")

To avoid leaking your user name and password when sharing code,
it is better to specify the user name and password in your
Expand Down Expand Up @@ -443,15 +442,12 @@ class ProjectQIBMBackend(_ProjectQDevice):
CZ, Rot, BasisState]}
_observable_map = dict({key:val for key, val in _operation_map.items() if val in [HGate, XGate, YGate, ZGate]}, **{'Identity': None})
_circuits = {}
_backend_kwargs = ['use_hardware', 'num_runs', 'verbose', 'user', 'password', 'device',
'retrieve_execution']
_backend_kwargs = ['use_hardware', 'num_runs', 'verbose', 'token', 'device', 'retrieve_execution']

def __init__(self, wires=1, shots=1024, **kwargs):
# check that necessary arguments are given
if 'user' not in kwargs:
raise ValueError('An IBM Quantum Experience user name specified via the "user" keyword argument is required') #pylint: disable=line-too-long
if 'password' not in kwargs:
raise ValueError('An IBM Quantum Experience password specified via the "password" keyword argument is required') #pylint: disable=line-too-long
if 'token' not in kwargs:
raise ValueError('An IBM Quantum Experience token specified via the "token" keyword argument is required') #pylint: disable=line-too-long

import projectq.setups.ibm #pylint: disable=unused-variable

Expand All @@ -462,7 +458,10 @@ def reset(self):
"""Reset/initialize the device by initializing the backend and engine, and allocating qubits.
"""
backend = pq.backends.IBMBackend(num_runs=self.shots, **self.filter_kwargs_for_backend(self._kwargs))
self._eng = pq.MainEngine(backend, verbose=self._kwargs['verbose'], engine_list=pq.setups.ibm.get_engine_list())
token = self._kwargs.get("token", "")
hw = self._kwargs.get("use_hardware", False)
device = self._kwargs.get("device", "ibmq_qasm_simulator" if not hw else "ibmqx2")
self._eng = pq.MainEngine(backend, verbose=self._kwargs['verbose'], engine_list=pq.setups.ibm.get_engine_list(token=token, device=device))
super().reset()

def pre_measure(self):
Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
projectq
git+https://github.com/ProjectQ-Framework/ProjectQ.git#egg=projectq
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will always use the latest commit to master, no? What if there is a future long-lived commit in master that is broken? Would it be better to pick a particular release/commit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the ProjectQ IBM API fix was only committed 5 days ago. This change is so that we can work on this PR and verify we can get the plugin working with the IBM backend; we should re-evaluate the status of ProjectQ before merging this in.

But good call on pinning to a particular commit 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this is going to be released soon as v0.5.1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great!

pennylane>=0.6
pybind11
8 changes: 5 additions & 3 deletions tests/test_basis_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ def setUp(self):
self.devices.append(ProjectQSimulator(wires=self.num_subsystems, verbose=True))
if self.args.device == 'ibm' or self.args.device == 'all':
ibm_options = pennylane.default_config['projectq.ibm']
if "user" in ibm_options and "password" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024, user=ibm_options['user'], password=ibm_options['password'], verbose=True))
if "token" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024,
token=ibm_options['token'], verbose=True))
else:
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login credentials could not be found in the PennyLane configuration file.")
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login "
"credentials could not be found in the PennyLane configuration file.")
if self.args.device == 'classical' or self.args.device == 'all':
self.devices.append(ProjectQClassicalSimulator(wires=self.num_subsystems, verbose=True))

Expand Down
11 changes: 8 additions & 3 deletions tests/test_compare_with_default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ def setUp(self):
self.devices.append(ProjectQSimulator(wires=self.num_subsystems, shots=20000000, verbose=True))
if self.args.device == 'ibm' or self.args.device == 'all':
ibm_options = pennylane.default_config['projectq.ibm']
if "user" in ibm_options and "password" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024, user=ibm_options['user'], password=ibm_options['password'], verbose=True))
if "token" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024,
token=ibm_options['token'], verbose=True))
else:
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login credentials could not be found in the PennyLane configuration file.")
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login credentials "
"could not be found in the PennyLane configuration file.")
if self.args.device == 'classical' or self.args.device == 'all':
self.devices.append(ProjectQClassicalSimulator(wires=self.num_subsystems, verbose=True))

Expand All @@ -74,6 +76,9 @@ class IgnoreOperationException(Exception):

# run all single operation circuits
for operation in dev.operations:
if operation in ("DiagonalQubitUnitary"):
continue

for observable in dev.observables:
log.info("Running device "+dev.short_name+" with a circuit consisting of a "+operation+" Operation followed by a "+observable+" Expectation")

Expand Down
22 changes: 12 additions & 10 deletions tests/test_device_initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,36 @@
import pennylane_pq
import pennylane_pq.expval
from pennylane_pq.devices import ProjectQSimulator, ProjectQClassicalSimulator, ProjectQIBMBackend
import os

token = os.environ.get("IBMQX_TOKEN", "")

log.getLogger('defaults')



class DeviceInitialization(BaseTest):
"""test aspects of the device initialization.
"""

num_subsystems = 4
devices = None

def test_ibm_no_user(self):
def test_ibm_no_token(self):
if self.args.device == 'ibm' or self.args.device == 'all':
self.assertRaises(ValueError, ProjectQIBMBackend, wires=self.num_subsystems, use_hardware=False, password='password')

def test_ibm_no_password(self):
if self.args.device == 'ibm' or self.args.device == 'all':
self.assertRaises(ValueError, ProjectQIBMBackend, wires=self.num_subsystems, use_hardware=False, user='user')
self.assertRaises(ValueError, ProjectQIBMBackend, wires=self.num_subsystems, use_hardware=False)

def test_shots(self):
if self.args.device == 'ibm' or self.args.device == 'all':
shots = 5
dev1 = ProjectQIBMBackend(wires=self.num_subsystems, shots=shots, use_hardware=False, user="user", password='password')
dev1 = ProjectQIBMBackend(wires=self.num_subsystems, shots=shots, use_hardware=False, token=token, verbose=True)
self.assertEqual(shots, dev1.shots)

dev2 = ProjectQIBMBackend(wires=self.num_subsystems, num_runs=shots, use_hardware=False, user="user", password='password')
dev2 = ProjectQIBMBackend(wires=self.num_subsystems, num_runs=shots, use_hardware=False, token=token)
self.assertEqual(shots, dev2.shots)

dev2 = ProjectQIBMBackend(wires=self.num_subsystems, shots=shots+2, num_runs=shots, use_hardware=False, user="user", password='password')
dev2 = ProjectQIBMBackend(wires=self.num_subsystems, shots=shots+2, num_runs=shots, use_hardware=False,
token=token)
self.assertEqual(shots, dev2.shots)

def test_initiatlization_via_pennylane(self):
Expand All @@ -65,10 +66,11 @@ def test_initiatlization_via_pennylane(self):
'projectq.ibm'
]:
try:
dev = dev = qml.device(short_name, wires=2, user='user', password='password', verbose=True)
dev = qml.device(short_name, wires=2, token=token, verbose=True)
except DeviceError:
raise Exception("This test is expected to fail until pennylane-pq is installed.")


if __name__ == '__main__':
print('Testing PennyLane ProjectQ Plugin version ' + qml.version() + ', device initialization.')
# run the tests in this file
Expand Down
9 changes: 4 additions & 5 deletions tests/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
import pennylane_pq
import pennylane_pq.expval
from pennylane_pq.devices import ProjectQSimulator, ProjectQClassicalSimulator, ProjectQIBMBackend
import os

token = os.environ.get("IBMQX_TOKEN", "")
log.getLogger('defaults')

class DocumentationTest(BaseTest):
Expand All @@ -45,11 +47,8 @@ def setUp(self):
self.devices.append(ProjectQSimulator(wires=self.num_subsystems))
self.devices.append(ProjectQSimulator(wires=self.num_subsystems, shots=20000000))
if self.args.device == 'ibm' or self.args.device == 'all':
ibm_options = pennylane.default_config['projectq.ibm']
if "user" in ibm_options and "password" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024, user=ibm_options['user'], password=ibm_options['password']))
else:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024, user='user', password='password'))
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8 * 1024,
token=token, verbose=True))
if self.args.device == 'classical' or self.args.device == 'all':
self.devices.append(ProjectQClassicalSimulator(wires=self.num_subsystems))

Expand Down
8 changes: 5 additions & 3 deletions tests/test_ibm_expval_and_pre_expval_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import pennylane_pq.expval
from pennylane_pq.devices import ProjectQSimulator, ProjectQClassicalSimulator, ProjectQIBMBackend
from unittest.mock import patch, MagicMock, PropertyMock, call
import os

token = os.environ.get("IBMQX_TOKEN", "")
log.getLogger('defaults')

class ExpvalAndPreExpvalMock(BaseTest):
Expand All @@ -51,7 +53,7 @@ def test_pre_measure(self):
mock_PauliY,
mock_Hadamard,
]
dev = ProjectQIBMBackend(wires=2, use_hardware=False, num_runs=8*1024, user='user', password='password', verbose=True)
dev = ProjectQIBMBackend(wires=2, use_hardware=False, num_runs=8*1024, token=token, verbose=True)
dev._eng = MagicMock()
dev.apply = MagicMock()

Expand All @@ -77,7 +79,7 @@ def test_pre_measure(self):

def test_expval(self):

dev = ProjectQIBMBackend(wires=2, use_hardware=False, num_runs=8*1024, user='user', password='password', verbose=True)
dev = ProjectQIBMBackend(wires=2, use_hardware=False, num_runs=8*1024, token=token, verbose=True)
dev._eng = MagicMock()
dev._eng.backend = MagicMock()
dev._eng.backend.get_probabilities = MagicMock()
Expand All @@ -95,7 +97,7 @@ class Expval(BaseTest):
def test_expval_exception_if_no_obs_queue(self):

if self.args.device == 'ibm' or self.args.device == 'all':
dev = ProjectQIBMBackend(wires=2, shots=1, use_hardware=False, user='user', password='password', verbose=True)
dev = ProjectQIBMBackend(wires=2, shots=1, use_hardware=False, token=token, verbose=True)
else:
return

Expand Down
8 changes: 5 additions & 3 deletions tests/test_unsupported_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ def setUp(self):
self.devices.append(ProjectQSimulator(wires=self.num_subsystems, verbose=True))
if self.args.device == 'ibm' or self.args.device == 'all':
ibm_options = pennylane.default_config['projectq.ibm']
if "user" in ibm_options and "password" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8*1024, user=ibm_options['user'], password=ibm_options['password'], verbose=True))
if "token" in ibm_options:
self.devices.append(ProjectQIBMBackend(wires=self.num_subsystems, use_hardware=False, num_runs=8 * 1024,
token=ibm_options['token'], verbose=True))
else:
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login credentials could not be found in the PennyLane configuration file.")
log.warning("Skipping test of the ProjectQIBMBackend device because IBM login credentials "
"could not be found in the PennyLane configuration file.")
if self.args.device == 'classical' or self.args.device == 'all':
self.devices.append(ProjectQClassicalSimulator(wires=self.num_subsystems, verbose=True))

Expand Down
6 changes: 4 additions & 2 deletions tests/test_var.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

from defaults import TOLERANCE
from pennylane_pq.devices import ProjectQSimulator, ProjectQClassicalSimulator, ProjectQIBMBackend
import os

token = os.environ.get("IBMQX_TOKEN", "")


@pytest.fixture
Expand All @@ -45,8 +48,7 @@ def dev(DevClass, monkeypatch):
wires=1,
use_hardware=False,
num_runs=8 * 1024,
user="user",
password="password",
token=token,
verbose=True,
)

Expand Down