Skip to content

Commit

Permalink
Update plugin by removing analytic argument for device creation (#130)
Browse files Browse the repository at this point in the history
* Remove analytic argument from all methods and tests. Black all code.

* Remove analytic argument from workflow tests.

* Update requirements.txt

* sphinx action from Josh

* Apply suggestions from code review

Co-authored-by: antalszava <[email protected]>

* Update .github/workflows/docs.yml

* add UsageDetails directive

* Revert "Update .github/workflows/docs.yml"

This reverts commit e0d31de.

* Revert "sphinx action from Josh"

This reverts commit 92cb68e.

* Update requirements.txt

* Update requirements.txt

* Apply suggestions from code review

Co-authored-by: antalszava <[email protected]>

* Apply suggestions from code review

Co-authored-by: antalszava <[email protected]>

Co-authored-by: Olivia Di Matteo <[email protected]>
Co-authored-by: Josh Izaac <[email protected]>
Co-authored-by: antalszava <[email protected]>
  • Loading branch information
4 people authored Mar 28, 2021
1 parent 908eaec commit ef50766
Show file tree
Hide file tree
Showing 17 changed files with 517 additions and 427 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ jobs:
- name: Run tests
run: |
pl-device-test --device=qiskit.basicaer --tb=short --skip-ops --analytic=False --shots=20000 --device-kwargs backend=qasm_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --analytic=False --shots=20000 --device-kwargs backend=qasm_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --analytic=True --device-kwargs backend=statevector_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --analytic=True --device-kwargs backend=unitary_simulator
pl-device-test --device=qiskit.basicaer --tb=short --skip-ops --shots=20000 --device-kwargs backend=qasm_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --shots=20000 --device-kwargs backend=qasm_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --shots=None --device-kwargs backend=statevector_simulator
pl-device-test --device=qiskit.aer --tb=short --skip-ops --shots=None --device-kwargs backend=unitary_simulator
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
Expand Down
3 changes: 2 additions & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,9 @@
#autodoc_default_flags = ['members']
autosummary_generate = True

from directives import CustomDeviceGalleryItemDirective, CustomDemoGalleryItemDirective
from directives import UsageDetails, CustomDeviceGalleryItemDirective, CustomDemoGalleryItemDirective

def setup(app):
app.add_directive('devicegalleryitem', CustomDeviceGalleryItemDirective)
app.add_directive('demogalleryitem', CustomDemoGalleryItemDirective)
app.add_directive("usagedetails", UsageDetails)
36 changes: 36 additions & 0 deletions doc/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,42 @@

import os

USAGE_DETAILS_TEMPLATE = """
.. raw:: html
<a class="usage-details-header collapse-header" data-toggle="collapse" href="#usageDetails" aria-expanded="false" aria-controls="usageDetails">
<h2 style="font-size: 24px;">
<i class="fas fa-angle-down rotate" style="float: right;"></i> Usage Details
</h2>
</a>
<div class="collapse" id="usageDetails">
{content}
.. raw:: html
</div>
"""


class UsageDetails(Directive):
"""Create a collapsed Usage Details section in the documentation."""

# defines the parameter the directive expects
# directives.unchanged means you get the raw value from RST
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
has_content = True

def run(self):
rst = USAGE_DETAILS_TEMPLATE.format(content="\n".join(self.content))
string_list = StringList(rst.split('\n'))
node = nodes.section()
self.state.nested_parse(string_list, self.content_offset, node)
return [node]


GALLERY_TEMPLATE = """
.. raw:: html
Expand Down
8 changes: 3 additions & 5 deletions pennylane_qiskit/aer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,14 @@ class AerDevice(QiskitDevice):
or iterable that contains unique labels for the subsystems as numbers (i.e., ``[-1, 0, 2]``)
or strings (``['ancilla', 'q1', 'q2']``).
backend (str): the desired backend
shots (int): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables
shots (int or None): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables. For statevector backends,
setting to ``None`` results in computing statistics like expectation values and variances analytically.
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.
analytic (bool): For statevector backends, determines if the
expectation values and variances are to be computed analytically.
Default value is ``False``.
noise_model (NoiseModel): NoiseModel Object from ``qiskit.providers.aer.noise``
"""

Expand Down
8 changes: 3 additions & 5 deletions pennylane_qiskit/basic_aer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,14 @@ class BasicAerDevice(QiskitDevice):
or iterable that contains unique labels for the subsystems as numbers (i.e., ``[-1, 0, 2]``)
or strings (``['ancilla', 'q1', 'q2']``).
backend (str): the desired backend
shots (int): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables
shots (int or None): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables. For statevector backends,
setting to ``None`` results in computing statistics like expectation values and variances analytically.
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.
analytic (bool): For statevector backends, determines if the
expectation values and variances are to be computed analytically.
Default value is ``False``.
"""

short_name = "qiskit.basicaer"
Expand Down
20 changes: 7 additions & 13 deletions pennylane_qiskit/qiskit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,14 @@ class QiskitDevice(QubitDevice, abc.ABC):
or strings (``['ancilla', 'q1', 'q2']``).
provider (Provider): The Qiskit simulation provider
backend (str): the desired backend
shots (int): Number of circuit evaluations/random samples used
to estimate expectation values of observables.
shots (int or None): number of circuit evaluations/random samples used
to estimate expectation values and variances of observables. For statevector backends,
setting to ``None`` results in computing statistics like expectation values and variances analytically.
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.
analytic (bool): For statevector backends, determines if the
expectation values and variances are to be computed analytically.
Default value is ``False``.
"""
name = "Qiskit PennyLane plugin"
pennylane_requires = ">=0.12.0"
Expand Down Expand Up @@ -113,16 +111,12 @@ def __init__(self, wires, provider, backend, shots=1024, **kwargs):
super().__init__(wires=wires, shots=shots)

# Keep track if the user specified analytic to be True
user_specified_analytic = "analytic" in kwargs and kwargs["analytic"]
self.analytic = kwargs.pop("analytic", False)
if shots is None and backend not in self._state_backends:

if self.analytic and backend not in self._state_backends:
# Raise a warning if no shots were specified for a hardware device
warnings.warn(self.hw_analytic_warning_message.format(backend), UserWarning)

if user_specified_analytic:
# Raise a warning if the analytic attribute was set to True
warnings.warn(self.hw_analytic_warning_message.format(backend), UserWarning)

self.analytic = False
self.shots = 1024

self._backend = None

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
qiskit>=0.23.4
pennylane>=0.14.0
git+https://github.com/PennyLaneAI/pennylane.git
numpy
networkx>=2.2;python_version>'3.5'
networkx>=2.2,<2.4;python_version=='3.5'
25 changes: 14 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@


@pytest.fixture
def tol(analytic):
if analytic:
def tol(shots):
if shots is None:
return {"atol": 0.01, "rtol": 0}

return {"atol": 0.05, "rtol": 0.1}
Expand All @@ -42,16 +42,19 @@ def _init_state(n):

return _init_state


@pytest.fixture
def skip_unitary(backend):
if backend == "unitary_simulator":
pytest.skip("This test does not support the unitary simulator backend.")


@pytest.fixture
def run_only_for_unitary(backend):
if backend != "unitary_simulator":
pytest.skip("This test only supports the unitary simulator.")


@pytest.fixture(params=state_backends + hw_backends)
def backend(request):
return request.param
Expand All @@ -68,22 +71,22 @@ def hardware_backend(request):


@pytest.fixture(params=[AerDevice, BasicAerDevice])
def device(request, backend, shots, analytic):
if backend not in state_backends and analytic == True:
def device(request, backend, shots):
if backend not in state_backends and shots is None:
pytest.skip("Hardware simulators do not support analytic mode")

def _device(n, device_options=None):
if device_options is None:
device_options = {}
return request.param(wires=n, backend=backend, shots=shots, analytic=analytic, **device_options)
return request.param(wires=n, backend=backend, shots=shots, **device_options)

return _device


@pytest.fixture(params=[AerDevice, BasicAerDevice])
def state_vector_device(request, statevector_backend, shots, analytic):
def state_vector_device(request, statevector_backend, shots):
def _device(n):
return request.param(wires=n, backend=statevector_backend, shots=shots, analytic=analytic)
return request.param(wires=n, backend=statevector_backend, shots=shots)

return _device

Expand All @@ -94,20 +97,20 @@ def mock_device(monkeypatch):

with monkeypatch.context() as m:
dev = qml.Device
m.setattr(dev, '__abstractmethods__', frozenset())
m.setattr(dev, "__abstractmethods__", frozenset())
yield qml.Device()


@pytest.fixture(scope="function")
def recorder():
return qml._queuing.OperationRecorder()
return qml.tape.OperationRecorder()


@pytest.fixture(scope="function")
def qubit_device_single_wire():
return qml.device('default.qubit', wires=1)
return qml.device("default.qubit", wires=1)


@pytest.fixture(scope="function")
def qubit_device_2_wires():
return qml.device('default.qubit', wires=2)
return qml.device("default.qubit", wires=2)
29 changes: 12 additions & 17 deletions tests/test_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,18 @@
)


single_qubit_operations = [
qml.PauliX,
qml.PauliY,
qml.PauliZ,
qml.Hadamard,
qml.S,
qml.T
]
single_qubit_operations = [qml.PauliX, qml.PauliY, qml.PauliZ, qml.Hadamard, qml.S, qml.T]

single_qubit_operations_param = [qml.PhaseShift, qml.RX, qml.RY, qml.RZ]
two_qubit = [qml.CNOT, qml.SWAP, qml.CZ]
two_qubit_param = [qml.CRZ]
three_qubit = [qml.Toffoli, qml.CSWAP]

@pytest.mark.parametrize("analytic", [True])
@pytest.mark.parametrize("shots", [8192])

@pytest.mark.parametrize("shots", [None])
@pytest.mark.usefixtures("skip_unitary")
class TestAnalyticApply:
"""Test application of PennyLane operations with analytic attribute set to True."""
"""Test application of PennyLane operations with analytic calculation."""

def test_qubit_state_vector(self, init_state, device, tol):
"""Test that the QubitStateVector operation produces the expected
Expand Down Expand Up @@ -149,8 +142,8 @@ def test_three_qubit_operations_no_parameters(self, init_state, device, operatio
expected = np.abs(applied_operation.matrix @ state) ** 2
assert np.allclose(res, expected, **tol)

@pytest.mark.parametrize("analytic", [True])
@pytest.mark.parametrize("shots", [8192])

@pytest.mark.parametrize("shots", [None])
@pytest.mark.usefixtures("run_only_for_unitary")
class TestStateApplyUnitarySimulator:
"""Test application of PennyLane operations to the unitary simulator."""
Expand All @@ -161,14 +154,17 @@ def test_invalid_qubit(self, init_state, device):
dev = device(1)
state = init_state(1)

with pytest.raises(qml.DeviceError, match="The QubitStateVector operation is not supported on the unitary simulator backend"):
with pytest.raises(
qml.DeviceError,
match="The QubitStateVector operation is not supported on the unitary simulator backend",
):
dev.apply([qml.QubitStateVector(state, wires=[0])])


@pytest.mark.parametrize("shots", [8192])
@pytest.mark.parametrize("analytic", [False])
@pytest.mark.usefixtures("skip_unitary")
class TestNonAnalyticApply:
"""Test application of PennyLane operations with the analytic attribute set to False."""
"""Test application of PennyLane operations with non-analytic calculation."""

def test_qubit_state_vector(self, init_state, device, tol):
"""Test that the QubitStateVector operation produces the expected
Expand Down Expand Up @@ -302,4 +298,3 @@ def test_three_qubit_no_parameters(self, init_state, device, operation, tol):
res = np.fromiter(dev.probability(), dtype=np.float64)
expected = np.abs(applied_operation.matrix @ state) ** 2
assert np.allclose(res, expected, **tol)

Loading

0 comments on commit ef50766

Please sign in to comment.