From 5424085422a62473b8d522384254a4315c4e1a27 Mon Sep 17 00:00:00 2001 From: antalszava Date: Fri, 6 Nov 2020 16:32:18 -0500 Subject: [PATCH 1/8] Don't reset the noise model --- pennylane_qiskit/qiskit_device.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pennylane_qiskit/qiskit_device.py b/pennylane_qiskit/qiskit_device.py index 74dbc8abf..345fecf8c 100644 --- a/pennylane_qiskit/qiskit_device.py +++ b/pennylane_qiskit/qiskit_device.py @@ -206,7 +206,6 @@ def reset(self): 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", []) From 731d43e8cd0a51dff27cf50b04119ddec52b3ca3 Mon Sep 17 00:00:00 2001 From: antalszava Date: Fri, 6 Nov 2020 16:58:59 -0500 Subject: [PATCH 2/8] Test bitflip --- tests/test_integration.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_integration.py b/tests/test_integration.py index f701af063..189f47123 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -4,6 +4,7 @@ import pennylane as qml import pytest import qiskit +import qiskit.providers.aer.noise as noise from pennylane_qiskit import AerDevice, BasicAerDevice @@ -332,3 +333,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""" + dev = qml.device('qiskit.aer', wires=2, noise_model=noise_model) + + 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"]) + + @qml.qnode(dev) + def circuit(): + qml.RX(0, wires=[0]) + return qml.expval(qml.PauliZ(wires=0)) + + assert circuit() == -1 From 80b6ffa2ad932062527f754e7cb335ec7a113840 Mon Sep 17 00:00:00 2001 From: antalszava Date: Fri, 6 Nov 2020 17:06:44 -0500 Subject: [PATCH 3/8] Correct test --- tests/test_integration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index 189f47123..641c74760 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -339,14 +339,14 @@ class TestNoise: def test_noise_applied(self): """Test that the qiskit noise model is applied correctly""" - dev = qml.device('qiskit.aer', wires=2, noise_model=noise_model) - 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) + @qml.qnode(dev) def circuit(): qml.RX(0, wires=[0]) From 27b2a977a15b1aafe6ee0b8521fd73ad3ab0f123 Mon Sep 17 00:00:00 2001 From: antalszava Date: Mon, 9 Nov 2020 11:07:30 -0500 Subject: [PATCH 4/8] Remove dev.noise_model; add test --- pennylane_qiskit/qiskit_device.py | 18 +++++++++++------- tests/test_integration.py | 16 ++++++++++------ tests/test_qiskit_device.py | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/pennylane_qiskit/qiskit_device.py b/pennylane_qiskit/qiskit_device.py index c091b586d..2a067d4df 100644 --- a/pennylane_qiskit/qiskit_device.py +++ b/pennylane_qiskit/qiskit_device.py @@ -170,17 +170,23 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs): # Initialize inner state self.reset() + aer_provider = str(provider) == "AerProvider" + + # Clear Aer backend options that may have persisted on a 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)) - 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) @@ -210,6 +216,8 @@ 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") @@ -324,10 +332,6 @@ 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() diff --git a/tests/test_integration.py b/tests/test_integration.py index 641c74760..b021ebcde 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -4,7 +4,7 @@ import pennylane as qml import pytest import qiskit -import qiskit.providers.aer.noise as noise +import qiskit.providers.aer as aer from pennylane_qiskit import AerDevice, BasicAerDevice @@ -128,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 a: cache.append(a)) + dev = qml.device("qiskit.aer", wires=2, noise_model="test value") + assert cache[0] == "test value" def test_invalid_noise_model(self): """Test that the noise model argument causes an exception to be raised @@ -339,8 +343,8 @@ class TestNoise: def test_noise_applied(self): """Test that the qiskit noise model is applied correctly""" - noise_model = noise.NoiseModel() - bit_flip = noise.pauli_error([('X', 1), ('I', 0)]) + 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"]) diff --git a/tests/test_qiskit_device.py b/tests/test_qiskit_device.py index d1822f5d1..51fb48898 100644 --- a/tests/test_qiskit_device.py +++ b/tests/test_qiskit_device.py @@ -3,6 +3,7 @@ import pennylane as qml from pennylane_qiskit import AerDevice +import qiskit.providers.aer.noise as noise test_transpile_options = [ {}, @@ -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 From 4beb4c384917011a228458c94ec185a234c80a3f Mon Sep 17 00:00:00 2001 From: antalszava Date: Mon, 9 Nov 2020 11:15:40 -0500 Subject: [PATCH 5/8] Noise model dictionary --- tests/test_integration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_integration.py b/tests/test_integration.py index b021ebcde..be3cddc01 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -134,9 +134,9 @@ def test_noise_model_qasm_simulator(self, monkeypatch): cache = [] with monkeypatch.context() as m: - m.setattr(aer.QasmSimulator, set_options, lambda a: cache.append(a)) + 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] == "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 From 0ba5159e15f8405f36b7df422bf03b6e8be364c3 Mon Sep 17 00:00:00 2001 From: antalszava Date: Mon, 9 Nov 2020 12:34:28 -0500 Subject: [PATCH 6/8] Organize processing kwargs into new method (Codefactor complexity); remove unnecessary backend def --- pennylane_qiskit/qiskit_device.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pennylane_qiskit/qiskit_device.py b/pennylane_qiskit/qiskit_device.py index 2a067d4df..773e36e58 100644 --- a/pennylane_qiskit/qiskit_device.py +++ b/pennylane_qiskit/qiskit_device.py @@ -170,9 +170,12 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs): # Initialize inner state self.reset() - aer_provider = str(provider) == "AerProvider" + self.process_kwargs(kwargs) - # Clear Aer backend options that may have persisted on a previous + def process_kwargs(self, kwargs): + 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() @@ -182,8 +185,8 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs): self.compile_backend = kwargs.pop("compile_backend") 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)) noise_model = kwargs.pop("noise_model") self.backend.set_options(noise_model=noise_model) @@ -192,7 +195,7 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs): 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: @@ -330,8 +333,6 @@ def compile(self): def run(self, qobj): """Run the compiled circuit, and query the result.""" - backend = self.backend - self._current_job = self.backend.run(qobj, **self.run_args) result = self._current_job.result() From b87f892f007b6bd53d553c2e6c436a5ef3a56c7d Mon Sep 17 00:00:00 2001 From: antalszava Date: Mon, 9 Nov 2020 12:41:21 -0500 Subject: [PATCH 7/8] Docstring --- pennylane_qiskit/qiskit_device.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pennylane_qiskit/qiskit_device.py b/pennylane_qiskit/qiskit_device.py index 773e36e58..143e0da00 100644 --- a/pennylane_qiskit/qiskit_device.py +++ b/pennylane_qiskit/qiskit_device.py @@ -173,6 +173,11 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs): 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 From 4d7899ae7df9e63268035988532049f2dac3745a Mon Sep 17 00:00:00 2001 From: antalszava Date: Mon, 9 Nov 2020 12:41:34 -0500 Subject: [PATCH 8/8] Formatting --- pennylane_qiskit/qiskit_device.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pennylane_qiskit/qiskit_device.py b/pennylane_qiskit/qiskit_device.py index 143e0da00..c21f93062 100644 --- a/pennylane_qiskit/qiskit_device.py +++ b/pennylane_qiskit/qiskit_device.py @@ -191,7 +191,9 @@ def process_kwargs(self, kwargs): if "noise_model" in kwargs: if not aer_provider or self.backend_name != "qasm_simulator": - raise ValueError("Backend {} does not support noisy simulations".format(self.backend_name)) + raise ValueError( + "Backend {} does not support noisy simulations".format(self.backend_name) + ) noise_model = kwargs.pop("noise_model") self.backend.set_options(noise_model=noise_model)