-
Notifications
You must be signed in to change notification settings - Fork 66
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
Analytic true hw simulator warning #59
Changes from all commits
0f6c944
8222998
1223960
77c9961
f64b89b
852485a
27008ab
53b623f
5ebc929
7bb7641
828a615
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,26 +29,26 @@ | |
~~~~~~~~~~~~ | ||
""" | ||
# pylint: disable=too-many-instance-attributes | ||
|
||
import abc | ||
from collections import OrderedDict | ||
import functools | ||
import inspect | ||
import itertools | ||
import warnings | ||
from collections import OrderedDict | ||
|
||
import numpy as np | ||
|
||
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister | ||
from qiskit import extensions as ex | ||
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit | ||
|
||
from qiskit.compiler import transpile, assemble | ||
from qiskit.circuit.measure import measure | ||
from qiskit.converters import dag_to_circuit, circuit_to_dag | ||
from qiskit.compiler import assemble, transpile | ||
from qiskit.converters import circuit_to_dag, dag_to_circuit | ||
|
||
from pennylane import Device, DeviceError | ||
from pennylane.operation import Sample | ||
|
||
from .gates import BasisState, Rot | ||
from ._version import __version__ | ||
from .gates import BasisState, Rot | ||
|
||
|
||
@functools.lru_cache() | ||
|
@@ -134,6 +134,10 @@ class QiskitDevice(Device, abc.ABC): | |
operations = set(_operation_map.keys()) | ||
observables = {"PauliX", "PauliY", "PauliZ", "Identity", "Hadamard", "Hermitian"} | ||
|
||
hw_analytic_warning_message = "The analytic calculation of expectations and variances "\ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created separate warning message for |
||
"is only supported on statevector backends, not on the {}. "\ | ||
"The obtained result is based on sampling." | ||
|
||
_eigs = {} | ||
|
||
def __init__(self, wires, provider, backend, shots=1024, **kwargs): | ||
|
@@ -349,6 +353,12 @@ def expval(self, observable, wires, par): | |
prob = np.fromiter(self.probabilities(wires=wires).values(), dtype=np.float64) | ||
return (eigvals @ prob).real | ||
|
||
if self.analytic: | ||
# Raise a warning if backend is a hardware simulator | ||
warnings.warn(self.hw_analytic_warning_message. | ||
format(self.backend), | ||
UserWarning) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we move the warning to
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I first went for it to be in the |
||
|
||
# estimate the ev | ||
return np.mean(self.sample(observable, wires, par)) | ||
|
||
|
@@ -359,6 +369,12 @@ def var(self, observable, wires, par): | |
prob = np.fromiter(self.probabilities(wires=wires).values(), dtype=np.float64) | ||
return (eigvals ** 2) @ prob - (eigvals @ prob).real ** 2 | ||
|
||
if self.analytic: | ||
# Raise a warning if backend is a hardware simulator | ||
warnings.warn(self.hw_analytic_warning_message. | ||
format(self.backend), | ||
UserWarning) | ||
|
||
return np.var(self.sample(observable, wires, par)) | ||
|
||
def sample(self, observable, wires, par): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,116 @@ | ||
import pytest | ||
|
||
import numpy as np | ||
|
||
from pennylane_qiskit.qiskit_device import pauli_eigs | ||
from pennylane_qiskit import AerDevice | ||
|
||
|
||
Z = np.diag([1, -1]) | ||
|
||
|
||
class TestZEigs: | ||
r"""Test that eigenvalues of Z^{\otimes n} are correctly generated""" | ||
|
||
def test_one(self): | ||
"""Test that eigs(Z) = [1, -1]""" | ||
assert np.all(pauli_eigs(1) == np.array([1, -1])) | ||
|
||
@pytest.mark.parametrize("n", [2, 3, 6]) | ||
def test_multiple(self, n): | ||
r"""Test that eigs(Z^{\otimes n}) is correct""" | ||
res = pauli_eigs(n) | ||
Zn = np.kron(Z, Z) | ||
|
||
for _ in range(n - 2): | ||
Zn = np.kron(Zn, Z) | ||
|
||
expected = np.diag(Zn) | ||
assert np.all(res == expected) | ||
|
||
|
||
class TestProbabilities: | ||
"""Tests for the probability function""" | ||
|
||
def test_probability_no_results(self): | ||
"""Test that the probabilities function returns | ||
None if no job has yet been run.""" | ||
dev = AerDevice(backend="statevector_simulator", wires=1, analytic=True) | ||
assert dev.probabilities() is None | ||
import numpy as np | ||
import pytest | ||
|
||
import pennylane as qml | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this go below the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ran import numpy as np
import pytest
import pennylane as qml
from pennylane_qiskit import AerDevice
from pennylane_qiskit.qiskit_device import pauli_eigs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
from pennylane_qiskit import AerDevice | ||
from pennylane_qiskit.qiskit_device import pauli_eigs | ||
|
||
Z = np.diag([1, -1]) | ||
|
||
|
||
class TestZEigs: | ||
r"""Test that eigenvalues of Z^{\otimes n} are correctly generated""" | ||
|
||
def test_one(self): | ||
"""Test that eigs(Z) = [1, -1]""" | ||
assert np.all(pauli_eigs(1) == np.array([1, -1])) | ||
|
||
@pytest.mark.parametrize("n", [2, 3, 6]) | ||
def test_multiple(self, n): | ||
r"""Test that eigs(Z^{\otimes n}) is correct""" | ||
res = pauli_eigs(n) | ||
Zn = np.kron(Z, Z) | ||
|
||
for _ in range(n - 2): | ||
Zn = np.kron(Zn, Z) | ||
|
||
expected = np.diag(Zn) | ||
assert np.all(res == expected) | ||
|
||
|
||
class TestProbabilities: | ||
"""Tests for the probability function""" | ||
|
||
def test_probability_no_results(self): | ||
"""Test that the probabilities function returns | ||
None if no job has yet been run.""" | ||
dev = AerDevice(backend="statevector_simulator", wires=1, analytic=True) | ||
assert dev.probabilities() is None | ||
|
||
|
||
class TestAnalyticWarningHWSimulator: | ||
"""Tests the warnings for when the analytic attribute of a device is set to true""" | ||
|
||
def test_warning_raised_for_hardware_backend_analytic_expval(self, hardware_backend, recorder): | ||
"""Tests that a warning is raised if the analytic attribute is true on | ||
hardware simulators when calculating the expectation""" | ||
|
||
dev = qml.device("qiskit.basicaer", backend=hardware_backend, wires=2) | ||
|
||
@qml.qnode(dev) | ||
def circuit(): | ||
qml.Hadamard(wires=0) | ||
return qml.expval(qml.PauliZ(0)) | ||
|
||
with pytest.warns(UserWarning) as record: | ||
circuit() | ||
|
||
# check that only one warning was raised | ||
assert len(record) == 1 | ||
# check that the message matches | ||
assert record[0].message.args[0] == "The analytic calculation of expectations and variances "\ | ||
"is only supported on statevector backends, not on the {}. "\ | ||
"The obtained result is based on sampling.".format(dev.backend) | ||
|
||
def test_no_warning_raised_for_software_backend_analytic_expval(self, statevector_backend, recorder, recwarn): | ||
"""Tests that no warning is raised if the analytic attribute is true on | ||
statevector simulators when calculating the expectation""" | ||
|
||
dev = qml.device("qiskit.basicaer", backend=statevector_backend, wires=2) | ||
|
||
@qml.qnode(dev) | ||
def circuit(): | ||
qml.Hadamard(wires=0) | ||
return qml.expval(qml.PauliZ(0)) | ||
|
||
circuit() | ||
|
||
# check that no warnings were raised | ||
assert len(recwarn) == 0 | ||
|
||
def test_warning_raised_for_hardware_backend_analytic_var(self, hardware_backend, recorder): | ||
"""Tests that a warning is raised if the analytic attribute is true on | ||
hardware simulators when calculating the variance""" | ||
|
||
dev = qml.device("qiskit.basicaer", backend=hardware_backend, wires=2) | ||
|
||
@qml.qnode(dev) | ||
def circuit(): | ||
qml.Hadamard(wires=0) | ||
return qml.var(qml.PauliZ(0)) | ||
|
||
with pytest.warns(UserWarning) as record: | ||
circuit() | ||
|
||
# check that only one warning was raised | ||
assert len(record) == 1 | ||
# check that the message matches | ||
assert record[0].message.args[0] == "The analytic calculation of expectations and variances "\ | ||
"is only supported on statevector backends, not on the {}. "\ | ||
"The obtained result is based on sampling.".format(dev.backend) | ||
|
||
def test_no_warning_raised_for_software_backend_analytic_var(self, statevector_backend, recorder, recwarn): | ||
"""Tests that no warning is raised if the analytic attribute is true on | ||
statevector simulators when calculating the variance""" | ||
|
||
dev = qml.device("qiskit.basicaer", backend=statevector_backend, wires=2) | ||
|
||
@qml.qnode(dev) | ||
def circuit(): | ||
qml.Hadamard(wires=0) | ||
return qml.var(qml.PauliZ(0)) | ||
|
||
circuit() | ||
|
||
# check that no warnings were raised | ||
assert len(recwarn) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 glad the ordering here has been fixed