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

No noise model reset #114

Merged
merged 10 commits into from
Nov 11, 2020
37 changes: 24 additions & 13 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,23 +170,39 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):
# Initialize inner state
self.reset()

self.process_kwargs(kwargs)

def process_kwargs(self, kwargs):
"""Processing the keyword arguments that were provided upon device creation.

Args:
kwargs (dict): keyword arguments to be set for the device
"""
aer_provider = str(self.provider) == "AerProvider"

# Clear Aer backend options that may have persisted since the previous
# device creation
if aer_provider:
self.backend.clear_options()

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

aer_provider = str(provider) == "AerProvider"
self.noise_model = None
if "noise_model" in kwargs:
if not aer_provider or backend != "qasm_simulator":
raise ValueError("Backend {} does not support noisy simulations".format(backend))
if not aer_provider or self.backend_name != "qasm_simulator":
raise ValueError(
"Backend {} does not support noisy simulations".format(self.backend_name)
)

self.noise_model = kwargs.pop("noise_model")
noise_model = kwargs.pop("noise_model")
self.backend.set_options(noise_model=noise_model)

# set transpile_args
self.set_transpile_args(**kwargs)

# Get further arguments for run
s = inspect.signature(b.run)
s = inspect.signature(self.backend.run)
self.run_args = {}

if aer_provider:
Expand All @@ -210,13 +226,14 @@ def backend(self):
return self.provider.get_backend(self.backend_name)

def reset(self):
# Reset only internal data, not the options that are determined on
# device creation
self._reg = QuantumRegister(self.num_wires, "q")
self._creg = ClassicalRegister(self.num_wires, "c")
self._circuit = QuantumCircuit(self._reg, self._creg, name="temp")

self._current_job = None
self._state = None # statevector of a simulator backend
self.noise_model = None

def apply(self, operations, **kwargs):
rotations = kwargs.get("rotations", [])
Expand Down Expand Up @@ -323,12 +340,6 @@ def compile(self):

def run(self, qobj):
"""Run the compiled circuit, and query the result."""
backend = self.backend

if self.noise_model:
# Set the noise model before execution
backend.set_options(noise_model=self.noise_model)

self._current_job = self.backend.run(qobj, **self.run_args)
result = self._current_job.result()

Expand Down
31 changes: 28 additions & 3 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pennylane as qml
import pytest
import qiskit
import qiskit.providers.aer as aer

from pennylane_qiskit import AerDevice, BasicAerDevice

Expand Down Expand Up @@ -127,11 +128,15 @@ def test_compile_backend(self, d):
dev = qml.device(d[0], wires=2, compile_backend="test value")
assert dev.compile_backend == "test value"

def test_noise_model(self):
def test_noise_model_qasm_simulator(self, monkeypatch):
"""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.noise_model == "test value"

cache = []
with monkeypatch.context() as m:
m.setattr(aer.QasmSimulator, "set_options", lambda *args, **kwargs: cache.append(kwargs))
dev = qml.device("qiskit.aer", wires=2, noise_model="test value")
assert cache[0] == {'noise_model': 'test value'}

def test_invalid_noise_model(self):
"""Test that the noise model argument causes an exception to be raised
Expand Down Expand Up @@ -332,3 +337,23 @@ def circuit_with_inverses_default_qubit(angle):

for x in angles:
assert np.allclose(circuit_with_inverses(x), circuit_with_inverses_default_qubit(x))

class TestNoise:
"""Integration test for the noise models."""

def test_noise_applied(self):
"""Test that the qiskit noise model is applied correctly"""
noise_model = aer.noise.NoiseModel()
bit_flip = aer.noise.pauli_error([('X', 1), ('I', 0)])

# Create a noise model where the RX operation always flips the bit
noise_model.add_all_qubit_quantum_error(bit_flip, ["rx"])

dev = qml.device('qiskit.aer', wires=2, noise_model=noise_model)

@qml.qnode(dev)
def circuit():
qml.RX(0, wires=[0])
return qml.expval(qml.PauliZ(wires=0))

assert circuit() == -1
Copy link
Member

Choose a reason for hiding this comment

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

nice test :)

19 changes: 19 additions & 0 deletions tests/test_qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import pennylane as qml
from pennylane_qiskit import AerDevice
import qiskit.providers.aer.noise as noise

test_transpile_options = [
{},
Expand Down Expand Up @@ -73,3 +74,21 @@ def test_no_warning_raised_for_software_backend_analytic_expval(self, statevecto

# check that no warnings were raised
assert len(recwarn) == 0

class TestAerBackendOptions:
"""Test the backend options of Aer backends."""

def test_backend_options_cleaned(self):
"""Test that the backend options are cleared upon new Aer device
initialization."""
noise_model = noise.NoiseModel()
bit_flip = noise.pauli_error([('X', 1), ('I', 0)])

# Create a noise model where the RX operation always flips the bit
noise_model.add_all_qubit_quantum_error(bit_flip, ["rx"])

dev = qml.device('qiskit.aer', wires=2, noise_model=noise_model)
assert 'noise_model' in dev.backend.options

dev2 = qml.device('qiskit.aer', wires=2)
assert 'noise_model' not in dev2.backend.options