Skip to content

Commit

Permalink
Compatibility with the new return system (#281)
Browse files Browse the repository at this point in the history
* Add new return

* Fix

* Coverage

* review

* Bump to master
  • Loading branch information
rmoyard authored Apr 10, 2023
1 parent 5d67f6e commit 9f74678
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 27 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Breaking changes

* The new return system from Pennylande is adopted in the plugin as well.
[(#281)](https://github.com/PennyLaneAI/pennylane-qiskit/pull/281)

### Improvements

### Documentation
Expand All @@ -14,6 +17,8 @@

This release contains contributions from (in alphabetical order):

Romain Moyard.

---
# Release 0.29.0

Expand Down
13 changes: 10 additions & 3 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import warnings

import numpy as np
import pennylane
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit import extensions as ex
from qiskit.compiler import transpile
Expand Down Expand Up @@ -479,9 +480,15 @@ def batch_execute(self, circuits):
if self.shots is not None or circuit.is_sampled:
self._samples = self.generate_samples(circuit_obj)

res = self.statistics(circuit)
res = np.asarray(res)
results.append(res)
if not pennylane.active_return():
res = self._statistics_legacy(circuit)
res = np.asarray(res)
results.append(res)
else:
res = self.statistics(circuit)
single_measurement = len(circuit.measurements) == 1
res = res[0] if single_measurement else tuple(res)
results.append(res)

if self.tracker.active:
self.tracker.update(batches=1, batch_len=len(circuits))
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ntlm-auth==1.5.0
numpy==1.22.3
orjson==3.6.8
pbr==5.8.1
PennyLane==0.27.0
git+https://github.com/PennyLaneAI/pennylane.git@master
PennyLane-Lightning==0.28.2
ply==3.11
psutil==5.9.4
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
requirements = [
"qiskit>=0.32",
"mthree>=0.17",
"pennylane>=0.28",
"pennylane @ git+https://github.com/PennyLaneAI/pennylane.git",
"numpy",
"networkx>=2.2",
]
Expand Down
25 changes: 9 additions & 16 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1115,21 +1115,14 @@ def circuit(a_val, b_val):

assert np.allclose(res, res_expected)

jac = qml.jacobian(circuit)(x, y)

# Note: with v0.21.0, the behaviour of qml.jacobian changed. Branch
# based on the version number to ensure that the test case passes even
# with <v0.21.
if qml.__version__ < "0.21.0":
jac_expected = [
[-np.sin(x + np.cos(y)), np.sin(x + np.cos(y)) * np.sin(y)],
[np.cos(x * y) * y, np.cos(x * y) * x],
]

else:
jac_expected = [
[-np.sin(x + np.cos(y)), np.cos(x * y) * y],
[np.sin(x + np.cos(y)) * np.sin(y), np.cos(x * y) * x],
]
def cost(x, y):
return qml.math.stack(circuit(x, y))

jac = qml.jacobian(cost)(x, y)

jac_expected = [
[-np.sin(x + np.cos(y)), np.cos(x * y) * y],
[np.sin(x + np.cos(y)) * np.sin(y), np.cos(x * y) * x],
]

assert np.allclose(jac, jac_expected)
39 changes: 33 additions & 6 deletions tests/test_qiskit_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pennylane
import pytest

import pennylane as qml
Expand Down Expand Up @@ -62,14 +63,14 @@ def test_warning_raised_for_hardware_backend_analytic_expval(self, hardware_back
assert len(record) == 1
# check that the message matches
assert (
record[0].message.args[0] == "The analytic calculation of "
"expectations, variances and probabilities is only supported on "
"statevector backends, not on the {}. Such statistics obtained from this "
"device are estimates based on samples.".format(dev.backend)
record[0].message.args[0] == "The analytic calculation of "
"expectations, variances and probabilities is only supported on "
"statevector backends, not on the {}. Such statistics obtained from this "
"device are estimates based on samples.".format(dev.backend)
)

def test_no_warning_raised_for_software_backend_analytic_expval(
self, statevector_backend, recorder, recwarn
self, statevector_backend, recorder, recwarn
):
"""Tests that no warning is raised if the analytic attribute is true on
statevector simulators when calculating the expectation"""
Expand Down Expand Up @@ -140,8 +141,10 @@ def test_calls_to_reset(self, n_tapes, mocker, device):

assert spy.call_count == n_tapes

def test_result(self, device, tol):
def test_result_legacy(self, device, tol):
"""Tests that the result has the correct shape and entry types."""
# TODO: remove once the legacy return system is removed.
pennylane.disable_return()
dev = device(2)
tapes = [self.tape1, self.tape2]
res = dev.batch_execute(tapes)
Expand All @@ -161,6 +164,30 @@ def test_result(self, device, tol):
assert isinstance(res[1], np.ndarray)
assert np.allclose(res[1], tape2_expected, atol=0)

pennylane.enable_return()

def test_result(self, device, tol):
"""Tests that the result has the correct shape and entry types."""
dev = device(2)
tapes = [self.tape1, self.tape2]
res = dev.batch_execute(tapes)

# We're calling device methods directly, need to reset before the next
# execution
dev.reset()
tape1_expected = dev.execute(self.tape1)

dev.reset()
tape2_expected = dev.execute(self.tape2)

assert len(res) == 2
assert isinstance(res[0], tuple)
assert len(res[0]) == 2
assert np.allclose(qml.math.stack(res[0]), tape1_expected, atol=0)

assert isinstance(res[1], np.ndarray)
assert np.allclose(res[1], tape2_expected, atol=0)

def test_result_empty_tape(self, device, tol):
"""Tests that the result has the correct shape and entry types for
empty tapes."""
Expand Down

0 comments on commit 9f74678

Please sign in to comment.