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

Fixes a bug where backend_options would be passed to backends that don't support it. #51

Merged
merged 4 commits into from Sep 14, 2019
Merged
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
16 changes: 7 additions & 9 deletions CHANGELOG.md
@@ -1,19 +1,17 @@
# Release 0.6.0-dev

### New features since last release

### Breaking changes

### Improvements

### Documentation
# Release 0.5.1

### Bug fixes

* Fixed a bug where backend keyword arguments, such as `backend_options`
and `noise_model`, were being passed to backends that did not support it.
[#51](https://github.com/XanaduAI/pennylane-qiskit/pull/51)

### Contributors

This release contains contributions from (in alphabetical order):

Josh Izaac

---

# Release 0.5.0
Expand Down
2 changes: 1 addition & 1 deletion pennylane_qiskit/_version.py
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.6.0-dev"
__version__ = "0.5.1"
17 changes: 3 additions & 14 deletions pennylane_qiskit/aer.py
Expand Up @@ -54,30 +54,19 @@ class AerDevice(QiskitDevice):
Args:
wires (int): The number of qubits of the device
backend (str): the desired backend
noise_model (NoiseModel): NoiseModel Object from ``qiskit.providers.aer.noise``
shots (int): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables

Keyword Args:
name (str): The name of the circuit. Default ``'circuit'``.
compile_backend (BaseBackend): The backend used for compilation. If you wish
to simulate a device compliant circuit, you can specify a backend here.
noise_model (NoiseModel): NoiseModel Object from ``qiskit.providers.aer.noise``
"""

# pylint: disable=too-many-arguments

short_name = "qiskit.aer"

def __init__(self, wires, shots=1024, backend="qasm_simulator", noise_model=None, **kwargs):
super().__init__(wires, qiskit.Aer, backend=backend, shots=shots, **kwargs)
self._noise_model = noise_model

def run(self, qobj):
Copy link
Member

Choose a reason for hiding this comment

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

how come this was removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

I noticed that this was part of the same bug. There were no tests for noise models, so it wasn't picked up. Since the logic for kwargs is now part of the base class, this method is redundant and can be removed.

"""Run the compiled circuit, and query the result."""
self._current_job = self.backend.run(
qobj, noise_model=self._noise_model, backend_options=self.kwargs
)
result = self._current_job.result()

if self.backend_name in self._state_backends:
self._state = self._get_state(result)
def __init__(self, wires, shots=1024, backend="qasm_simulator", **kwargs):
super().__init__(wires, provider=qiskit.Aer, backend=backend, shots=shots, **kwargs)
2 changes: 2 additions & 0 deletions pennylane_qiskit/ibmq.py
Expand Up @@ -65,6 +65,8 @@ class IBMQDevice(QiskitDevice):
variable ``IBMQX_TOKEN`` is used.
ibmqx_url (str): The IBM Q URL. If not provided, the environment
variable ``IBMQX_URL`` is used, followed by the default URL.
noise_model (NoiseModel): NoiseModel Object from ``qiskit.providers.aer.noise``.
Only applicable for simulator backends.
"""

short_name = "qiskit.ibmq"
Expand Down
24 changes: 20 additions & 4 deletions pennylane_qiskit/qiskit_device.py
Expand Up @@ -32,6 +32,7 @@
import abc
from collections import OrderedDict
import functools
import inspect
import itertools

import numpy as np
Expand Down Expand Up @@ -138,9 +139,6 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):

self.provider = provider
self.backend_name = backend
self.compile_backend = kwargs.get("compile_backend")
self.kwargs = kwargs

self._capabilities["backend"] = [b.name() for b in self.provider.backends()]

# check that backend exists
Expand Down Expand Up @@ -173,6 +171,24 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):
# job execution options
self.memory = False # do not return samples, just counts

# determine if backend supports backend options and noise models,
# and properly put together backend run arguments
s = inspect.signature(b.run)
self.run_args = {}
self.compile_backend = None

if "compile_backend" in kwargs:
self.compile_backend = kwargs.pop("compile_backend")

if "noise_model" in kwargs:
if "noise_model" in s.parameters:
self.run_args["noise_model"] = kwargs.pop("noise_model")
else:
raise ValueError("Backend {} does not support noisy simulations".format(backend))

if "backend_options" in s.parameters:
self.run_args["backend_options"] = kwargs

self.reset()

@property
Expand Down Expand Up @@ -228,7 +244,7 @@ def compile(self):

def run(self, qobj):
"""Run the compiled circuit, and query the result."""
self._current_job = self.backend.run(qobj, backend_options=self.kwargs)
self._current_job = self.backend.run(qobj, **self.run_args)
result = self._current_job.result()

if self.backend_name in self._state_backends:
Expand Down
30 changes: 30 additions & 0 deletions tests/test_integration.py
Expand Up @@ -66,3 +66,33 @@ def circuit(x, y, z):
return qml.expval(qml.PauliZ(0))

assert np.allclose(circuit(a, b, c), np.cos(a) * np.sin(b), **tol)


class TestKeywordArguments:
"""Test keyword argument logic is correct"""

@pytest.mark.parametrize("d", pldevices)
def test_compile_backend(self, d):
"""Test that the compile backend argument is properly
extracted"""
dev = qml.device(d[0], wires=2, compile_backend="test value")
assert dev.compile_backend == "test value"

def test_noise_model(self):
"""Test that the noise model argument is properly
extracted if the backend supports it"""
dev = qml.device("qiskit.aer", wires=2, noise_model="test value")
assert dev.run_args["noise_model"] == "test value"

def test_invalid_noise_model(self):
"""Test that the noise model argument causes an exception to be raised
if the backend does not support it"""
with pytest.raises(ValueError, match="does not support noisy simulations"):
dev = qml.device("qiskit.basicaer", wires=2, noise_model="test value")

@pytest.mark.parametrize("d", pldevices)
def test_overflow_backend_options(self, d):
"""Test all overflow backend options are extracted"""
dev = qml.device(d[0], wires=2, k1="v1", k2="v2")
assert dev.run_args["backend_options"]["k1"] == "v1"
assert dev.run_args["backend_options"]["k2"] == "v2"