From d6673d5144c4d2d3669fba0021967b7919e810aa Mon Sep 17 00:00:00 2001 From: Viraj Chaudhari <72896239+virajvchaudhari@users.noreply.github.com> Date: Wed, 7 Dec 2022 11:11:18 -0800 Subject: [PATCH 01/34] feature: adjoint gradient (#116) Co-authored-by: Jacob Feldman Co-authored-by: Katharine Hyatt Co-authored-by: Aaron Berdy Co-authored-by: Cody Wang --- .github/workflows/python-package.yml | 7 +- doc/devices/braket_remote.rst | 10 + example.py | 20 +- setup.cfg | 9 +- setup.py | 2 +- src/braket/pennylane_plugin/braket_device.py | 170 +++++- src/braket/pennylane_plugin/translation.py | 85 ++- test/integ_tests/conftest.py | 12 + test/integ_tests/test_adjoint_gradient.py | 139 +++++ test/integ_tests/test_batch.py | 12 +- test/integ_tests/test_expval.py | 4 +- test/unit_tests/test_braket_device.py | 543 ++++++++++++++++++- test/unit_tests/test_translation.py | 180 +++++- tox.ini | 2 - 14 files changed, 1139 insertions(+), 56 deletions(-) create mode 100644 test/integ_tests/test_adjoint_gradient.py diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index ed3ebdcb..8bf9d0c4 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -5,9 +5,12 @@ name: Python package on: push: - branches: [ main ] + branches: + - main pull_request: - branches: [ main ] + branches: + - main + - feature/** jobs: build: diff --git a/doc/devices/braket_remote.rst b/doc/devices/braket_remote.rst index 49226695..0d3e53b6 100644 --- a/doc/devices/braket_remote.rst +++ b/doc/devices/braket_remote.rst @@ -102,3 +102,13 @@ from :mod:`braket.pennylane_plugin.ops <.ops>`: braket.pennylane_plugin.BitFlip braket.pennylane_plugin.PhaseFlip braket.pennylane_plugin.QubitChannel + + +Gradient computation on Braket with a QAOA Hamiltonian +~~~~~~~~~~~~~~~~~~~~ +Currently, PennyLane will compute grouping indices for QAOA Hamiltonians and use them to split the Hamiltonian into multiple expectation values. If you wish to use `SV1’s adjoint differentiation capability` when running QAOA from PennyLane, you will need reconstruct the cost Hamiltonian to remove the grouping indices from the cost Hamiltonian, like so: + +.. code-block:: python + + cost_h, mixer_h = qml.qaoa.max_clique(g, constrained=False) + cost_h = qml.Hamiltonian(cost_h.coeffs, cost_h.ops) diff --git a/example.py b/example.py index 9ba03d04..03144da7 100644 --- a/example.py +++ b/example.py @@ -12,10 +12,17 @@ # language governing permissions and limitations under the License. import pennylane as qml +from pennylane import numpy as np s3 = ("my-bucket", "my-prefix") dev_sim = qml.device("braket.simulator", s3_destination_folder=s3, wires=2) +dev_managed_sim = qml.device( + "braket.aws.qubit", + device_arn="arn:aws:braket:::device/quantum-simulator/amazon/sv1", + wires=3, + shots=0, +) dev_qpu = qml.device( "braket.rigetti", s3_destination_folder=s3, poll_timeout_seconds=1800, shots=10000, wires=2 ) @@ -40,4 +47,15 @@ def circuit(a): return qml.expval(qml.PauliZ(1)) -print(circuit(0.543)) +@qml.qnode(dev_managed_sim) +def circuit(a): + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(a, wires=1) + return qml.expval(qml.PauliZ(1)) + + +x = np.array(0.543, requires_grad=False) +print(circuit(x)) +print(qml.grad(circuit)(x)) +print(qml.jacobian(circuit)(x)) diff --git a/setup.cfg b/setup.cfg index 79ada15d..98c6a2bf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,9 +14,12 @@ include_trailing_comma = true [flake8] ignore = - E203, # not pep8, black adds whitespace before ':' - E231, # not pep8, https://www.python.org/dev/peps/pep-0008/#pet-peeves - W503, # not pep8, black adds line break before binary operator + # not pep8, black adds whitespace before ':' + E203, + # not pep8, https://www.python.org/dev/peps/pep-0008/#pet-peeves + E231, + # not pep8, black adds line break before binary operator + W503, max_line_length = 100 max-complexity = 10 exclude = diff --git a/setup.py b/setup.py index d147fb69..cd7f94a8 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ packages=find_namespace_packages(where="src", exclude=("test",)), package_dir={"": "src"}, install_requires=[ - "amazon-braket-sdk>=1.30.0", + "amazon-braket-sdk>=1.35.0", "pennylane>=0.25.1", ], entry_points={ diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index 02379b1a..60dbf4f1 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -32,6 +32,9 @@ ~~~~~~~~~~~~ """ +import collections +import numbers + # pylint: disable=invalid-name from enum import Enum, auto from typing import FrozenSet, Iterable, List, Optional, Sequence, Union @@ -46,8 +49,10 @@ from pennylane import numpy as np from pennylane.measurements import Expectation, Probability, Sample, State, Variance from pennylane.operation import Observable, Operation +from pennylane.ops.qubit.hamiltonian import Hamiltonian from braket.pennylane_plugin.translation import ( + get_adjoint_gradient_result_type, supported_operations, translate_operation, translate_result, @@ -134,21 +139,70 @@ def task(self) -> QuantumTask: """QuantumTask: The task corresponding to the last run circuit.""" return self._task - def _pl_to_braket_circuit(self, circuit, **run_kwargs): + def _pl_to_braket_circuit(self, circuit: CircuitGraph, compute_gradient=False, **run_kwargs): """Converts a PennyLane circuit to a Braket circuit""" braket_circuit = self.apply( circuit.operations, rotations=None, # Diagonalizing gates are applied in Braket SDK + use_unique_params=compute_gradient, **run_kwargs, ) - for observable in circuit.observables: - dev_wires = self.map_wires(observable.wires).tolist() - translated = translate_result_type(observable, dev_wires, self._braket_result_types) - if isinstance(translated, tuple): - for result_type in translated: - braket_circuit.add_result_type(result_type) - else: - braket_circuit.add_result_type(translated) + if compute_gradient: + braket_circuit = self._apply_gradient_result_type(circuit, braket_circuit) + else: + for observable in circuit.observables: + dev_wires = self.map_wires(observable.wires).tolist() + translated = translate_result_type(observable, dev_wires, self._braket_result_types) + if isinstance(translated, tuple): + for result_type in translated: + braket_circuit.add_result_type(result_type) + else: + braket_circuit.add_result_type(translated) + return braket_circuit + + def _apply_gradient_result_type(self, circuit, braket_circuit): + """Adds the AdjointGradient result type to the braket_circuit with the first observable in + circuit.observables. This fails for circuits with multiple observables""" + if len(circuit.observables) != 1: + raise ValueError( + f"Braket can only compute gradients for circuits with a single expectation" + f" observable, not {len(circuit.observables)} observables. If your QNode " + f"returns the expval of a single Hamiltonian observable and you're still seeing " + f"this error, try recreating H = qml.Hamiltonian(H.coeffs, H.ops) before " + f"returning expval(H). PennyLane transforms Hamiltonian observables if a grouping" + f" is set, and this clears any grouping. See " + f"https://docs.aws.amazon.com/braket/latest/developerguide/hybrid.html for more." + ) + pl_observable = circuit.observables[0] + if pl_observable.return_type != Expectation: + raise ValueError( + f"Braket can only compute gradients for circuits with a single expectation" + f" observable, not a {pl_observable.return_type} observable." + ) + if isinstance(pl_observable, Hamiltonian): + targets = [self.map_wires(op.wires) for op in pl_observable.ops] + else: + targets = self.map_wires(pl_observable.wires).tolist() + param_index = 0 + params_not_to_diff = {} + for operation in circuit.operations: + for p in operation.parameters: + if param_index not in circuit.trainable_params: + params_not_to_diff[f"p_{param_index}"] = p + param_index += 1 + + # bind all the non-trainable parameters since they don't need to be parameters in the + # Amazon Braket service. + braket_circuit = braket_circuit(**params_not_to_diff) + + braket_circuit.add_result_type( + get_adjoint_gradient_result_type( + pl_observable, + targets, + self._braket_result_types, + [f"p_{param_index}" for param_index in circuit.trainable_params], + ) + ) return braket_circuit def statistics( @@ -173,7 +227,6 @@ def statistics( "Unsupported return type specified for observable {}".format(obs.name) ) results.append(self._get_statistic(braket_result, obs)) - return results def _braket_to_pl_result(self, braket_result, circuit): @@ -182,6 +235,29 @@ def _braket_to_pl_result(self, braket_result, circuit): # Compute the required statistics results = self.statistics(braket_result, circuit.observables) + ag_results = [ + result + for result in braket_result.result_types + if result.type.type == "adjoint_gradient" + ] + + if ag_results: + # adjoint gradient results are a "ragged nested sequences (which is a list-or-tuple of + # lists-or-tuples-or ndarrays with different lengths or shapes)", so we have to set + # dtype="object", otherwise numpy will throw a warning + + # whenever the adjoint gradient result type is present, it should be the only result + # type, which is why this changing of dtype works. If we ever change this plugin + # to submit another result type alongside adjoint gradient, this logic will need to + # change. + return np.asarray( + [ + np.asarray(result, dtype="object") + if isinstance(result, collections.abc.Sequence) + else result + for result in results + ] + ) # Ensures that a combination with sample does not put # single-number results in superfluous arrays all_sampled = all(obs.return_type is Sample for obs in circuit.observables) @@ -208,29 +284,47 @@ def _tracking_data(task): else: return {"braket_failed_task_id": task.id} - def execute(self, circuit: CircuitGraph, **run_kwargs) -> np.ndarray: + def execute(self, circuit: CircuitGraph, compute_gradient=False, **run_kwargs) -> np.ndarray: self.check_validity(circuit.operations, circuit.observables) - self._circuit = self._pl_to_braket_circuit(circuit, **run_kwargs) - self._task = self._run_task(self._circuit) + self._circuit = self._pl_to_braket_circuit( + circuit, compute_gradient=compute_gradient, **run_kwargs + ) + param_index = 0 + param_dict = {} + for operation in circuit.operations: + for p in operation.parameters: + if isinstance(p, numbers.Number): + param_name = f"p_{param_index}" + param_dict[param_name] = p + param_index += 1 + self._task = self._run_task(self._circuit, inputs=param_dict) braket_result = self._task.result() if self.tracker.active: tracking_data = self._tracking_data(self._task) self.tracker.update(executions=1, shots=self.shots, **tracking_data) self.tracker.record() - return self._braket_to_pl_result(braket_result, circuit) def apply( - self, operations: Sequence[Operation], rotations: Sequence[Operation] = None, **run_kwargs + self, + operations: Sequence[Operation], + rotations: Sequence[Operation] = None, + use_unique_params=False, + **run_kwargs, ) -> Circuit: """Instantiate Braket Circuit object.""" rotations = rotations or [] circuit = Circuit() # Add operations to Braket Circuit object + param_index = 0 for operation in operations + rotations: - gate = translate_operation(operation) + param_names = [f"p_{param_index+i}" for i, p in enumerate(operation.parameters)] + param_index += len(operation.parameters) + gate = translate_operation( + operation, use_unique_params=use_unique_params, param_names=param_names + ) dev_wires = self.map_wires(operation.wires).tolist() ins = Instruction(gate, dev_wires) circuit.add_instruction(ins) @@ -247,12 +341,11 @@ def _check_supported_result_types(self): supported_result_types = self._device.properties.action[ "braket.ir.openqasm.program" ].supportedResultTypes - self._braket_result_types = frozenset( result_type.name for result_type in supported_result_types ) - def _run_task(self, circuit): + def _run_task(self, circuit, inputs=None): raise NotImplementedError("Need to implement task runner") def _get_statistic(self, braket_result, observable): @@ -285,7 +378,6 @@ class BraketAwsQubitDevice(BraketQubitDevice): aws_session (Optional[AwsSession]): An AwsSession object created to manage interactions with AWS services, to be supplied if extra control is desired. Default: None - parallel (bool): Indicates whether to use parallel execution for gradient calculations. Default: False max_parallel (int, optional): Maximum number of tasks to run on AWS in parallel. Batch creation will fail if this value is greater than the maximum allowed concurrent @@ -348,7 +440,6 @@ def __init__( @property def parallel(self): - """bool: True if gradient calculations are evaluated in parallel.""" return self._parallel def batch_execute(self, circuits, **run_kwargs): @@ -395,16 +486,51 @@ def batch_execute(self, circuits, **run_kwargs): for braket_result, circuit in zip(braket_results_batch, circuits) ] - def _run_task(self, circuit): + def _run_task(self, circuit, inputs=None): return self._device.run( circuit, s3_destination_folder=self._s3_folder, shots=0 if self.analytic else self.shots, poll_timeout_seconds=self._poll_timeout_seconds, poll_interval_seconds=self._poll_interval_seconds, + inputs=inputs or {}, **self._run_kwargs, ) + def capabilities(self=None): + """Add support for AG on sv1""" + # normally, we'd just call super().capabilities() here, but super() + # resolution doesn't work when you override a classmethod with an instance method + capabilities = BraketQubitDevice.capabilities().copy() + # if this method is called as a class method, don't add provides_jacobian since + # we don't know if the device is sv1 + if self and "AdjointGradient" in self._braket_result_types: + capabilities.update(provides_jacobian=True) + return capabilities + + def execute_and_gradients(self, circuits, **kwargs): + """Execute a list of circuits and calculate their gradients. + Returns a list of circuit results and a list of gradients/jacobians, one of each + for each circuit in circuits. + of floats, 1 float for every instance of a trainable parameter in a gate in the circuit. + Functions like qml.grad or qml.jacobian then use that format to generate a per-parameter + format. + """ + res = [] + jacs = [] + for circuit in circuits: + if not circuit.trainable_params: + new_res = self.execute(circuit, compute_gradient=False) + # don't bother computing a gradient when there aren't any trainable parameters. + new_jac = np.tensor([]) + else: + results = self.execute(circuit, compute_gradient=True) + new_res, new_jac = results[0] + res.append(new_res) + jacs.append(new_jac) + + return res, jacs + class BraketLocalQubitDevice(BraketQubitDevice): r"""Amazon Braket LocalSimulator qubit device for PennyLane. @@ -436,7 +562,7 @@ def __init__( device = LocalSimulator(backend) super().__init__(wires, device, shots=shots, **run_kwargs) - def _run_task(self, circuit): + def _run_task(self, circuit, inputs=None): return self._device.run( circuit, shots=0 if self.analytic else self.shots, **self._run_kwargs ) diff --git a/src/braket/pennylane_plugin/translation.py b/src/braket/pennylane_plugin/translation.py index 2e099cbd..da800ab4 100644 --- a/src/braket/pennylane_plugin/translation.py +++ b/src/braket/pennylane_plugin/translation.py @@ -11,12 +11,14 @@ # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. +import numbers from functools import reduce, singledispatch -from typing import Any, FrozenSet, List, Tuple, Union +from typing import Any, FrozenSet, List, Optional, Tuple, Union import pennylane as qml -from braket.circuits import Gate, ResultType, gates, noises, observables +from braket.circuits import FreeParameter, Gate, ResultType, gates, noises, observables from braket.circuits.result_types import ( + AdjointGradient, DensityMatrix, Expectation, Probability, @@ -109,16 +111,49 @@ def supported_operations(device: Device) -> FrozenSet[str]: ) -def translate_operation(operation: Operation, *args, **kwargs) -> Gate: +def translate_operation( + operation: Operation, + use_unique_params: bool = False, + param_names: Optional[List[str]] = None, + *args, + **kwargs, +) -> Gate: """Translates a PennyLane ``Operation`` into the corresponding Braket ``Gate``. Args: operation (Operation): The PennyLane ``Operation`` to translate + use_unique_params (bool): If true, numeric parameters in the resulting operation will be + replaced with FreeParameter objects (with names corresponding to param_names). Non-numeric + parameters will be skipped. + param_names (Optional[List[str]]): A list of parameter names + to be supplied to the new operation. Returns: Gate: The Braket gate corresponding to the given operation """ - parameters = [p.numpy() if isinstance(p, qml.numpy.tensor) else p for p in operation.parameters] + if use_unique_params: + param_names = param_names or [] + parameters = [] + name_index = 0 + for param in operation.parameters: + # PennyLane passes any non-keyword argument in the operation.parameters list. + # In some cases, like the unitary gate or qml.QubitChannel (Kraus noise), these + # parameter can be matrices. Braket only supports parameterization of numeric parameters + # (so far, these are all angle parameters), so non-numeric parameters are handled + # separately. + if isinstance(param, numbers.Number): + new_param = FreeParameter(param_names[name_index]) + name_index += 1 + elif isinstance(param, qml.numpy.tensor): + new_param = param.numpy() + else: + new_param = param + parameters.append(new_param) + else: + parameters = [ + p.numpy() if isinstance(p, qml.numpy.tensor) else p for p in operation.parameters + ] + return _translate_operation(operation, parameters) @@ -354,6 +389,18 @@ def _(ms: MS, parameters): return gates.MS(phi_0 + np.pi, phi_1) if ms.inverse else gates.MS(phi_0, phi_1) +def get_adjoint_gradient_result_type( + observable: Observable, + targets: Union[List[int], List[List[int]]], + supported_result_types: FrozenSet[str], + parameters: List[str], +): + if "AdjointGradient" not in supported_result_types: + raise NotImplementedError("Unsupported return type: AdjointGradient") + braket_observable = _translate_observable(observable) + return AdjointGradient(observable=braket_observable, target=targets, parameters=parameters) + + def translate_result_type( observable: Observable, targets: List[int], supported_result_types: FrozenSet[str] ) -> Union[ResultType, Tuple[ResultType, ...]]: @@ -402,7 +449,21 @@ def translate_result_type( @singledispatch def _translate_observable(observable): - raise TypeError(f"Unsupported observable: {observable}") + raise TypeError(f"Unsupported observable: {type(observable)}") + + +@_translate_observable.register +def _(H: qml.Hamiltonian): + # terms is structured like [C, O] where C is a tuple of all the coefficients, and O is + # a tuple of all the corresponding observable terms (X, Y, Z, H, etc or a tensor product + # of them) + coefficents, pl_observables = H.terms() + braket_observables = list(map(lambda obs: _translate_observable(obs), pl_observables)) + braket_hamiltonian = sum( + (coef * obs for coef, obs in zip(coefficents[1:], braket_observables[1:])), + coefficents[0] * braket_observables[0], + ) + return braket_hamiltonian @_translate_observable.register @@ -473,6 +534,20 @@ def translate_result( Note: Hamiltonian results will be summed over all terms. """ + + # if braket result contains adjoint gradient, just return it since it should be the only + # result type if it's there at all. + ag_results = [ + result for result in braket_result.result_types if result.type.type == "adjoint_gradient" + ] + if ag_results: + ag_result = ag_results[0] + key_indices = [int(param_name.split("p_")[1]) for param_name in ag_result.value["gradient"]] + return [ag_result.value["expectation"]], [ + # we need to sort the keys by index since braket can return them in the wrong order + ag_result.value["gradient"][f"p_{i}"] + for i in sorted(key_indices) + ] translated = translate_result_type(observable, targets, supported_result_types) if isinstance(observable, qml.Hamiltonian): coeffs, _ = observable.terms() diff --git a/test/integ_tests/conftest.py b/test/integ_tests/conftest.py index bf4334b6..44ae08f3 100755 --- a/test/integ_tests/conftest.py +++ b/test/integ_tests/conftest.py @@ -50,6 +50,7 @@ # PennyLane devices # List of all devices. +on_demand_sv_devices = [(BraketAwsQubitDevice, DEVICE_ARN)] sv_devices = [(BraketAwsQubitDevice, DEVICE_ARN), (BraketLocalQubitDevice, "braket_sv")] dm_devices = [(BraketLocalQubitDevice, "braket_dm")] devices = sv_devices + dm_devices @@ -143,6 +144,17 @@ def _device(n): return _device +@pytest.fixture(params=on_demand_sv_devices) +def on_demand_sv_device(request, shots, extra_kwargs): + """Fixture to initialize and return a PennyLane device""" + device, backend = request.param + + def _device(n): + return device(wires=n, shots=shots, **extra_kwargs(device, backend)) + + return _device + + @pytest.fixture(params=dm_devices) def dm_device(request, shots, extra_kwargs): """Fixture to initialize and return a PennyLane device""" diff --git a/test/integ_tests/test_adjoint_gradient.py b/test/integ_tests/test_adjoint_gradient.py new file mode 100644 index 00000000..9973238c --- /dev/null +++ b/test/integ_tests/test_adjoint_gradient.py @@ -0,0 +1,139 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You +# may not use this file except in compliance with the License. A copy of +# the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is +# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF +# ANY KIND, either express or implied. See the License for the specific +# language governing permissions and limitations under the License. + + +"""Tests that gradients are correctly computed in the plugin device via braket""" + +import math +import os +import random + +import pennylane as qml +import pytest +from pennylane import numpy as np + +os.environ["BRAKET_ENDPOINT"] = "https://braket-gamma.us-west-2.amazonaws.com" +os.environ["AWS_REGION"] = "us-west-2" +ABS_TOLERANCE = 1e-5 + + +def adj_grad_test_helper(device, circuit, parameters): + @qml.qnode(device, diff_method="device") + def circuit_braket_ag(*parameters): + return circuit(*parameters) + + # pl uses braket gradient calculation by default! so we have to specify + # pl's parameter shift method + @qml.qnode(device, diff_method="parameter-shift") + def circuit_with_pl(*parameters): + return circuit(*parameters) + + braket_grad = qml.grad(circuit_braket_ag)(*parameters) + pl_grad = qml.grad(circuit_with_pl)(*parameters) + + assert len(braket_grad) + # assert grad isn't all zeros + assert np.array( + [not math.isclose(derivative, 0, abs_tol=ABS_TOLERANCE) for derivative in pl_grad] + ).any() + assert np.allclose(braket_grad, pl_grad) + braket_jac = qml.jacobian(circuit_braket_ag)(*parameters) + pl_jac = qml.jacobian(circuit_with_pl)(*parameters) + # assert jac isn't all zeros + assert len(braket_jac) + assert np.array( + [not math.isclose(derivative, 0, abs_tol=ABS_TOLERANCE) for derivative in braket_jac] + ).any() + assert np.allclose(braket_jac, pl_jac) + + +@pytest.mark.parametrize("shots", [None]) +class TestAdjointGradient: + def test_grad(self, on_demand_sv_device): + dev = on_demand_sv_device(2) + + def circuit(x, y, z): + qml.RX(x, wires=0) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 1]) + qml.RX(z, wires=1) + return qml.expval(qml.PauliZ(1)) + + x = np.array(0.1, requires_grad=False) + y = np.array(0.2, requires_grad=True) + z = np.array(0.3, requires_grad=True) + + adj_grad_test_helper(dev, circuit, [x, y, z]) + + def test_grad_large_circuit(self, on_demand_sv_device): + num_qubits = 8 + # having > 10 parameterized gates is important; we've + # had a bug with string sorting of the gradients + # that this test should catch + num_params = 11 + dev = on_demand_sv_device(num_qubits) + + def circuit(x): + # seed this so it's always the same circuit generated + random.seed(2) + # put qubits into an interesting state so we have non-zero + # derivatives + for i in range(num_qubits): + rand_val = random.randint(0, 2) + rand_param = random.choice(x) + if rand_val == 0: + qml.RX(rand_param, wires=i) + elif rand_val == 1: + qml.RY(rand_param, wires=i) + else: + qml.RZ(rand_param, wires=i) + if random.randint(0, 3) == 0: + # cnot i with some random other qubit + qml.CNOT(wires=[i, random.choice([j for j in range(num_qubits) if i != j])]) + + # use every parameter at least once + for i in range(num_params): + rand_val = random.randint(0, 2) + qubit = random.randrange(num_qubits) + if rand_val == 0: + qml.RX(x[i], wires=qubit) + elif rand_val == 1: + qml.RY(x[i], wires=qubit) + else: + qml.RZ(x[i], wires=qubit) + return qml.expval(qml.PauliZ(1)) + + # x = [.1,.2,....] + x = np.array([i / 10 for i in range(num_params)], requires_grad=True) + x[1] = np.array(x[1], requires_grad=False) + + adj_grad_test_helper(dev, circuit, [x]) + + # this test runs on sv1, dm1, and the local simulator to validate that + # calls to qml.grad() without a specified diff_method succeed + def test_default_diff_method(self, device): + dev = device(2) + + @qml.qnode(dev) + def circuit(x, y, z): + qml.RX(x, wires=0) + qml.RY(y, wires=1) + qml.CNOT(wires=[0, 1]) + qml.RX(z, wires=1) + return qml.expval(qml.PauliZ(1)) + + x = np.array(0.1, requires_grad=False) + y = np.array(0.2, requires_grad=True) + z = np.array(0.3, requires_grad=True) + + qml.grad(circuit)(x, y, z) diff --git a/test/integ_tests/test_batch.py b/test/integ_tests/test_batch.py index 3bf9388a..8507a765 100644 --- a/test/integ_tests/test_batch.py +++ b/test/integ_tests/test_batch.py @@ -41,8 +41,8 @@ def func(weights): qml.templates.StronglyEntanglingLayers(weights, wires=range(qubits)) return qml.expval(qml.PauliZ(0)) - qnode_aws = qml.QNode(func, dev_aws) - qnode_default = qml.QNode(func, dev_default) + qnode_aws = qml.QNode(func, dev_aws, diff_method="parameter-shift") + qnode_default = qml.QNode(func, dev_default, diff_method="parameter-shift") shape = qml.templates.StronglyEntanglingLayers.shape(layers, qubits) weights = np.random.random(shape) @@ -103,8 +103,8 @@ def func(weights): qml.templates.StronglyEntanglingLayers(weights, wires=range(qubits)) return qml.expval(qml.PauliZ(0)) - qnode_aws = qml.QNode(func, dev_aws, interface="torch") - qnode_default = qml.QNode(func, dev_default, interface="torch") + qnode_aws = qml.QNode(func, dev_aws, interface="torch", diff_method="parameter-shift") + qnode_default = qml.QNode(func, dev_default, interface="torch", diff_method="parameter-shift") shape = qml.templates.StronglyEntanglingLayers.shape(layers, qubits) weights = np.random.random(shape) @@ -167,8 +167,8 @@ def func(weights): qml.templates.StronglyEntanglingLayers(weights, wires=range(qubits)) return qml.expval(qml.PauliZ(0)) - qnode_aws = qml.QNode(func, dev_aws, interface="tf") - qnode_default = qml.QNode(func, dev_default, interface="tf") + qnode_aws = qml.QNode(func, dev_aws, interface="tf", diff_method="parameter-shift") + qnode_default = qml.QNode(func, dev_default, interface="tf", diff_method="parameter-shift") shape = qml.templates.StronglyEntanglingLayers.shape(layers, qubits) weights = np.random.random(shape) diff --git a/test/integ_tests/test_expval.py b/test/integ_tests/test_expval.py index 035487a5..412f1988 100755 --- a/test/integ_tests/test_expval.py +++ b/test/integ_tests/test_expval.py @@ -146,7 +146,7 @@ def test_multi_mode_hermitian_expectation(self, device, shots, tol): ] ) - @qml.qnode(dev) + @qml.qnode(dev, diff_method="parameter-shift") def circuit(): qml.RY(theta, wires=[0]) qml.RY(phi, wires=[1]) @@ -269,7 +269,7 @@ def test_hermitian(self, device, shots, tol): ] ) - @qml.qnode(dev) + @qml.qnode(dev, diff_method="parameter-shift") def circuit(): qml.RX(theta, wires=[0]) qml.RX(phi, wires=[1]) diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 84508981..cf13a0d4 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -21,7 +21,7 @@ import pennylane as qml import pytest from braket.aws import AwsDevice, AwsDeviceType, AwsQuantumTask, AwsQuantumTaskBatch -from braket.circuits import Circuit, Observable, result_types +from braket.circuits import Circuit, FreeParameter, Observable, result_types from braket.device_schema import DeviceActionType from braket.device_schema.openqasm_device_action_properties import OpenQASMDeviceActionProperties from braket.device_schema.simulators import GateModelSimulatorDeviceCapabilities @@ -44,9 +44,15 @@ { "actionType": "braket.ir.openqasm.program", "version": ["1"], - "supportedOperations": ["rx", "ry", "h", "cy", "cnot"], + "supportedOperations": ["rx", "ry", "h", "cy", "cnot", "unitary"], "supportedResultTypes": [ - {"name": "StateVector", "observables": None, "minShots": 0, "maxShots": 0} + {"name": "StateVector", "observables": None, "minShots": 0, "maxShots": 0}, + { + "name": "AdjointGradient", + "observables": ["x", "y", "z", "h", "i"], + "minShots": 0, + "maxShots": 0, + }, ], } ) @@ -116,6 +122,7 @@ type(TASK_BATCH).tasks = PropertyMock(return_value=[TASK, TASK]) SIM_TASK = Mock() SIM_TASK.result.return_value.additional_metadata.simulatorMetadata.executionDuration = 1234 +SIM_TASK.result.return_value.result_types = [] type(SIM_TASK).id = PropertyMock(return_value="task_arn") SIM_TASK.state.return_value = "COMPLETED" CIRCUIT = ( @@ -151,6 +158,36 @@ def test_apply(): assert circuit == Circuit().h(0).cnot(0, 1) +def test_apply_unique_parameters(): + """Tests that apply with unique_params=True applies the correct parametrized gates.""" + dev = _aws_device(wires=2) + circuit = dev.apply( + [ + qml.Hadamard(wires=0), + qml.CNOT(wires=[0, 1]), + qml.RX(np.pi, wires=0), + qml.RY(np.pi, wires=0), + # note the gamma/p ordering doesn't affect the naming of the parameters below. + qml.GeneralizedAmplitudeDamping(gamma=0.1, p=0.9, wires=0), + qml.GeneralizedAmplitudeDamping(p=0.9, gamma=0.1, wires=0), + ], + use_unique_params=True, + ) + expected = Circuit().h(0).cnot(0, 1).rx(0, FreeParameter("p_0")) + expected = expected.ry(0, FreeParameter("p_1")) + expected = expected.generalized_amplitude_damping( + 0, + gamma=FreeParameter("p_2"), + probability=FreeParameter("p_3"), + ) + expected = expected.generalized_amplitude_damping( + 0, + gamma=FreeParameter("p_4"), + probability=FreeParameter("p_5"), + ) + assert circuit == expected + + def test_apply_unused_qubits(): """Tests that the correct circuit is created when not all wires in the device are used.""" dev = _aws_device(wires=4) @@ -196,6 +233,8 @@ def test_execute(mock_run): with QuantumTape() as circuit: qml.Hadamard(wires=0) + qml.QubitUnitary(1 / np.sqrt(2) * np.array([[1, 1], [1, -1]]), wires=0) + qml.RX(0.432, wires=0) qml.CNOT(wires=[0, 1]) qml.probs(wires=[0]) qml.expval(qml.PauliX(1)) @@ -222,15 +261,215 @@ def test_execute(mock_run): RESULT.get_value_by_result_type(result_types.Sample(observable=Observable.Z(), target=3)), ) assert dev.task == TASK - + EXPECTED_CIRC = ( + Circuit() + .h(0) + .unitary([0], 1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])) + .rx(0, 0.432) + .cnot(0, 1) + .i(2) + .i(3) + .probability(target=[0]) + .expectation(observable=Observable.X(), target=1) + .variance(observable=Observable.Y(), target=2) + .sample(observable=Observable.Z(), target=3) + ) mock_run.assert_called_with( - CIRCUIT, + EXPECTED_CIRC, s3_destination_folder=("foo", "bar"), shots=SHOTS, poll_timeout_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, poll_interval_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, foo="bar", + inputs={"p_0": 0.432}, + ) + + +with QuantumTape() as CIRCUIT_1: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(0.432, wires=0) + qml.RY(0.543, wires=0) + qml.expval(qml.PauliX(1)) +CIRCUIT_1.trainable_params = [0] + +with QuantumTape() as CIRCUIT_2: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(0.432, wires=0) + qml.RY(0.543, wires=0) + qml.expval(2 * qml.PauliX(0) @ qml.PauliY(1)) +CIRCUIT_2.trainable_params = [0, 1] + +with QuantumTape() as CIRCUIT_3: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(0.432, wires=0) + qml.RY(0.543, wires=0) + qml.expval(2 * qml.PauliX(0) @ qml.PauliY(1) + 0.75 * qml.PauliY(0) @ qml.PauliZ(1)) +CIRCUIT_3.trainable_params = [0, 1] + +with QuantumTape() as CIRCUIT_4: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(0.432, wires=0) + qml.RY(0.543, wires=0) + qml.expval(qml.PauliX(1)) +CIRCUIT_4.trainable_params = [] + + +@patch.object(AwsDevice, "run") +@pytest.mark.parametrize( + "pl_circ, expected_braket_circ, wires, expected_inputs, result_types, expected_pl_result", + [ + ( + CIRCUIT_1, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, FreeParameter("p_0")) + .ry(0, 0.543) + .adjoint_gradient(observable=Observable.X(), target=1, parameters=["p_0"]), + 2, + {"p_0": 0.432, "p_1": 0.543}, + [ + { + "type": { + "observable": "x()", + "targets": [[0]], + "parameters": ["p_0", "p_1"], + "type": "adjoint_gradient", + }, + "value": { + "gradient": {"p_0": -0.194399, "p_1": 0.9316158}, + "expectation": 0.0, + }, + }, + ], + np.tensor( + [ + [ + np.tensor([0.0], requires_grad=True), + np.tensor([-0.194399, 0.9316158], requires_grad=True), + ] + ], + dtype=object, + requires_grad=True, + ), + ), + ( + CIRCUIT_2, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, FreeParameter("p_0")) + .ry(0, FreeParameter("p_1")) + .adjoint_gradient( + observable=(2 * Observable.X() @ Observable.Y()), + target=[0, 1], + parameters=["p_0", "p_1"], + ), + 2, + {"p_0": 0.432, "p_1": 0.543}, + [ + { + "type": { + "observable": "2.0 * x() @ y()", + "targets": [[0, 1]], + "parameters": ["p_0", "p_1"], + "type": "adjoint_gradient", + }, + "value": { + "gradient": {"p_0": -0.01894799, "p_1": 0.9316158}, + "expectation": 0.0, + }, + }, + ], + np.tensor( + [ + [ + np.tensor([0.0], requires_grad=True), + np.tensor([-0.01894799, 0.9316158], requires_grad=True), + ] + ], + dtype=object, + requires_grad=True, + ), + ), + ( + CIRCUIT_3, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, FreeParameter("p_0")) + .ry(0, FreeParameter("p_1")) + .adjoint_gradient( + observable=( + 2 * Observable.X() @ Observable.Y() + 0.75 * Observable.Y() @ Observable.Z() + ), + target=[[0, 1], [0, 1]], + parameters=["p_0", "p_1"], + ), + 2, + {"p_0": 0.432, "p_1": 0.543}, + [ + { + "type": { + "observable": "2.0 * x() @ y() + .75 * y() @ z()", + "targets": [[0, 1], [0, 1]], + "parameters": ["p_0", "p_1"], + "type": "adjoint_gradient", + }, + "value": { + "gradient": {"p_0": -0.01894799, "p_1": 0.9316158}, + "expectation": 0.0, + }, + }, + ], + np.tensor( + [ + [ + np.tensor([0.0], requires_grad=True), + np.tensor([-0.01894799, 0.9316158], requires_grad=True), + ] + ], + dtype=object, + requires_grad=True, + ), + ), + ], +) +def test_execute_with_gradient( + mock_run, + pl_circ, + expected_braket_circ, + wires, + expected_inputs, + result_types, + expected_pl_result, +): + task = Mock() + type(task).id = PropertyMock(return_value="task_arn") + task.state.return_value = "COMPLETED" + task.result.return_value = get_test_result_object(result_types=result_types) + mock_run.return_value = task + dev = _aws_device(wires=wires, foo="bar", shots=0, device_type=AwsDeviceType.SIMULATOR) + + results = dev.execute(pl_circ, compute_gradient=True) + + assert dev.task == task + + mock_run.assert_called_with( + (expected_braket_circ), + s3_destination_folder=("foo", "bar"), + shots=0, + poll_timeout_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, + poll_interval_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, + foo="bar", + inputs=expected_inputs, ) + assert (results[0][0] == expected_pl_result[0][0]).all() + assert (results[0][1] == expected_pl_result[0][1]).all() @patch.object(AwsDevice, "run") @@ -300,6 +539,108 @@ def test_pl_to_braket_circuit(): assert braket_circuit_true == braket_circuit +def test_pl_to_braket_circuit_compute_gradient(): + """Tests that a PennyLane circuit is correctly converted into a Braket circuit + with a gradient and unique parameters when compute_gradient is True""" + dev = _aws_device(wires=2, foo="bar") + + with QuantumTape() as tape: + qml.RX(0.2, wires=0) + qml.RX(0.3, wires=1) + qml.CNOT(wires=[0, 1]) + qml.expval(qml.PauliZ(0)) + + expected_braket_circuit = ( + Circuit() + .rx(0, FreeParameter("p_0")) + .rx(1, FreeParameter("p_1")) + .cnot(0, 1) + .add_result_type( + result_types.AdjointGradient( + observable=Observable.Z(), target=0, parameters=["p_0", "p_1"] + ) + ) + ) + + actual_braket_circuit = dev._pl_to_braket_circuit(tape, compute_gradient=True) + + assert expected_braket_circuit == actual_braket_circuit + + +def test_pl_to_braket_circuit_compute_gradient_hamiltonian_tensor_product_terms(): + """Tests that a PennyLane circuit is correctly converted into a Braket circuit""" + """when the Hamiltonian has multiple tensor product ops and we compute the gradient""" + dev = _aws_device(wires=2, foo="bar") + + with QuantumTape() as tape: + qml.RX(0.2, wires=0) + qml.RX(0.3, wires=1) + qml.CNOT(wires=[0, 1]) + qml.expval( + qml.Hamiltonian( + (2, 3), + ( + qml.PauliX(wires=0) @ qml.PauliX(wires=1), + qml.PauliY(wires=0) @ qml.PauliY(wires=1), + ), + ) + ) + + braket_obs = 2 * Observable.X() @ Observable.X() + 3 * Observable.Y() @ Observable.Y() + braket_circuit_true = ( + Circuit() + .rx(0, FreeParameter("p_0")) + .rx(1, FreeParameter("p_1")) + .cnot(0, 1) + .add_result_type( + result_types.AdjointGradient( + observable=braket_obs, target=[[0, 1], [0, 1]], parameters=["p_0", "p_1"] + ) + ) + ) + + braket_circuit = dev._pl_to_braket_circuit(tape, compute_gradient=True) + + assert braket_circuit_true == braket_circuit + + +def test_pl_to_braket_circuit_gradient_fails_with_multiple_observables(): + """Tests that a PennyLane circuit is correctly converted into a Braket circuit + with a gradient and unique parameters when compute_gradient is True""" + dev = _aws_device(wires=2, foo="bar") + + with QuantumTape() as tape: + qml.RX(0.2, wires=0) + qml.RX(0.3, wires=1) + qml.CNOT(wires=[0, 1]) + qml.expval(qml.PauliZ(0)) + qml.expval(qml.PauliZ(0)) + with pytest.raises( + ValueError, + match="Braket can only compute gradients for circuits with a single expectation" + " observable, not ", + ): + dev._pl_to_braket_circuit(tape, compute_gradient=True) + + +def test_pl_to_braket_circuit_gradient_fails_with_invalid_observable(): + """Tests that a PennyLane circuit is correctly converted into a Braket circuit + with a gradient and unique parameters when compute_gradient is True""" + dev = _aws_device(wires=2, foo="bar") + + with QuantumTape() as tape: + qml.RX(0.2, wires=0) + qml.RX(0.3, wires=1) + qml.CNOT(wires=[0, 1]) + qml.var(qml.PauliZ(0)) + with pytest.raises( + ValueError, + match="Braket can only compute gradients for circuits with a single expectation" + " observable, not a", + ): + dev._pl_to_braket_circuit(tape, compute_gradient=True) + + def test_pl_to_braket_circuit_hamiltonian(): """Tests that a PennyLane circuit is correctly converted into a Braket circuit""" dev = _aws_device(wires=2, foo="bar") @@ -324,6 +665,39 @@ def test_pl_to_braket_circuit_hamiltonian(): assert braket_circuit_true == braket_circuit +def test_pl_to_braket_circuit_hamiltonian_tensor_product_terms(): + """Tests that a PennyLane circuit is correctly converted into a Braket circuit""" + """when the Hamiltonian has multiple tensor product ops""" + dev = _aws_device(wires=2, foo="bar") + + with QuantumTape() as tape: + qml.RX(0.2, wires=0) + qml.RX(0.3, wires=1) + qml.CNOT(wires=[0, 1]) + qml.expval( + qml.Hamiltonian( + (2, 3), + ( + qml.PauliX(wires=0) @ qml.PauliX(wires=1), + qml.PauliY(wires=0) @ qml.PauliY(wires=1), + ), + ) + ) + + braket_circuit_true = ( + Circuit() + .rx(0, 0.2) + .rx(1, 0.3) + .cnot(0, 1) + .expectation(Observable.X() @ Observable.X(), [0, 1]) + .expectation(Observable.Y() @ Observable.Y(), [0, 1]) + ) + + braket_circuit = dev._pl_to_braket_circuit(tape) + + assert braket_circuit_true == braket_circuit + + def test_bad_statistics(): """Test if a QuantumFunctionError is raised for an invalid return type""" dev = _aws_device(wires=1, foo="bar") @@ -768,6 +1142,120 @@ def test_add_braket_user_agent_invoked(aws_device_mock): ) +@patch.object(AwsDevice, "run") +@pytest.mark.parametrize( + "pl_circ, expected_braket_circ, wires, expected_inputs, result_types, expected_pl_result", + [ + ( + CIRCUIT_1, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, FreeParameter("p_0")) + .ry(0, 0.543) + .adjoint_gradient(observable=Observable.X(), target=1, parameters=["p_0"]), + 2, + {"p_0": 0.432, "p_1": 0.543}, + [ + { + "type": { + "observable": "x()", + "targets": [[0]], + "parameters": ["p_0", "p_1"], + "type": "adjoint_gradient", + }, + "value": { + "gradient": {"p_0": -0.194399, "p_1": 0.9316158}, + "expectation": 0.0, + }, + }, + ], + [np.tensor([0]), np.tensor([-0.194399, 0.9316158])], + ), + ( + CIRCUIT_4, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, 0.432) + .ry(0, 0.543) + .expectation( + observable=Observable.X(), + target=1, + ), + 2, + {"p_0": 0.432, "p_1": 0.543}, + [ + { + "type": {"observable": ["x"], "targets": [1], "type": "expectation"}, + "value": 0.0, + } + ], + [np.tensor([0]), np.tensor([])], + ), + ], +) +def test_execute_and_gradients( + mock_run, + pl_circ, + expected_braket_circ, + wires, + expected_inputs, + result_types, + expected_pl_result, +): + task = Mock() + type(task).id = PropertyMock(return_value="task_arn") + task.state.return_value = "COMPLETED" + task.result.return_value = get_test_result_object(result_types=result_types) + mock_run.return_value = task + dev = _aws_device( + wires=wires, + foo="bar", + shots=0, + device_type=AwsDeviceType.SIMULATOR, + device_arn="arn:aws:braket:::device/quantum-simulator/amazon/sv1", + ) + + results, jacs = dev.execute_and_gradients([pl_circ]) + assert dev.task == task + mock_run.assert_called_with( + (expected_braket_circ), + s3_destination_folder=("foo", "bar"), + shots=0, + poll_timeout_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, + poll_interval_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, + foo="bar", + inputs=expected_inputs, + ) + + # assert results & jacs are right + assert (results == expected_pl_result[0]).all() + assert (jacs == expected_pl_result[1]).all() + + +def test_capabilities_class_and_instance_method(): + class_caps = BraketAwsQubitDevice.capabilities() + instance_caps = _aws_device(wires=2).capabilities() + expected_caps = { + "model": "qubit", + "supports_broadcasting": False, + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "supports_inverse_operations": True, + } + assert class_caps == expected_caps + # the instance should have provides_jacobian because AdjointGradient is in the + # supported result types + expected_caps["provides_jacobian"] = True + assert instance_caps == expected_caps + + +def _noop(*args, **kwargs): + return None + + class DummyLocalQubitDevice(BraketQubitDevice): short_name = "dummy" @@ -837,10 +1325,6 @@ def properties(self) -> GateModelSimulatorDeviceCapabilities: return GateModelSimulatorDeviceCapabilities.parse_obj(input_json) -def _noop(*args, **kwargs): - return None - - @patch.object(AwsDevice, "__init__", _noop) @patch.object(AwsDevice, "aws_session", new_callable=mock.PropertyMock) @patch.object(AwsDevice, "type", new_callable=mock.PropertyMock) @@ -852,6 +1336,7 @@ def _aws_device( wires, device_type=AwsDeviceType.QPU, shots=SHOTS, + device_arn="baz", **kwargs, ): properties_mock.action = {DeviceActionType.OPENQASM: ACTION_PROPERTIES} @@ -859,14 +1344,17 @@ def _aws_device( DeviceActionType.OPENQASM: ACTION_PROPERTIES } type_mock.return_value = device_type - return BraketAwsQubitDevice( + dev = BraketAwsQubitDevice( wires=wires, s3_destination_folder=("foo", "bar"), - device_arn="baz", + device_arn=device_arn, aws_session=Mock(), shots=shots, **kwargs, ) + # needed by the BraketAwsQubitDevice.capabilities function + dev._device._arn = device_arn + return dev @patch.object(AwsDevice, "__init__", _noop) @@ -883,3 +1371,36 @@ def _bad_aws_device(properties_mock, session_mock, wires, **kwargs): shots=SHOTS, **kwargs, ) + + +def get_test_result_object(result_types=[], source="qubit[2] q; cnot q[0], q[1]; measure q;"): + json_str = json.dumps( + { + "braketSchemaHeader": { + "name": "braket.task_result.gate_model_task_result", + "version": "1", + }, + "measurements": [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 1]], + "resultTypes": result_types, + "measuredQubits": [0, 1, 2, 3], + "taskMetadata": { + "braketSchemaHeader": { + "name": "braket.task_result.task_metadata", + "version": "1", + }, + "id": "task_arn", + "shots": 0, + "deviceId": "default", + }, + "additionalMetadata": { + "action": { + "braketSchemaHeader": { + "name": "braket.ir.openqasm.program", + "version": "1", + }, + "source": source, + }, + }, + } + ) + return GateModelQuantumTaskResult.from_string(json_str) diff --git a/test/unit_tests/test_translation.py b/test/unit_tests/test_translation.py index cd4ed874..34a970dd 100644 --- a/test/unit_tests/test_translation.py +++ b/test/unit_tests/test_translation.py @@ -17,8 +17,9 @@ import numpy as np import pennylane as qml import pytest -from braket.circuits import gates, noises, observables +from braket.circuits import FreeParameter, gates, noises, observables from braket.circuits.result_types import ( + AdjointGradient, DensityMatrix, Expectation, Probability, @@ -28,6 +29,7 @@ ) from braket.circuits.serialization import IRType from braket.tasks import GateModelQuantumTaskResult +from pennylane import numpy as pnp from pennylane.measurements import MeasurementProcess, ObservableReturnTypes from pennylane.wires import Wires @@ -35,6 +37,8 @@ from braket.pennylane_plugin.ops import MS, GPi, GPi2 from braket.pennylane_plugin.translation import ( _BRAKET_TO_PENNYLANE_OPERATIONS, + _translate_observable, + get_adjoint_gradient_result_type, translate_operation, translate_result, translate_result_type, @@ -145,6 +149,87 @@ (qml.SX, gates.Vi, 0), ] +testdata_with_params = [ + (qml.Identity, gates.I, [0], [], [], []), + (qml.Hadamard, gates.H, [0], [], [], []), + (qml.PauliX, gates.X, [0], [], [], []), + (qml.PauliY, gates.Y, [0], [], [], []), + (qml.PauliZ, gates.Z, [0], [], [], []), + (qml.Hadamard, gates.H, [0], [], [], []), + (qml.CNOT, gates.CNot, [0, 1], [], [], []), + (qml.CZ, gates.CZ, [0, 1], [], [], []), + (qml.CY, gates.CY, [0, 1], [], [], []), + (qml.SWAP, gates.Swap, [0, 1], [], [], []), + (qml.ECR, gates.ECR, [0, 1], [], [], []), + (qml.CSWAP, gates.CSwap, [0, 1, 2], [], [], []), + (qml.Toffoli, gates.CCNot, [0, 1, 2], [], [], []), + (qml.PhaseShift, gates.PhaseShift, [0], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.RX, gates.Rx, [0], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.RY, gates.Ry, [0], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.RZ, gates.Rz, [0], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.SWAP, gates.Swap, [0, 1], [], [], []), + (qml.CSWAP, gates.CSwap, [0, 1, 2], [], [], []), + (qml.Toffoli, gates.CCNot, [0, 1, 2], [], [], []), + (qml.ControlledPhaseShift, gates.CPhaseShift, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (CPhaseShift00, gates.CPhaseShift00, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (CPhaseShift01, gates.CPhaseShift01, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (CPhaseShift10, gates.CPhaseShift10, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (GPi, gates.GPi, [0], [2], ["a"], [FreeParameter("a")]), + (GPi2, gates.GPi2, [0], [2], ["a"], [FreeParameter("a")]), + (MS, gates.MS, [0, 1], [2, 3], ["a", "b"], [FreeParameter("a"), FreeParameter("b")]), + (PSWAP, gates.PSwap, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.ECR, gates.ECR, [0, 1], [], [], []), + (qml.ISWAP, gates.ISwap, [0, 1], [], [], []), + (qml.IsingXY, gates.XY, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.IsingXX, gates.XX, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.IsingYY, gates.YY, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + (qml.IsingZZ, gates.ZZ, [0, 1], [np.pi], ["pi"], [FreeParameter("pi")]), + ( + qml.AmplitudeDamping, + noises.AmplitudeDamping, + [0], + [0.1], + ["alpha"], + [FreeParameter("alpha")], + ), + ( + qml.GeneralizedAmplitudeDamping, + noises.GeneralizedAmplitudeDamping, + [0], + [0.1, 0.15], + ["p_000", "p_001"], + [FreeParameter("p_000"), FreeParameter("p_001")], + ), + (qml.PhaseDamping, noises.PhaseDamping, [0], [0.1], ["a"], [FreeParameter("a")]), + (qml.DepolarizingChannel, noises.Depolarizing, [0], [0.1], ["a"], [FreeParameter("a")]), + (qml.BitFlip, noises.BitFlip, [0], [0.1], ["a"], [FreeParameter("a")]), + (qml.PhaseFlip, noises.PhaseFlip, [0], [0.1], ["a"], [FreeParameter("a")]), + ( + qml.QubitUnitary, + gates.Unitary, + [0], + [np.array([[0, 1], [1, 0]])], + [], + [np.array([[0, 1], [1, 0]])], + ), + ( + qml.QubitChannel, + noises.Kraus, + [0], + [[np.array([[0, 0.8], [0.8, 0]]), np.array([[0.6, 0], [0, 0.6]])]], + [], + [[np.array([[0, 0.8], [0.8, 0]]), np.array([[0.6, 0], [0, 0.6]])]], + ), + ( + qml.QubitChannel, + noises.Kraus, + [0], + [pnp.tensor([np.array([[0, 0.8], [0.8, 0]]), np.array([[0.6, 0], [0, 0.6]])])], + [], + [pnp.tensor([np.array([[0, 0.8], [0.8, 0]]), np.array([[0.6, 0], [0, 0.6]])])], + ), +] + _braket_to_pl = { op.lower().replace("_", ""): _BRAKET_TO_PENNYLANE_OPERATIONS[op] for op in _BRAKET_TO_PENNYLANE_OPERATIONS @@ -183,6 +268,34 @@ def test_translate_operation(pl_cls, braket_cls, qubits, params): ) +@pytest.mark.parametrize( + "pl_gate_fn, braket_gate_fn, qubits, pl_params, pl_param_names, expected_params", + testdata_with_params, +) +def test_translate_operation_with_unique_params( + pl_gate_fn, braket_gate_fn, qubits, pl_params, pl_param_names, expected_params +): + """Tests that Braket operations are translated correctly""" + pl_op = pl_gate_fn(*pl_params, wires=qubits) + braket_gate = braket_gate_fn(*expected_params) + assert ( + translate_operation(pl_op, use_unique_params=True, param_names=pl_param_names) + == braket_gate + ) + if isinstance(pl_op, (GPi, GPi2, MS)): + assert ( + _braket_to_pl[ + re.match("^[a-z0-2]+", braket_gate.to_ir(qubits, ir_type=IRType.OPENQASM)).group(0) + ] + == pl_op.name + ) + else: + assert ( + _braket_to_pl[braket_gate.to_ir(qubits).__class__.__name__.lower().replace("_", "")] + == pl_op.name + ) + + @pytest.mark.parametrize("pl_cls, braket_cls, qubits, params, inv_params", testdata_inverses) def test_translate_operation_inverse(pl_cls, braket_cls, qubits, params, inv_params): """Tests that inverse gates are translated correctly""" @@ -229,6 +342,43 @@ def test_translate_result_type_observable(return_type, braket_result_type): assert braket_result_type == braket_result_type_calculated +@pytest.mark.parametrize( + "pl_obs, braket_obs, targets, param_names", + [ + (qml.Hadamard(0), observables.H(), [0], []), + (qml.PauliX(0), observables.X(), [0], ["p_000"]), + ( + qml.PauliX(0) @ qml.PauliY(1), + observables.X() @ observables.Y(), + [0, 1], + ["p_000", "p_001", "p_003"], + ), + ], +) +def test_get_adjoint_gradient_result_type(pl_obs, braket_obs, targets, param_names): + """Tests that an AdjointGradient result type is returned correctly""" + braket_result_type_calculated = get_adjoint_gradient_result_type( + pl_obs, + targets, + frozenset(["AdjointGradient"]), + param_names, + ) + braket_result_type = AdjointGradient( + observable=braket_obs, target=targets, parameters=param_names + ) + assert braket_result_type == braket_result_type_calculated + + +def test_get_adjoint_gradient_result_type_unsupported(): + """Tests if a NotImplementedError is raised by translate_result_type when a PennyLane state + return type is converted while not supported by the device""" + pl_obs = qml.Hadamard(0) + targets = [0] + param_names = ["p_000", "p_001"] + with pytest.raises(NotImplementedError, match="Unsupported return type"): + get_adjoint_gradient_result_type(pl_obs, targets, frozenset(), param_names) + + def test_translate_result_type_hamiltonian_expectation(): """Tests that a Hamiltonian is translated correctly""" obs = qml.Hamiltonian((2, 3), (qml.PauliX(wires=0), qml.PauliY(wires=1))) @@ -379,3 +529,31 @@ def _result_meta() -> dict: }, }, } + + +@pytest.mark.parametrize( + "expected_braket_H, pl_H", + [ + ( + 2 * observables.X() @ observables.Y() @ observables.Z(), + 2 * qml.PauliX(wires=0) @ qml.PauliY(wires=1) @ qml.PauliZ(wires=2), + ), + ( + 2 * (observables.X() @ observables.Y() @ observables.Z()), + 2 * (qml.PauliX(wires=0) @ qml.PauliY(wires=1) @ qml.PauliZ(wires=2)), + ), + ( + 2 * observables.X() @ observables.Y() @ observables.Z() + 0.75 * observables.X(), + 2 * qml.PauliX(wires=0) @ qml.PauliY(wires=1) @ qml.PauliZ(wires=2) + + 0.75 * qml.PauliX(0), + ), + (1.25 * observables.H(), 1.25 * qml.Hadamard(wires=0)), + ], +) +def test_translate_hamiltonian_observable(expected_braket_H, pl_H): + translated_braket_H = _translate_observable(pl_H) + assert expected_braket_H == translated_braket_H + + +def test_translate_result_type_adjoint_gradient(): + print("not implemented yet") diff --git a/tox.ini b/tox.ini index b2530016..dbbdf874 100644 --- a/tox.ini +++ b/tox.ini @@ -89,6 +89,4 @@ commands = [test-deps] deps = # If you need to test on a certain branch, add @ after.git - git+https://github.com/aws/amazon-braket-schemas-python.git - git+https://github.com/aws/amazon-braket-default-simulator-python.git git+https://github.com/aws/amazon-braket-sdk-python.git From ce86881161fd1bbf531e34d28b1ffd7d0b816cd0 Mon Sep 17 00:00:00 2001 From: Aaron Berdy Date: Wed, 7 Dec 2022 11:43:14 -0800 Subject: [PATCH 02/34] fix: remove env variable from integ tests (#117) --- test/integ_tests/test_adjoint_gradient.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/integ_tests/test_adjoint_gradient.py b/test/integ_tests/test_adjoint_gradient.py index 9973238c..db97a654 100644 --- a/test/integ_tests/test_adjoint_gradient.py +++ b/test/integ_tests/test_adjoint_gradient.py @@ -15,15 +15,12 @@ """Tests that gradients are correctly computed in the plugin device via braket""" import math -import os import random import pennylane as qml import pytest from pennylane import numpy as np -os.environ["BRAKET_ENDPOINT"] = "https://braket-gamma.us-west-2.amazonaws.com" -os.environ["AWS_REGION"] = "us-west-2" ABS_TOLERANCE = 1e-5 From 63b5a85c40ae5838b082425529320da0594bbb7f Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 7 Dec 2022 20:01:44 +0000 Subject: [PATCH 03/34] prepare release v1.10.0 --- CHANGELOG.md | 10 ++++++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf88e06..0cb399c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.10.0 (2022-12-07) + +### Features + + * adjoint gradient + +### Bug Fixes and Other Changes + + * remove env variable from integ tests + ## v1.9.0 (2022-09-21) ### Features diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 03729ff0..8ec7a8bd 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.9.1.dev0" +__version__ = "1.10.0" From ff461282f45c114663b0ffc4fd6a3867667b4871 Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 7 Dec 2022 20:01:44 +0000 Subject: [PATCH 04/34] update development version to v1.10.1.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 8ec7a8bd..b84f6ebc 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.0" +__version__ = "1.10.1.dev0" From f61d4db255f903e48db35c8fcc8c0bace10e7f7c Mon Sep 17 00:00:00 2001 From: Katharine Hyatt <67932820+kshyatt-aws@users.noreply.github.com> Date: Wed, 7 Dec 2022 15:41:55 -0500 Subject: [PATCH 05/34] Workaround for np.tensor around observable (#118) * Workaround for np.tensor around observable Co-authored-by: Aaron Berdy --- src/braket/pennylane_plugin/translation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/braket/pennylane_plugin/translation.py b/src/braket/pennylane_plugin/translation.py index da800ab4..44c39b43 100644 --- a/src/braket/pennylane_plugin/translation.py +++ b/src/braket/pennylane_plugin/translation.py @@ -398,6 +398,10 @@ def get_adjoint_gradient_result_type( if "AdjointGradient" not in supported_result_types: raise NotImplementedError("Unsupported return type: AdjointGradient") braket_observable = _translate_observable(observable) + + braket_observable = ( + braket_observable.item() if hasattr(braket_observable, "item") else braket_observable + ) return AdjointGradient(observable=braket_observable, target=targets, parameters=parameters) From fc56cc050fd94700b08257631f8052f2e7404846 Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 7 Dec 2022 21:01:14 +0000 Subject: [PATCH 06/34] prepare release v1.10.1 --- CHANGELOG.md | 6 ++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb399c7..1472a94d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.10.1 (2022-12-07) + +### Bug Fixes and Other Changes + + * Workaround for np.tensor around observable + ## v1.10.0 (2022-12-07) ### Features diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index b84f6ebc..9a9033d5 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.1.dev0" +__version__ = "1.10.1" From 0c74b50bcdd484f2fdf926a8540a3e15f5aa34d1 Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 7 Dec 2022 21:01:14 +0000 Subject: [PATCH 07/34] update development version to v1.10.2.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 9a9033d5..3af96bd3 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.1" +__version__ = "1.10.2.dev0" From f22ad7a422702fe690e54dd43cba2f5c6a9c3fbc Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Thu, 8 Dec 2022 11:20:13 -0800 Subject: [PATCH 08/34] fix: Only support adjoint gradient if shots=0 (#119) Right now, `BraketAwsQubitDevice` will _always_ calculate gradients with the adjoint method if the underlying device supports it, even when shots>0; this doesn't work because the adjoint gradient only makes sense for shots=0. This commit tightens the adjoint gradient support check to include shots=0. --- src/braket/pennylane_plugin/braket_device.py | 2 +- test/unit_tests/test_braket_device.py | 23 +++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index 60dbf4f1..540f3d01 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -504,7 +504,7 @@ def capabilities(self=None): capabilities = BraketQubitDevice.capabilities().copy() # if this method is called as a class method, don't add provides_jacobian since # we don't know if the device is sv1 - if self and "AdjointGradient" in self._braket_result_types: + if self and "AdjointGradient" in self._braket_result_types and not self.shots: capabilities.update(provides_jacobian=True) return capabilities diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index cf13a0d4..2e1a36bd 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -1246,9 +1246,26 @@ def test_capabilities_class_and_instance_method(): "supports_inverse_operations": True, } assert class_caps == expected_caps - # the instance should have provides_jacobian because AdjointGradient is in the - # supported result types - expected_caps["provides_jacobian"] = True + # the instance should not have provides_jacobian, even though AdjointGradient is in the + # supported result types, because shots != 0 + assert instance_caps == expected_caps + + +def test_capabilities_adjoint_shots_0(): + instance_caps = _aws_device( + wires=2, device_type=AwsDeviceType.SIMULATOR, shots=0 + ).capabilities() + expected_caps = { + "model": "qubit", + "supports_broadcasting": False, + "supports_finite_shots": True, + "supports_tensor_observables": True, + "returns_probs": True, + "supports_inverse_operations": True, + # the instance should have provides_jacobian because AdjointGradient is in the + # supported result types and shots == 0 + "provides_jacobian": True, + } assert instance_caps == expected_caps From db6f4d7001d6d5bfb6a8def08288efc8cbbbbad9 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 8 Dec 2022 19:50:40 +0000 Subject: [PATCH 09/34] prepare release v1.10.2 --- CHANGELOG.md | 6 ++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1472a94d..b2d68075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.10.2 (2022-12-08) + +### Bug Fixes and Other Changes + + * Only support adjoint gradient if shots=0 + ## v1.10.1 (2022-12-07) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 3af96bd3..434666f6 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.2.dev0" +__version__ = "1.10.2" From 1f463862c410acc6800ca9aa6cbd606285d3b1e8 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 8 Dec 2022 19:50:40 +0000 Subject: [PATCH 10/34] update development version to v1.10.3.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 434666f6..fa0a5de8 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.2" +__version__ = "1.10.3.dev0" From c7356ffed50399ba11552da832a1557229899f55 Mon Sep 17 00:00:00 2001 From: Jacob Feldman Date: Thu, 8 Dec 2022 16:03:18 -0800 Subject: [PATCH 11/34] fix: integrated with pl's device.use_grouping to fix a bug with qaoa creating multiple observables --- setup.py | 1 + src/braket/pennylane_plugin/braket_device.py | 19 +++- test/integ_tests/conftest.py | 5 + test/integ_tests/qchem/co2.xyz | 5 + test/integ_tests/test_adjoint_gradient.py | 37 +++++++ test/unit_tests/test_braket_device.py | 109 ++++++++++++++++++- 6 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 test/integ_tests/qchem/co2.xyz diff --git a/setup.py b/setup.py index cd7f94a8..2868b737 100644 --- a/setup.py +++ b/setup.py @@ -61,6 +61,7 @@ "tox", "tensorflow>=2.6.0", "torch>=1.11", + "openfermionpyscf", ] }, url="https://github.com/aws/amazon-braket-pennylane-plugin-python", diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index 540f3d01..5da29cfe 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -125,6 +125,8 @@ def operations(self) -> FrozenSet[str]: @property def observables(self) -> FrozenSet[str]: base_observables = frozenset(super().observables) + # This needs to be here bc expectation(ax+by)== a*expectation(x)+b*expectation(y) + # is only true when shots=0 if not self.shots: return base_observables.union({"Hamiltonian"}) return base_observables @@ -166,12 +168,7 @@ def _apply_gradient_result_type(self, circuit, braket_circuit): if len(circuit.observables) != 1: raise ValueError( f"Braket can only compute gradients for circuits with a single expectation" - f" observable, not {len(circuit.observables)} observables. If your QNode " - f"returns the expval of a single Hamiltonian observable and you're still seeing " - f"this error, try recreating H = qml.Hamiltonian(H.coeffs, H.ops) before " - f"returning expval(H). PennyLane transforms Hamiltonian observables if a grouping" - f" is set, and this clears any grouping. See " - f"https://docs.aws.amazon.com/braket/latest/developerguide/hybrid.html for more." + f" observable, not {len(circuit.observables)} observables." ) pl_observable = circuit.observables[0] if pl_observable.return_type != Expectation: @@ -438,6 +435,16 @@ def __init__( self._max_connections = max_connections self._max_retries = max_retries + @property + def use_grouping(self) -> bool: + # We *need* to do this because AdjointGradient doesn't support multiple + # observables and grouping converts single Hamiltonian observables into + # multiple tensor product observables, which breaks AG. + # We *can* do this without fear because grouping is only beneficial when + # shots!=0, and (conveniently) AG is only supported when shots=0 + caps = self.capabilities() + return not ("provides_jacobian" in caps and caps["provides_jacobian"]) + @property def parallel(self): return self._parallel diff --git a/test/integ_tests/conftest.py b/test/integ_tests/conftest.py index 44ae08f3..222f0a45 100755 --- a/test/integ_tests/conftest.py +++ b/test/integ_tests/conftest.py @@ -86,6 +86,11 @@ # pytest fixtures +@pytest.fixture +def qchem_data_dir(): + return os.path.join(os.path.dirname(__file__), "qchem") + + @pytest.fixture def s3(): """ diff --git a/test/integ_tests/qchem/co2.xyz b/test/integ_tests/qchem/co2.xyz new file mode 100644 index 00000000..9bda6175 --- /dev/null +++ b/test/integ_tests/qchem/co2.xyz @@ -0,0 +1,5 @@ +3 +280 +O 3.73200 0.50000 0.00000 +O 2.00000 -0.50000 0.00000 +C 2.86600 0.00000 0.00000 diff --git a/test/integ_tests/test_adjoint_gradient.py b/test/integ_tests/test_adjoint_gradient.py index db97a654..9d0770d7 100644 --- a/test/integ_tests/test_adjoint_gradient.py +++ b/test/integ_tests/test_adjoint_gradient.py @@ -15,11 +15,14 @@ """Tests that gradients are correctly computed in the plugin device via braket""" import math +import os import random +import warnings import pennylane as qml import pytest from pennylane import numpy as np +from pennylane import qchem ABS_TOLERANCE = 1e-5 @@ -134,3 +137,37 @@ def circuit(x, y, z): z = np.array(0.3, requires_grad=True) qml.grad(circuit)(x, y, z) + + def test_qaoa_grad(self, on_demand_sv_device, qchem_data_dir): + """Tests that qchem + qaoa""" + n_electrons = 2 + symbols, coordinates = qchem.read_structure(os.path.join(qchem_data_dir, "co2.xyz")) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + H, qubits = qchem.molecular_hamiltonian( + symbols, coordinates, method="pyscf", active_electrons=n_electrons, name="co2" + ) + + hf_state = qchem.hf_state(n_electrons, qubits) + # generate single- and double-excitations + _, doubles = qchem.excitations(n_electrons, qubits) + + dev = on_demand_sv_device(qubits) + + @qml.qnode(dev) + def circuit_1(params, excitations): + qml.BasisState(hf_state, wires=H.wires) + for i, excitation in enumerate(excitations): + if len(excitation) == 4: + qml.DoubleExcitation(params[i], wires=excitation) + else: + qml.SingleExcitation(params[i], wires=excitation) + return qml.expval(H) + + circuit_gradient = qml.grad(circuit_1, argnum=0) + params = [0.0] * len(doubles) + # the goal of this test is that the following lines don't throw an error + # if use_grouping is True, the gradient computation will fail because + # braket doesn't support gradient computation with multiple observables. + assert not dev.use_grouping + circuit_gradient(params, excitations=doubles) diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 2e1a36bd..7d0f25de 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -516,6 +516,111 @@ def test_execute_tracker(mock_run): callback.assert_called_with(latest=latest, history=history, totals=totals) +def _noop(*args, **kwargs): + return None + + +@patch.object(AwsDevice, "__init__", _noop) +@patch.object(AwsDevice, "aws_session", new_callable=mock.PropertyMock) +@patch.object(AwsDevice, "type", new_callable=mock.PropertyMock) +@patch.object(AwsDevice, "properties") +@pytest.mark.parametrize( + "action_props, shots, expected_use_grouping", + [ + ( + OpenQASMDeviceActionProperties.parse_raw( + json.dumps( + { + "actionType": "braket.ir.openqasm.program", + "version": ["1"], + "supportedOperations": ["rx", "ry", "h", "cy", "cnot", "unitary"], + "supportedResultTypes": [ + { + "name": "StateVector", + "observables": None, + "minShots": 0, + "maxShots": 0, + }, + ], + } + ) + ), + 0, + True, + ), + ( + OpenQASMDeviceActionProperties.parse_raw( + json.dumps( + { + "actionType": "braket.ir.openqasm.program", + "version": ["1"], + "supportedOperations": ["rx", "ry", "h", "cy", "cnot", "unitary"], + "supportedResultTypes": [ + { + "name": "StateVector", + "observables": None, + "minShots": 0, + "maxShots": 0, + }, + { + "name": "AdjointGradient", + "observables": ["x", "y", "z", "h", "i"], + "minShots": 0, + "maxShots": 0, + }, + ], + } + ) + ), + 10, + True, + ), + ( + OpenQASMDeviceActionProperties.parse_raw( + json.dumps( + { + "actionType": "braket.ir.openqasm.program", + "version": ["1"], + "supportedOperations": ["rx", "ry", "h", "cy", "cnot", "unitary"], + "supportedResultTypes": [ + { + "name": "StateVector", + "observables": None, + "minShots": 0, + "maxShots": 0, + }, + { + "name": "AdjointGradient", + "observables": ["x", "y", "z", "h", "i"], + "minShots": 0, + "maxShots": 0, + }, + ], + } + ) + ), + 0, + # Should be disabled only when AdjGrad is present and shots = 0 + False, + ), + ], +) +def test_use_grouping( + properties_mock, type_mock, session_mock, action_props, shots, expected_use_grouping +): + """Tests that grouping is enabled except when AdjointGradient is present""" + properties_mock.action = {DeviceActionType.OPENQASM: action_props} + properties_mock.return_value.action.return_value = {DeviceActionType.OPENQASM: action_props} + type_mock.return_value = AwsDeviceType.SIMULATOR + device = BraketAwsQubitDevice( + wires=1, + device_arn=DEVICE_ARN, + aws_session=Mock(), + shots=shots, + ) + assert device.use_grouping == expected_use_grouping + + def test_pl_to_braket_circuit(): """Tests that a PennyLane circuit is correctly converted into a Braket circuit""" dev = _aws_device(wires=2, foo="bar") @@ -1269,10 +1374,6 @@ def test_capabilities_adjoint_shots_0(): assert instance_caps == expected_caps -def _noop(*args, **kwargs): - return None - - class DummyLocalQubitDevice(BraketQubitDevice): short_name = "dummy" From 19d6f11b22b6663634c91a43ca672539754340d6 Mon Sep 17 00:00:00 2001 From: Jacob Feldman Date: Fri, 9 Dec 2022 10:55:27 -0800 Subject: [PATCH 12/34] removed qaoa integ test since it won't build on windows --- setup.py | 1 - test/integ_tests/conftest.py | 5 ---- test/integ_tests/qchem/co2.xyz | 5 ---- test/integ_tests/test_adjoint_gradient.py | 34 ----------------------- 4 files changed, 45 deletions(-) delete mode 100644 test/integ_tests/qchem/co2.xyz diff --git a/setup.py b/setup.py index 2868b737..cd7f94a8 100644 --- a/setup.py +++ b/setup.py @@ -61,7 +61,6 @@ "tox", "tensorflow>=2.6.0", "torch>=1.11", - "openfermionpyscf", ] }, url="https://github.com/aws/amazon-braket-pennylane-plugin-python", diff --git a/test/integ_tests/conftest.py b/test/integ_tests/conftest.py index 222f0a45..44ae08f3 100755 --- a/test/integ_tests/conftest.py +++ b/test/integ_tests/conftest.py @@ -86,11 +86,6 @@ # pytest fixtures -@pytest.fixture -def qchem_data_dir(): - return os.path.join(os.path.dirname(__file__), "qchem") - - @pytest.fixture def s3(): """ diff --git a/test/integ_tests/qchem/co2.xyz b/test/integ_tests/qchem/co2.xyz deleted file mode 100644 index 9bda6175..00000000 --- a/test/integ_tests/qchem/co2.xyz +++ /dev/null @@ -1,5 +0,0 @@ -3 -280 -O 3.73200 0.50000 0.00000 -O 2.00000 -0.50000 0.00000 -C 2.86600 0.00000 0.00000 diff --git a/test/integ_tests/test_adjoint_gradient.py b/test/integ_tests/test_adjoint_gradient.py index 9d0770d7..b5e2da59 100644 --- a/test/integ_tests/test_adjoint_gradient.py +++ b/test/integ_tests/test_adjoint_gradient.py @@ -137,37 +137,3 @@ def circuit(x, y, z): z = np.array(0.3, requires_grad=True) qml.grad(circuit)(x, y, z) - - def test_qaoa_grad(self, on_demand_sv_device, qchem_data_dir): - """Tests that qchem + qaoa""" - n_electrons = 2 - symbols, coordinates = qchem.read_structure(os.path.join(qchem_data_dir, "co2.xyz")) - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - H, qubits = qchem.molecular_hamiltonian( - symbols, coordinates, method="pyscf", active_electrons=n_electrons, name="co2" - ) - - hf_state = qchem.hf_state(n_electrons, qubits) - # generate single- and double-excitations - _, doubles = qchem.excitations(n_electrons, qubits) - - dev = on_demand_sv_device(qubits) - - @qml.qnode(dev) - def circuit_1(params, excitations): - qml.BasisState(hf_state, wires=H.wires) - for i, excitation in enumerate(excitations): - if len(excitation) == 4: - qml.DoubleExcitation(params[i], wires=excitation) - else: - qml.SingleExcitation(params[i], wires=excitation) - return qml.expval(H) - - circuit_gradient = qml.grad(circuit_1, argnum=0) - params = [0.0] * len(doubles) - # the goal of this test is that the following lines don't throw an error - # if use_grouping is True, the gradient computation will fail because - # braket doesn't support gradient computation with multiple observables. - assert not dev.use_grouping - circuit_gradient(params, excitations=doubles) From d1de23fce914bd45589de1e8cb85ca5e3bda5348 Mon Sep 17 00:00:00 2001 From: Jacob Feldman Date: Fri, 9 Dec 2022 11:05:12 -0800 Subject: [PATCH 13/34] fixing linters --- test/integ_tests/test_adjoint_gradient.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/integ_tests/test_adjoint_gradient.py b/test/integ_tests/test_adjoint_gradient.py index b5e2da59..db97a654 100644 --- a/test/integ_tests/test_adjoint_gradient.py +++ b/test/integ_tests/test_adjoint_gradient.py @@ -15,14 +15,11 @@ """Tests that gradients are correctly computed in the plugin device via braket""" import math -import os import random -import warnings import pennylane as qml import pytest from pennylane import numpy as np -from pennylane import qchem ABS_TOLERANCE = 1e-5 From 67723cce20e509f079d824ae4f5bea0da343e893 Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 13 Dec 2022 16:16:38 +0000 Subject: [PATCH 14/34] prepare release v1.10.3 --- CHANGELOG.md | 9 +++++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d68075..60134ba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v1.10.3 (2022-12-13) + +### Bug Fixes and Other Changes + + * Merge pull request #120 from aws/qaoa_bug_fix + * fixing linters + * removed qaoa integ test since it won't build on windows + * integrated with pl's device.use_grouping to fix a bug with qaoa creating multiple observables + ## v1.10.2 (2022-12-08) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index fa0a5de8..c9cc7e67 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.3.dev0" +__version__ = "1.10.3" From 5ead8b684d76a3fd7bca3d858b9f7ae7f4a3480a Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 13 Dec 2022 16:16:38 +0000 Subject: [PATCH 15/34] update development version to v1.10.4.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index c9cc7e67..6d090028 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.3" +__version__ = "1.10.4.dev0" From 3be9716e56d98554ebb58203396e09f218c672df Mon Sep 17 00:00:00 2001 From: Milan Krneta Date: Tue, 13 Dec 2022 09:15:05 -0800 Subject: [PATCH 16/34] testing python 3.10 --- .github/workflows/python-package.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index ed3ebdcb..afc83dbf 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.7, 3.8, 3.9] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 From 158ed73647d168825aabab7face252a01ec423e5 Mon Sep 17 00:00:00 2001 From: "Tim (Yi-Ting)" Date: Tue, 3 Jan 2023 16:32:33 -0500 Subject: [PATCH 17/34] fix: Cap pennylane version at v0.27 (#124) --- setup.py | 2 +- test/unit_tests/test_braket_device.py | 48 ++++++++++----------------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/setup.py b/setup.py index cd7f94a8..b926693f 100644 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ package_dir={"": "src"}, install_requires=[ "amazon-braket-sdk>=1.35.0", - "pennylane>=0.25.1", + "pennylane>=0.25.1,<=0.27.0", ], entry_points={ "pennylane.plugins": [ diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 7d0f25de..1bbb2100 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -346,16 +346,12 @@ def test_execute(mock_run): }, }, ], - np.tensor( - [ - [ - np.tensor([0.0], requires_grad=True), - np.tensor([-0.194399, 0.9316158], requires_grad=True), - ] - ], - dtype=object, - requires_grad=True, - ), + [ + ( + np.tensor([0.0], requires_grad=True), + np.tensor([-0.194399, 0.9316158], requires_grad=True), + ) + ], ), ( CIRCUIT_2, @@ -385,16 +381,12 @@ def test_execute(mock_run): }, }, ], - np.tensor( - [ - [ - np.tensor([0.0], requires_grad=True), - np.tensor([-0.01894799, 0.9316158], requires_grad=True), - ] - ], - dtype=object, - requires_grad=True, - ), + [ + ( + np.tensor([0.0], requires_grad=True), + np.tensor([-0.01894799, 0.9316158], requires_grad=True), + ) + ], ), ( CIRCUIT_3, @@ -426,16 +418,12 @@ def test_execute(mock_run): }, }, ], - np.tensor( - [ - [ - np.tensor([0.0], requires_grad=True), - np.tensor([-0.01894799, 0.9316158], requires_grad=True), - ] - ], - dtype=object, - requires_grad=True, - ), + [ + ( + np.tensor([0.0], requires_grad=True), + np.tensor([-0.01894799, 0.9316158], requires_grad=True), + ) + ], ), ], ) From 3f65f375288f759985926ffd190267e09a7da913 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 4 Jan 2023 06:35:20 +0800 Subject: [PATCH 18/34] infra: Use the new Pennylane Sphinx Theme (#113) --- doc/_templates/autosummary/base.rst | 5 - doc/_templates/autosummary/class.rst | 86 - doc/_templates/autosummary/module.rst | 40 - doc/_templates/autosummary_core/base.rst | 10 - doc/_templates/autosummary_core/class.rst | 93 - doc/_templates/autosummary_core/module.rst | 42 - doc/conf.py | 55 +- doc/directives.py | 88 - doc/index.rst | 4 +- doc/requirements.txt | 1 + doc/xanadu_theme/LICENSE | 20 - doc/xanadu_theme/comments.html | 16 - doc/xanadu_theme/footer.html | 74 - doc/xanadu_theme/globaltoc.html | 20 - doc/xanadu_theme/header.html | 67 - doc/xanadu_theme/layout.html | 302 --- doc/xanadu_theme/localtoc.html | 33 - doc/xanadu_theme/logo-text.html | 0 doc/xanadu_theme/search.html | 33 - doc/xanadu_theme/searchbox.html | 13 - doc/xanadu_theme/sourcelink.html | 30 - doc/xanadu_theme/static/css/nanoscroller.css | 55 - doc/xanadu_theme/static/tomorrow.css | 65 - doc/xanadu_theme/static/tomorrow_night.css | 67 - doc/xanadu_theme/static/xanadu.css_t | 2286 ------------------ doc/xanadu_theme/theme.conf | 44 - 26 files changed, 12 insertions(+), 3537 deletions(-) delete mode 100644 doc/_templates/autosummary/base.rst delete mode 100644 doc/_templates/autosummary/class.rst delete mode 100644 doc/_templates/autosummary/module.rst delete mode 100644 doc/_templates/autosummary_core/base.rst delete mode 100644 doc/_templates/autosummary_core/class.rst delete mode 100644 doc/_templates/autosummary_core/module.rst delete mode 100644 doc/directives.py delete mode 100644 doc/xanadu_theme/LICENSE delete mode 100644 doc/xanadu_theme/comments.html delete mode 100644 doc/xanadu_theme/footer.html delete mode 100644 doc/xanadu_theme/globaltoc.html delete mode 100644 doc/xanadu_theme/header.html delete mode 100644 doc/xanadu_theme/layout.html delete mode 100644 doc/xanadu_theme/localtoc.html delete mode 100644 doc/xanadu_theme/logo-text.html delete mode 100644 doc/xanadu_theme/search.html delete mode 100644 doc/xanadu_theme/searchbox.html delete mode 100644 doc/xanadu_theme/sourcelink.html delete mode 100644 doc/xanadu_theme/static/css/nanoscroller.css delete mode 100644 doc/xanadu_theme/static/tomorrow.css delete mode 100644 doc/xanadu_theme/static/tomorrow_night.css delete mode 100644 doc/xanadu_theme/static/xanadu.css_t delete mode 100644 doc/xanadu_theme/theme.conf diff --git a/doc/_templates/autosummary/base.rst b/doc/_templates/autosummary/base.rst deleted file mode 100644 index b7556ebf..00000000 --- a/doc/_templates/autosummary/base.rst +++ /dev/null @@ -1,5 +0,0 @@ -{{ fullname | escape | underline}} - -.. currentmodule:: {{ module }} - -.. auto{{ objtype }}:: {{ objname }} diff --git a/doc/_templates/autosummary/class.rst b/doc/_templates/autosummary/class.rst deleted file mode 100644 index e758e7a6..00000000 --- a/doc/_templates/autosummary/class.rst +++ /dev/null @@ -1,86 +0,0 @@ -{{ fullname }} -{{ underline }} - -.. autoclass:: {{ fullname }} - :show-inheritance: - - {% if '__init__' in methods %} - {% set caught_result = methods.remove('__init__') %} - {% endif %} - - {% block attributes_documentation %} - {% if attributes %} - - .. raw:: html - - -
- - {% block attributes_summary %} - {% if attributes %} - - .. autosummary:: - :nosignatures: - {% for item in attributes %} - ~{{ name }}.{{ item }} - {%- endfor %} - - {% endif %} - {% endblock %} - - {% for item in attributes %} - .. autoattribute:: {{ item }} - {%- endfor %} - - .. raw:: html - -
- - {% endif %} - {% endblock %} - - {% block methods_documentation %} - {% if methods %} - - .. raw:: html - - -
- - {% block methods_summary %} - {% if methods %} - - .. autosummary:: - {% for item in methods %} - ~{{ name }}.{{ item }} - {%- endfor %} - - {% endif %} - {% endblock %} - - {% for item in methods %} - .. automethod:: {{ item }} - {%- endfor %} - - .. raw:: html - -
- - {% endif %} - {% endblock %} - - .. raw:: html - - diff --git a/doc/_templates/autosummary/module.rst b/doc/_templates/autosummary/module.rst deleted file mode 100644 index bfdf25e7..00000000 --- a/doc/_templates/autosummary/module.rst +++ /dev/null @@ -1,40 +0,0 @@ -{{ fullname | escape | underline}} - -.. automodule:: {{ fullname }} - - {% block classes %} - {% if classes %} - .. rubric:: Classes - - .. autosummary:: - :toctree: - - {% for item in classes %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block functions %} - {% if functions %} - .. rubric:: Functions - - .. autosummary:: - :toctree: - - {% for item in functions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block exceptions %} - {% if exceptions %} - .. rubric:: Exceptions - - .. autosummary:: - {% for item in exceptions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} diff --git a/doc/_templates/autosummary_core/base.rst b/doc/_templates/autosummary_core/base.rst deleted file mode 100644 index 9160819e..00000000 --- a/doc/_templates/autosummary_core/base.rst +++ /dev/null @@ -1,10 +0,0 @@ -{% if referencefile %} -.. include:: {{ referencefile }} -{% endif %} - -{{ module }}.{{ objname }} -={% for i in range(module|length) %}={% endfor %}{{ underline }} - -.. currentmodule:: {{ module }} - -.. auto{{ objtype }}:: {{ objname }} diff --git a/doc/_templates/autosummary_core/class.rst b/doc/_templates/autosummary_core/class.rst deleted file mode 100644 index d16ad441..00000000 --- a/doc/_templates/autosummary_core/class.rst +++ /dev/null @@ -1,93 +0,0 @@ -{% if referencefile %} -.. include:: {{ referencefile }} -{% endif %} - - -{{ module }}.{{ objname }} -={% for i in range(module|length) %}={% endfor %}{{ underline }} - -.. currentmodule:: {{ module }} - -.. autoclass:: {{ objname }} - :show-inheritance: - - {% if '__init__' in methods %} - {% set caught_result = methods.remove('__init__') %} - {% endif %} - - {% block attributes_documentation %} - {% if attributes %} - - .. raw:: html - - -
- - {% block attributes_summary %} - {% if attributes %} - - .. autosummary:: - :nosignatures: - {% for item in attributes %} - ~{{ name }}.{{ item }} - {%- endfor %} - - {% endif %} - {% endblock %} - - {% for item in attributes %} - .. autoattribute:: {{ item }} - {%- endfor %} - - .. raw:: html - -
- - {% endif %} - {% endblock %} - - {% block methods_documentation %} - {% if methods %} - - .. raw:: html - - -
- - {% block methods_summary %} - {% if methods %} - - .. autosummary:: - {% for item in methods %} - ~{{ name }}.{{ item }} - {%- endfor %} - - {% endif %} - {% endblock %} - - {% for item in methods %} - .. automethod:: {{ item }} - {%- endfor %} - - .. raw:: html - -
- - {% endif %} - {% endblock %} - - .. raw:: html - - diff --git a/doc/_templates/autosummary_core/module.rst b/doc/_templates/autosummary_core/module.rst deleted file mode 100644 index df2c6353..00000000 --- a/doc/_templates/autosummary_core/module.rst +++ /dev/null @@ -1,42 +0,0 @@ -{% if referencefile %} -.. include:: {{ referencefile }} -{% endif %} - - -{{ module }}.{{ objname }} -={% for i in range(module|length) %}={% endfor %}{{ underline }} - -.. automodule:: {{ fullname }} - - {% block functions %} - {% if functions %} - .. rubric:: Functions - - .. autosummary:: - {% for item in functions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block classes %} - {% if classes %} - .. rubric:: Classes - - .. autosummary:: - {% for item in classes %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} - - {% block exceptions %} - {% if exceptions %} - .. rubric:: Exceptions - - .. autosummary:: - {% for item in exceptions %} - {{ item }} - {%- endfor %} - {% endif %} - {% endblock %} diff --git a/doc/conf.py b/doc/conf.py index 9786179e..e23b914a 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -17,6 +17,8 @@ import re import sys +from pennylane_sphinx_theme import templates_dir + # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. @@ -24,8 +26,6 @@ sys.path.insert(0, os.path.abspath("_ext")) sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(".")), "doc")) -from directives import CustomDeviceGalleryItemDirective # noqa: E402 - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -54,7 +54,8 @@ numpydoc_show_class_members = False # Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates", "xanadu_theme"] + +templates_path = [templates_dir()] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -138,7 +139,7 @@ # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -html_favicon = "_static/favicon.ico" +# html_favicon = "_static/favicon.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -172,14 +173,6 @@ # 'donate.html', # ] # } -html_sidebars = { - "**": [ - "logo-text.html", - "searchbox.html", - "globaltoc.html", - # 'sourcelink.html' - ] -} # Additional templates that should be rendered to pages, maps page names to # template names. @@ -231,7 +224,7 @@ htmlhelp_basename = "AmazonBraketPennyLanePlugindoc" # # -- Xanadu theme --------------------------------------------------------- -html_theme = "xanadu_theme" +html_theme = "pennylane" html_theme_path = ["."] # Register the theme as an extension to generate a sitemap.xml @@ -239,35 +232,9 @@ # xanadu theme options (see theme.conf for more information) html_theme_options = { - # Set the path to a special layout to include for the homepage - # "index_template": "special_index.html", - # Set the name of the project to appear in the left sidebar. - "project_nav_name": "PennyLane-Braket", - # Set your Disqus short name to enable comments - # "disqus_comments_shortname": "pennylane-1", - # Set you GA account ID to enable tracking - "google_analytics_account": "UA-130507810-2", - # Path to a touch icon - "touch_icon": "logo_new.png", - # Specify a base_url used to generate sitemap.xml links. If not - # specified, then no sitemap will be built. - # "base_url": "" - # Allow a separate homepage from the master_doc - # "homepage": "index", - # Allow the project link to be overriden to a custom URL. - # "projectlink": "http://myproject.url", - "large_toc": True, - # colors - "navigation_button": "#19b37b", - "navigation_button_hover": "#0e714d", - "toc_caption": "#19b37b", - "toc_hover": "#19b37b", - "table_header_bg": "#edf7f4", - "table_header_border": "#19b37b", - "download_button": "#19b37b", - # gallery options - # "github_repo": "XanaduAI/PennyLane", - # "gallery_dirs": "tutorials", + "navbar_name": "PennyLane-Braket", + "toc_overview": True, + "navbar_active_link": 3, } edit_on_github_project = "aws/amazon-braket-pennylane-plugin-python" @@ -348,7 +315,3 @@ # autodoc_default_flags = ['members'] autosummary_generate = True - - -def setup(app): - app.add_directive("devicegalleryitem", CustomDeviceGalleryItemDirective) diff --git a/doc/directives.py b/doc/directives.py deleted file mode 100644 index 1860eba0..00000000 --- a/doc/directives.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2018-2020 Xanadu Quantum Technologies Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -r""" -Custom sphinx directives -""" -from docutils import nodes -from docutils.parsers.rst import Directive, directives -from docutils.statemachine import StringList - -GALLERY_TEMPLATE = """ -.. raw:: html - - -""" - - -class CustomDeviceGalleryItemDirective(Directive): - """Create a sphinx gallery style thumbnail. - tooltip and figure are self explanatory. Description could be a link to - a document like in below example. - Example usage: - - .. customgalleryitem:: - :name: 'default.qubit' - :description: This is a device - :link: /path/to/device - - """ - - required_arguments = 0 - optional_arguments = 4 - final_argument_whitespace = True - option_spec = { - "name": directives.unchanged, - "description": directives.unchanged, - "link": directives.unchanged, - } - - has_content = False - add_index = False - - def run(self): - try: - if "name" in self.options: - name = self.options["name"] - - if "description" in self.options: - description = self.options["description"] - else: - raise ValueError("description not found") - - if "link" in self.options: - link = self.options["link"] - else: - link = "code/qml_templates" - - except FileNotFoundError as e: - print(e) - return [] - except ValueError as e: - print(e) - raise - return [] - - thumbnail_rst = GALLERY_TEMPLATE.format(name=name, description=description, link=link) - thumbnail = StringList(thumbnail_rst.split("\n")) - thumb = nodes.paragraph() - self.state.nested_parse(thumbnail, self.content_offset, thumb) - return [thumb] diff --git a/doc/index.rst b/doc/index.rst index 0b224cb6..1569dd28 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -22,12 +22,12 @@ Devices This plugin provides two Braket devices for use with PennyLane: -.. devicegalleryitem:: +.. title-card:: :name: 'braket.aws.qubit' :description: Runs circuits on the remote Amazon Braket service. :link: devices/braket_remote.html -.. devicegalleryitem:: +.. title-card:: :name: 'braket.local.qubit' :description: Runs circuits on the Braket SDK's local simulator. :link: devices/braket_local.html diff --git a/doc/requirements.txt b/doc/requirements.txt index 3c42f1b4..c664dc34 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,3 +1,4 @@ sphinx sphinx-automodapi pennylane>=0.23.0 +pennylane-sphinx-theme diff --git a/doc/xanadu_theme/LICENSE b/doc/xanadu_theme/LICENSE deleted file mode 100644 index 3cbe22e7..00000000 --- a/doc/xanadu_theme/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Original work Copyright (c) 2013 Michael Dowling -Modified work Copyright (c) 2018 Xanadu Quantum Technologies Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/doc/xanadu_theme/comments.html b/doc/xanadu_theme/comments.html deleted file mode 100644 index 42a95fb9..00000000 --- a/doc/xanadu_theme/comments.html +++ /dev/null @@ -1,16 +0,0 @@ -{% if theme_disqus_comments_shortname %} -
-
- - - comments powered by Disqus -
-{% endif %} diff --git a/doc/xanadu_theme/footer.html b/doc/xanadu_theme/footer.html deleted file mode 100644 index f5926016..00000000 --- a/doc/xanadu_theme/footer.html +++ /dev/null @@ -1,74 +0,0 @@ - diff --git a/doc/xanadu_theme/globaltoc.html b/doc/xanadu_theme/globaltoc.html deleted file mode 100644 index 71065be9..00000000 --- a/doc/xanadu_theme/globaltoc.html +++ /dev/null @@ -1,20 +0,0 @@ - - diff --git a/doc/xanadu_theme/header.html b/doc/xanadu_theme/header.html deleted file mode 100644 index 88f9c854..00000000 --- a/doc/xanadu_theme/header.html +++ /dev/null @@ -1,67 +0,0 @@ - - - diff --git a/doc/xanadu_theme/layout.html b/doc/xanadu_theme/layout.html deleted file mode 100644 index 573738db..00000000 --- a/doc/xanadu_theme/layout.html +++ /dev/null @@ -1,302 +0,0 @@ -{%- extends "basic/layout.html" %} - -{# Do this so that bootstrap is included before the main css file #} -{%- block htmltitle %} - - - - - - - - - - - - - - - - - - {%- block ga %} - {%- if theme_google_analytics_account %} - - - - {%- endif %} - {%- endblock %} - {{ super() }} -{%- endblock %} - -{# Displays the URL for the homepage if it's set or the master_doc if it is not #} -{% macro homepage() -%} - {%- if theme_homepage %} - {%- if hasdoc(theme_homepage) %} - {{ pathto(theme_homepage) }} - {%- else %} - {{ theme_homepage }} - {%- endif %} - {%- else %} - {{ pathto(master_doc) }} - {%- endif %} -{%- endmacro %} - -{# Displays the URL for the tospage if it's set or falls back to homepage macro #} -{% macro tospage() -%} - {%- if theme_tospage %} - {%- if hasdoc(theme_tospage) %} - {{ pathto(theme_tospage) }} - {%- else %} - {{ theme_tospage }} - {%- endif %} - {%- else %} - {{ homepage() }} - {%- endif %} -{%- endmacro %} - -{# Displays the URL for the projectpage if it's set or falls back to homepage macro #} -{% macro projectlink() -%} - {%- if theme_projectlink %} - {%- if hasdoc(theme_projectlink) %} - {{ pathto(theme_projectlink) }} - {%- else %} - {{ theme_projectlink }} - {%- endif %} - {%- else %} - {{ homepage() }} - {%- endif %} -{%- endmacro %} - -{# Displays the next and previous links both before and after content #} -{% macro render_relations() -%} - {% if prev or next %} - -
- {% endif %} -{%- endmacro %} - -{%- macro guzzle_sidebar() %} -
-
- {%- if sidebars != None %} - {#- new style sidebar: explicitly include/exclude templates #} - {%- for sidebartemplate in sidebars %} - {%- include sidebartemplate %} - {%- endfor %} - {% else %} - {% include "searchbox.html" %} - {% include "globaltoc.html" %} - {%- endif %} -
-
-{%- endmacro %} - -{%- block header -%} - {% include "header.html" %} -{%- endblock %} - -{%- block content %} - - {%- if pagename == 'index' and theme_index_template %} - {% include theme_index_template %} - {%- else %} -
- {%- block sidebar1 %}{{ guzzle_sidebar() }}{% endblock %} - - {%- block document_wrapper %} - {%- block document %} -
-
- {% block breadcrumbs %} -
- -
- {% endblock %} -
- - {% block body %} {% endblock %} -
- {%- block bottom_rel_links %} - {{ render_relations() }} - {%- endblock %} -
- {%- block comments -%} - {% include "localtoc.html" %} - {%- endblock %} - -
-
- - {%- endblock %} - {%- endblock %} - - -
- {%- endif %} - {%- endblock %} - -{%- block footer %} - - - - - - - - - - - - - - - - - - {% include "footer.html" %} -{%- endblock %} diff --git a/doc/xanadu_theme/localtoc.html b/doc/xanadu_theme/localtoc.html deleted file mode 100644 index b527f4aa..00000000 --- a/doc/xanadu_theme/localtoc.html +++ /dev/null @@ -1,33 +0,0 @@ -{%- if pagename != "search" %} -
-
-
-

Contents

- {% set toctree = toctree(maxdepth=3, collapse=True, includehidden=True) %} - {% if display_toc %} - {{ toc | replace("
  • ", "
  • ") - | replace("
      ", "
        ")}} - {% else %} -
        - {{ toctree }} - {% endif %} -
  • - -
    -
    -{%- endif %} \ No newline at end of file diff --git a/doc/xanadu_theme/logo-text.html b/doc/xanadu_theme/logo-text.html deleted file mode 100644 index e69de29b..00000000 diff --git a/doc/xanadu_theme/search.html b/doc/xanadu_theme/search.html deleted file mode 100644 index f2c56e64..00000000 --- a/doc/xanadu_theme/search.html +++ /dev/null @@ -1,33 +0,0 @@ -{%- extends "basic/search.html" %} - -{% block body %} -

    {{ _('Search') }}

    -
    - -

    - {% trans %}Please activate JavaScript to enable the search - functionality.{% endtrans %} -

    -
    -

    - {% trans %} Note that the search function will only return results containing all of the search terms; if you can't find the page you are looking for, try removing some search terms and searching again.{% endtrans %} -

    - {% if search_performed %} -

    {{ _('Search Results') }}

    - {% if not search_results %} -

    {{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}

    - {% endif %} - {% endif %} -
    - {% if search_results %} -
      - {% for href, caption, context in search_results %} -
    • {{ caption }} -
      {{ context|e }}
      -
    • - {% endfor %} -
    - {% endif %} -
    -{% endblock %} - diff --git a/doc/xanadu_theme/searchbox.html b/doc/xanadu_theme/searchbox.html deleted file mode 100644 index 73503c4e..00000000 --- a/doc/xanadu_theme/searchbox.html +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/doc/xanadu_theme/sourcelink.html b/doc/xanadu_theme/sourcelink.html deleted file mode 100644 index e0cb698e..00000000 --- a/doc/xanadu_theme/sourcelink.html +++ /dev/null @@ -1,30 +0,0 @@ -{%- if show_source and has_source and sourcename %} - -{%- endif %} \ No newline at end of file diff --git a/doc/xanadu_theme/static/css/nanoscroller.css b/doc/xanadu_theme/static/css/nanoscroller.css deleted file mode 100644 index 5b2c5229..00000000 --- a/doc/xanadu_theme/static/css/nanoscroller.css +++ /dev/null @@ -1,55 +0,0 @@ -/** initial setup **/ -.nano { - position : relative; - width : 100%; - height : 100%; - overflow : hidden; -} -.nano > .nano-content { - position : absolute; - overflow : scroll; - overflow-x : hidden; - top : 0; - right : 0; - bottom : 0; - left : 0; -} -.nano > .nano-content:focus { - outline: thin dotted; -} -.nano > .nano-content::-webkit-scrollbar { - display: none; -} -.has-scrollbar > .nano-content::-webkit-scrollbar { - display: block; -} -.nano > .nano-pane { - background : rgba(0,0,0,.25); - position : absolute; - width : 10px; - right : 0; - top : 0; - bottom : 0; - visibility : hidden\9; /* Target only IE7 and IE8 with this hack */ - opacity : .01; - -webkit-transition : .2s; - -moz-transition : .2s; - -o-transition : .2s; - transition : .2s; - -moz-border-radius : 5px; - -webkit-border-radius : 5px; - border-radius : 5px; -} -.nano > .nano-pane > .nano-slider { - background: #444; - background: rgba(0,0,0,.5); - position : relative; - margin : 0 1px; - -moz-border-radius : 3px; - -webkit-border-radius : 3px; - border-radius : 3px; -} -.nano:hover > .nano-pane, .nano-pane.active, .nano-pane.flashed { - visibility : visible\9; /* Target only IE7 and IE8 with this hack */ - opacity : 0.99; -} diff --git a/doc/xanadu_theme/static/tomorrow.css b/doc/xanadu_theme/static/tomorrow.css deleted file mode 100644 index f71cd88a..00000000 --- a/doc/xanadu_theme/static/tomorrow.css +++ /dev/null @@ -1,65 +0,0 @@ -.highlight .hll { background-color: #d6d6d6 } -.highlight { background: #ffffff; color: #4d4d4c } -.highlight .c { color: #8e908c } /* Comment */ -.highlight .err { color: #c82829 } /* Error */ -.highlight .k { color: #8959a8 } /* Keyword */ -.highlight .l { color: #f5871f } /* Literal */ -.highlight .n { color: #4d4d4c } /* Name */ -.highlight .o { color: #3e999f } /* Operator */ -.highlight .p { color: #4d4d4c } /* Punctuation */ -.highlight .cm { color: #8e908c } /* Comment.Multiline */ -.highlight .cp { color: #8e908c } /* Comment.Preproc */ -.highlight .c1 { color: #8e908c } /* Comment.Single */ -.highlight .cs { color: #8e908c } /* Comment.Special */ -.highlight .gd { color: #c82829 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gh { color: #4d4d4c; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #718c00 } /* Generic.Inserted */ -/*.highlight .gp { color: #8e908c; font-weight: bold } /* Generic.Prompt */*/ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #3e999f; font-weight: bold } /* Generic.Subheading */ -.highlight .kc { color: #8959a8 } /* Keyword.Constant */ -.highlight .kd { color: #8959a8 } /* Keyword.Declaration */ -.highlight .kn { color: #3e999f } /* Keyword.Namespace */ -.highlight .kp { color: #8959a8 } /* Keyword.Pseudo */ -.highlight .kr { color: #8959a8 } /* Keyword.Reserved */ -.highlight .kt { color: #eab700 } /* Keyword.Type */ -.highlight .ld { color: #718c00 } /* Literal.Date */ -.highlight .m { color: #f5871f } /* Literal.Number */ -.highlight .s { color: #718c00 } /* Literal.String */ -.highlight .na { color: #4271ae } /* Name.Attribute */ -.highlight .nb { color: #4d4d4c } /* Name.Builtin */ -.highlight .nc { color: #eab700 } /* Name.Class */ -.highlight .no { color: #c82829 } /* Name.Constant */ -.highlight .nd { color: #3e999f } /* Name.Decorator */ -.highlight .ni { color: #4d4d4c } /* Name.Entity */ -.highlight .ne { color: #c82829 } /* Name.Exception */ -.highlight .nf { color: #4271ae } /* Name.Function */ -.highlight .nl { color: #4d4d4c } /* Name.Label */ -.highlight .nn { color: #eab700 } /* Name.Namespace */ -.highlight .nx { color: #4271ae } /* Name.Other */ -.highlight .py { color: #4d4d4c } /* Name.Property */ -.highlight .nt { color: #3e999f } /* Name.Tag */ -.highlight .nv { color: #c82829 } /* Name.Variable */ -.highlight .ow { color: #3e999f } /* Operator.Word */ -.highlight .w { color: #4d4d4c } /* Text.Whitespace */ -.highlight .mf { color: #f5871f } /* Literal.Number.Float */ -.highlight .mh { color: #f5871f } /* Literal.Number.Hex */ -.highlight .mi { color: #f5871f } /* Literal.Number.Integer */ -.highlight .mo { color: #f5871f } /* Literal.Number.Oct */ -.highlight .sb { color: #718c00 } /* Literal.String.Backtick */ -.highlight .sc { color: #4d4d4c } /* Literal.String.Char */ -.highlight .sd { color: #8e908c } /* Literal.String.Doc */ -.highlight .s2 { color: #718c00 } /* Literal.String.Double */ -.highlight .se { color: #f5871f } /* Literal.String.Escape */ -.highlight .sh { color: #718c00 } /* Literal.String.Heredoc */ -.highlight .si { color: #f5871f } /* Literal.String.Interpol */ -.highlight .sx { color: #718c00 } /* Literal.String.Other */ -.highlight .sr { color: #718c00 } /* Literal.String.Regex */ -.highlight .s1 { color: #718c00 } /* Literal.String.Single */ -.highlight .ss { color: #718c00 } /* Literal.String.Symbol */ -.highlight .bp { color: #4d4d4c } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #c82829 } /* Name.Variable.Class */ -.highlight .vg { color: #c82829 } /* Name.Variable.Global */ -.highlight .vi { color: #c82829 } /* Name.Variable.Instance */ -.highlight .il { color: #f5871f } /* Literal.Number.Integer.Long */ diff --git a/doc/xanadu_theme/static/tomorrow_night.css b/doc/xanadu_theme/static/tomorrow_night.css deleted file mode 100644 index 73624364..00000000 --- a/doc/xanadu_theme/static/tomorrow_night.css +++ /dev/null @@ -1,67 +0,0 @@ -/*! tomorrow night; https://github.com/MozMorris/tomorrow-pygments */ -/*.highlight, .highlight pre, .highlight table { background: #1d1f21 !important; color: #c5c8c6 !important; }*/ -.highlight .hll { background-color: #373b41 !important; } -.highlight .c { color: #969896 !important; } /* Comment */ -.highlight .err { color: #cc6666 !important; } /* Error */ -.highlight .k { color: #b294bb !important; } /* Keyword */ -.highlight .l { color: #de935f !important; } /* Literal */ -.highlight .n, .highlight .h { color: #c5c8c6 !important; } /* Name */ -.highlight .o { color: #8abeb7 !important; } /* Operator */ -.highlight .p { color: #c5c8c6 !important; } /* Punctuation */ -.highlight .cm { color: #969896 !important; } /* Comment.Multiline */ -.highlight .cp { color: #969896 !important; } /* Comment.Preproc */ -.highlight .c1 { color: #969896 !important; } /* Comment.Single */ -.highlight .cs { color: #969896 !important; } /* Comment.Special */ -.highlight .gd { color: #cc6666 !important; } /* Generic.Deleted */ -.highlight .ge { font-style: italic !important; } /* Generic.Emph */ -.highlight .gh { color: #c5c8c6 !important; font-weight: bold !important; } /* Generic.Heading */ -.highlight .gi { color: #b5bd68 !important; } /* Generic.Inserted */ -.highlight .go { color: #b5bd68 !important; } /* Generic.Inserted */ -/*.highlight .gp { color: #969896 !important; font-weight: bold !important; } /* Generic.Prompt */*/ -.highlight .gs { font-weight: bold !important; } /* Generic.Strong */ -.highlight .gu { color: #8abeb7 !important; font-weight: bold !important; } /* Generic.Subheading */ -.highlight .kc { color: #b294bb !important; } /* Keyword.Constant */ -.highlight .kd { color: #b294bb !important; } /* Keyword.Declaration */ -.highlight .kn { color: #8abeb7 !important; } /* Keyword.Namespace */ -.highlight .kp { color: #b294bb !important; } /* Keyword.Pseudo */ -.highlight .kr { color: #b294bb !important; } /* Keyword.Reserved */ -.highlight .kt { color: #f0c674 !important; } /* Keyword.Type */ -.highlight .ld { color: #b5bd68 !important; } /* Literal.Date */ -.highlight .m { color: #de935f !important; } /* Literal.Number */ -.highlight .s { color: #b5bd68 !important; } /* Literal.String */ -.highlight .na { color: #81a2be !important; } /* Name.Attribute */ -.highlight .nb { color: #c5c8c6 !important; } /* Name.Builtin */ -.highlight .nc { color: #f0c674 !important; } /* Name.Class */ -.highlight .no { color: #cc6666 !important; } /* Name.Constant */ -.highlight .nd { color: #8abeb7 !important; } /* Name.Decorator */ -.highlight .ni { color: #c5c8c6 !important; } /* Name.Entity */ -.highlight .ne { color: #cc6666 !important; } /* Name.Exception */ -.highlight .nf { color: #81a2be !important; } /* Name.Function */ -.highlight .nl { color: #c5c8c6 !important; } /* Name.Label */ -.highlight .nn { color: #f0c674 !important; } /* Name.Namespace */ -.highlight .nx { color: #81a2be !important; } /* Name.Other */ -.highlight .py { color: #c5c8c6 !important; } /* Name.Property */ -.highlight .nt { color: #8abeb7 !important; } /* Name.Tag */ -.highlight .nv { color: #cc6666 !important; } /* Name.Variable */ -.highlight .ow { color: #8abeb7 !important; } /* Operator.Word */ -.highlight .w { color: #c5c8c6 !important; } /* Text.Whitespace */ -.highlight .mf { color: #de935f !important; } /* Literal.Number.Float */ -.highlight .mh { color: #de935f !important; } /* Literal.Number.Hex */ -.highlight .mi { color: #de935f !important; } /* Literal.Number.Integer */ -.highlight .mo { color: #de935f !important; } /* Literal.Number.Oct */ -.highlight .sb { color: #b5bd68 !important; } /* Literal.String.Backtick */ -.highlight .sc { color: #c5c8c6 !important; } /* Literal.String.Char */ -.highlight .sd { color: #969896 !important; } /* Literal.String.Doc */ -.highlight .s2 { color: #b5bd68 !important; } /* Literal.String.Double */ -.highlight .se { color: #de935f !important; } /* Literal.String.Escape */ -.highlight .sh { color: #b5bd68 !important; } /* Literal.String.Heredoc */ -.highlight .si { color: #de935f !important; } /* Literal.String.Interpol */ -.highlight .sx { color: #b5bd68 !important; } /* Literal.String.Other */ -.highlight .sr { color: #b5bd68 !important; } /* Literal.String.Regex */ -.highlight .s1 { color: #b5bd68 !important; } /* Literal.String.Single */ -.highlight .ss { color: #b5bd68 !important; } /* Literal.String.Symbol */ -.highlight .bp { color: #c5c8c6 !important; } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #cc6666 !important; } /* Name.Variable.Class */ -.highlight .vg { color: #cc6666 !important; } /* Name.Variable.Global */ -.highlight .vi { color: #cc6666 !important; } /* Name.Variable.Instance */ -.highlight .il { color: #de935f !important; } /* Literal.Number.Integer.Long */ diff --git a/doc/xanadu_theme/static/xanadu.css_t b/doc/xanadu_theme/static/xanadu.css_t deleted file mode 100644 index b100b9d6..00000000 --- a/doc/xanadu_theme/static/xanadu.css_t +++ /dev/null @@ -1,2286 +0,0 @@ -/* Sphinx themes --------------------------------------------------- */ -@font-face { - font-family: 'Noto Sans'; - font-style: normal; - font-weight: 400; - src: local('Open Sans'), local('OpenSans'), url(https://fonts.gstatic.com/s/productsans/v5/HYvgU2fE2nRJvZ5JFAumwegdm0LZdjqr5-oayXSOefg.woff2) format('woff2'); -} - - - -body { - /*background-color: #edf0f2;*/ - margin: 0; - padding: 0; - font-weight: 400!important; - /*font-family: "Open Sans", Helvetica, Arial, sans-serif;*/ - /*font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;*/ - font-family: Roboto,Noto Sans,"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; - font-size: 15px; - color: #333; - line-height: 1.4; - width: 100%; - min-height: calc(100vh - 90px); -} - -.css-transitions-only-after-page-load * { - -webkit-transition: none !important; - -moz-transition: none !important; - -ms-transition: none !important; - -o-transition: none !important; - transition: none !important; -} - -#left-column { - float: left; - position: fixed; - height: calc(100% - 50px); - min-height: calc(100% - 50px); - width: 300px; - overflow: hidden; - /*box-shadow: 0 0px 0px 0 rgba(0,0,0,.05),0 30px 40px 0px rgba(0,0,0,.2) !important;*/ - border-right: 1px #ddd solid; - background-color: #fff; - z-index: 2000; -} - -#right-column { - position: relative; - padding: 20px 0px 20px 0px; - margin-left: auto; - max-width: 900px; - width: 100%; - height: auto; - margin-right: auto; - border-radius: 20px; - margin-bottom: 100px; - margin-top: 30px; -} - -.page-shadow { - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0), 0 6px 50px 0 rgba(0, 0, 0, 0.19); - border: 0px; -} - -a.headerlink { - visibility: hidden; - color: #ddd; - padding: 0 4px; - text-decoration: none; -} - -a { - color: #2a6496; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -h1 > a, h2 > a, h3 > a, h4 > a, h5 > a, h6 > a { - color: #5C7C98; -} - -h1, h2, h3, h4, h5, h6 { - color: black; - font-weight: normal; - padding: 0; - font-family: 'Noto Sans', 'Roboto', sans-serif!important; -} - -h1, h2, h3 { - margin-top: 30px; - margin-bottom: 20px; -} - -h1 { - font-size: 38px; - padding: 10px 10px 10px 45px; - margin: 20px 0 35px -45px; - /*background-color: #daf0e9;*/ - width: calc(100% + 90px); - /*border-bottom: 3px solid #D8E4EF;*/ - /*border-bottom: 3px solid #eee;*/ - padding-bottom: -29px; -} - -h2 { - margin-top: 40px; - font-size: 28px; - padding: .2em 0; - border-bottom: 1px solid #ddd; -} - -h3 { - margin-top: 35px; - font-size: 24px; -} - -h4 { - margin-top: 30px; - font-size: 20px; -} - -h5 { - margin-top: 25px; - font-size: 18px; -} - -div.clearer { - clear: both; -} - -.container-wrapper { - padding: 0; - position: relative; - margin-top: -29px; - padding-top: 29px; -} - -div.related { - display: none; -} - -p { - padding: 0; - font-family: inherit; - font-size: inherit; - color: #353535; -} - -code { - padding: 2px 0.7px !important; -} - -code, pre, tt { - font-size: 14px; - font-family: Consolas, monospace; -} - -code, tt { - color: #8D1A38 !important; -} - -tt { - padding: 0 2px; -} - -code, pre { - line-height: 23px; - margin: 20px 0; - word-wrap: normal; - background-color: #fff; -} - -pre { - /*color: #c5c8c6;*/ /*tomorrow night*/ - /*background-color: #1d1f21;*/ /*tomorrow night*/ - background-color: #f7f7f7; /*tomorrow*/ - border-color: #f7f7f7; /*tomorrow*/ - overflow: auto; - /*border-width: 0 0 0 2px;*/ - /*border-color: #eee;*/ /*tomorrow night*/ - border-style: solid; - padding: 14px 0 14px 20px; - padding-right: 0; - margin: 20px 0; -} - -div.highlight { - background-color: none !important; -} - -a.internal em { - font-style: normal; -} - -dl dd { - margin: 3px 0 5px 30px; -} - -dl.method, -dl.staticmethod, -dl.classmethod, -dl.attribute { - border-bottom: 1px solid #ccc; - margin-bottom: -30px; -} - -/*dl.class dl:first-of-type { - padding-top: 10px; - border-top: 1px solid #ccc; -}*/ - -dl.method:last-child, -dl.staticmethod:last-child, -dl.classmethod:last-child, -dl.attribute:last-child { - border-bottom: 0px solid #fff; -} - -.breadcrumb { - font-size: 15px; - margin-top: -20px; - background: none; - display: block; - padding: 8px 15px; - list-style: none; - border-radius: 0px; - border-bottom: 1px solid lightgray; -} - -.breadcrumb>li { - display: inline-block -} - -.breadcrumb>li+li:before { - content: "/\00a0"; - padding: 0 5px; - color: #ccc -} - -.breadcrumb>.active { - color: #999 -} - -blockquote { - border-width: .1em 0 .1em 0; - border-color: #e5eef2; - border-style: solid; - background-color: #f3f8f9; - color: #000; - margin: 20px 0; - padding: 15px 20px; - font-size: 16px; -} - -.btn-xanadu { - color: #ffffff; - background-color: {{ theme_navigation_button }}; - border: none; -} - -.btn-xanadu:hover, -.btn-xanadu:focus, -.btn-xanadu:active, -.btn-xanadu.active, -.open .dropdown-toggle.btn-xanadu { - color: #ffffff; - background-color: {{ theme_navigation_button_hover }}; - border: none; -} - -.btn-xanadu:active, -.btn-xanadu.active, -.open .dropdown-toggle.btn-xanadu { - background-image: none; -} - -.btn-xanadu.disabled, -.btn-xanadu[disabled], -fieldset[disabled] .btn-xanadu, -.btn-xanadu.disabled:hover, -.btn-xanadu[disabled]:hover, -fieldset[disabled] .btn-xanadu:hover, -.btn-xanadu.disabled:focus, -.btn-xanadu[disabled]:focus, -fieldset[disabled] .btn-xanadu:focus, -.btn-xanadu.disabled:active, -.btn-xanadu[disabled]:active, -fieldset[disabled] .btn-xanadu:active, -.btn-xanadu.disabled.active, -.btn-xanadu[disabled].active, -fieldset[disabled] .btn-xanadu.active { - background-color: #19B37B; - border: none; -} - -.btn-xanadu .badge { - color: #19B37B; - background-color: #ffffff; -} - -/* References and footnotes --------------------------------------------------- */ - -td.label { - margin-top: 1px; - display: block; - font-size: 100%; - font-weight: bold; - line-height: initial; - color: #000; - text-align: right; - width: 50px; -} - -table.citation { - margin-bottom: 10px; -} - -table.citation td { - padding: 0px 5px !important; -} - -table.citation:target { - background-color: #ffa; -} - -/* Sphinx sidebar --------------------------------------------------- */ - -div.sphinxsidebar { - word-wrap: break-word; - position: absolute; - overflow-y: scroll; - top: 0; - left: 0; - bottom: 0; - right: -20px; - height: 100%; - padding-top: 29px; -} - -div.sphinxsidebar .panel-default > .panel-heading { - background-image: none; -} - -.sidebar-wrapper { - padding: 0 22px; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-weight: normal; - margin: 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 16px; -} - -div.sphinxsidebar p { - margin: 20px 0px 10px 21px; - font-weight: normal; - padding: 0; - font-family: 'Noto Sans', 'Roboto', sans-serif!important; - font-size: 24px; - color: #515151; - /*text-align: center;*/ -} - -div.sphinxsidebar a:hover { - text-decoration: none; -} - -.sidebar-toc { - font-size: 15px; - position: absolute; - width: 300px; -} - -div.sphinxsidebar .sidebar-toc ul { - margin: 0 0 4px 0; - list-style-type: none; - color: #000; -} - -div.sphinxsidebar .sidebar-toc a { - color: #606060; - text-decoration: none; -} - -.sidebar-toc > ul { - padding: 0 !important; - list-style-type: none; - margin: 0; -} - -.sidebar-toc ul li a { - display: block; -} - -.sidebar-toc ul li a:hover { - color: {{ theme_toc_hover }}; -} - -.sidebar-toc > ul li.current { - list-style-type: disc; - margin-left: 25px; - color: {{ theme_toc_hover }}; - font-size: 18px; -} - -.sidebar-toc > ul li.current > a, -.sidebar-toc > ul li.current > a:hover { - /*background-color: #e6e6e6;*/ - background-color: #ddd; - color: #444; - margin-left: -25px; - font-size: 15px; -} - -.sidebar-toc > ul > li.current > a, -.sidebar-toc > ul > li.current > a:hover { - /*background-color: #e6e6e6;*/ - background-color: white; - font-weight: 700; - color: #444; -} - -.sidebar-toc ul li.toctree-l1 a { - padding: 5px 21px; -} - -.sidebar-toc ul li.toctree-l2 a { - padding: 5px 50px; -} - -.sidebar-toc ul li.toctree-l2 { - background-color: #f9f9f9; -} - -.sidebar-toc ul li.toctree-l3 a { - padding: 5px 75px; -} - -div.sphinxsidebar ul.want-points { - padding-left: 20px; - margin: 0; -} - -div.sphinxsidebar .sidebar-toc ul ul { - margin: 0; - padding: 0; -} - -.sidebar-localtoc ul { - padding-left: 24px; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: Helvetica, arial, freesans, clean, sans-serif; - font-size: 1em; -} - -.margin-top-1em { - margin-top: 1em; -} - -.sidebar-block { - padding: 0; - /*margin: 14px 0 30px 0;*/ -} - -.sidebar-block h2 { - border-bottom: none; - margin: 0 0 17px 0; - font-size: 14px; - font-family: "Lato", Helvetica, Arial, sans-serif; - padding: 0 0 6px 0; - font-weight: bold; - text-transform: uppercase; - /*color: #606060;*/ - color: #eee; -} - -.sidebar-block .bd { - font-size: 16px; -} - -/*.sphinxsidebar > .sidebar-block:not(:last-child):after { - content: ''; - display:block; - border-top: 1px solid #333; - margin: 24px 0px 0 0px; -}*/ - -.text-logo { - position: sticky; - top: 0; - overflow: hidden; - font-size: 18px; - height: 190px; - z-index: 1; - text-align: center; - display: block; - padding: 8px; - color: #333; - font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; - margin: 0 0 20px 0; - font-weight: bold; - -o-transition:.5s; - -ms-transition:.5s; - -moz-transition:.5s; - -webkit-transition:.5s; - outline: 1px solid transparent; - transition:.5s; - background-color: #efefef; -} - -.text-logo.active { - height: 150px; -} - -.logo { - opacity: 0; - left: 50%; - transform: translateX(-50%); - position: absolute; - margin-top: 100px; - visibility: hidden; - transition: all 0.6s cubic-bezier(.4,0,.2,1); - outline: 1px solid transparent; -} - -.logo.active { - opacity: 1; - width: 80%; - margin: 0 0 0 0; - visibility: visible; -} - -.logo-small { - width: 70%; - opacity: 0; - position: absolute; - left: 50%; - margin-top: -50px; - transform: translateX(-50%); - transition: all .6s cubic-bezier(.4,0,.2,1); - outline: 1px solid transparent; -} - -.logo-small.active { - opacity: 1; - margin: 0 0 0 0; -} - -.text-logo:hover { - color: #333; - background: {{ theme_logo_hover_bg }}; - text-decoration: none; -} - -#project-name { - font-size: 18px; - text-align: center; - display: block; - padding: 8px; - color: #000; - padding-bottom: 15px; - /*font-variant: unicase;*/ - letter-spacing: 2px; - /*font-variant: all-small-caps;*/ - padding-top: 15px; - margin-top: 0px; - font-weight: bold; -} - -.search-block { - z-index: 1; - margin-top: -30px; - width: 92%; - margin-left: 12px; - /*padding-top: 20px;*/ -} - -.nano .nano-pane { - z-index: 3; - background: none !important; -} - -.nano .nano-slider { - background: rgba(144, 144, 144, 0.5) !important; -} - -/* Left-nav search box --------------------------------------------------- */ -.form-control:focus { - border-color: #119a68; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(66, 164, 94, 0.6); -} - -#main-search form .input-group { - width: 100%; - margin: 0 0 12px 0; - padding: 0; - border: none; - position: unset !important; -} - -#main-search form .input-group input { - padding: 4px; - width: 100%; - border-radius: 20px; - margin: 0; - font-size: 15px; - padding-left: 10px; - padding-right: 10px; -} - -.search-page-form { - width: 350px; -} - -/* Two-pane table list --------------------------------------------------- */ - -.table-bordered>thead>tr>th, -.table-bordered>tbody>tr>th, -.table-bordered>tfoot>tr>th, -.table-bordered>thead>tr>td, -.table-bordered>tbody>tr>td, -.table-bordered>tfoot>tr>td, -table.two-column.table-bordered caption+thead tr:first-child th:first-child, -table.two-column.table-bordered caption+tbody tr:first-child td:first-child, -table.two-column.table-bordered colgroup+thead tr:first-child th:first-child, -table.two-column.table-bordered colgroup+tbody tr:first-child td:first-child, -table.two-column tbody td { - border-collapse: collapse; - border: 0 0 0 0 solid #eee; - border-left: none; - padding: 8px 4px; - font-size: 16px; -} - -table.two-column { - width: 100%; - border: 0px none !important; - box-shadow: none; -} -table td { - font-size: 0.9rem; - font-weight: unset!important; -} -table th { - font-size: 0.9rem; - font-weight: unset!important; -} -td { - padding: 5px; -} -td:first-child { - white-space: nowrap; -} - -.longtable { - border-collapse: collapse; - border: 1px solid #ccc; -} - -.longtable tr.row-odd { - border-bottom: 1px solid #ccc; -} - -.longtable tr.row-even { - border-bottom: 1px solid #ccc; -} - -.longtable tr.row-odd > td { - border-right: 1px solid #ccc; -} - -.longtable tr.row-odd > td ~ td { - border-right: 0px solid #fff; -} -.longtable tr.row-even > td { - border-right: 1px solid #ccc; -} - -.longtable tr.row-even > td ~ td { - border-right: 0px solid #fff; -} - - - -.summary-table { - border-collapse: collapse; - border: 1px solid #fff; -} -.summary-table .longtable { - border: 1px solid #fff; -} - -.summary-table tr.row-odd { - border-bottom: 1px solid #fff; -} - -.summary-table tr.row-even { - border-bottom: 1px solid #fff; -} - -.summary-table tr.row-odd > td { - border-right: 1px solid #fff; -} - -.summary-table tr.row-odd > td ~ td { - border-right: 0px solid #fff; -} -.summary-table tr.row-even > td { - border-right: 1px solid #fff; -} - -.summary-table tr.row-even > td ~ td { - border-right: 0px solid #fff; -} - -.summary-table td { - padding: 0px 25px 1px 5px; - font-size: 0.9rem; -} - -/* Disqus comments styles --------------------------------------------------- */ - -.up-button { - top: 119px; - max-width: 300px; - left: calc(50% - 520px); - font-size: xx-large; - position: fixed; - transition-property: opacity; - transition-duration: 1s; - opacity: 0.5; -} - -.up-button:hover { - transition-property: opacity; - transition-duration: 0.2s; - opacity: 1; - transition-timing-function: linear; -} - -.up-button a { - color: #515151; -} - -.comment-container { - /*margin: 24px auto;*/ - width: 300px; - top: 119px; - max-width: 300px; - right: calc(50% - 820px); - position: fixed; - transition-property: opacity; - transition-duration: 1s; - opacity: 0.5; - height: 100%; -} - -.comment-container:hover { - transition-property: opacity; - transition-duration: 0.2s; - opacity: 1; - transition-timing-function: linear; -} - -.comment-container h3 { - margin-top: 10px; - color: #515151; -} - -#comments > ul:first-of-type > li > a{ - display:none; -} - - -#comments ul > li > ul > li > ul { - margin-top: -7px; - margin-left: 20px; - margin-bottom: -15px; - font-size: smaller; -} - -#comments ul > li > ul > li > ul > li { - margin-bottom: -15px; -} - -#comments a:hover { - text-decoration: none; -} - -#comments { - font-size: 15px; - width: 300px; -} - -#comments ul { - margin: 0 0 10px 0; - list-style-type: none; - color: #000; -} - -#comments a { - font-family: Roboto,Noto Sans,"Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; - /*color: #444;*/ - color: #606060; - text-decoration: none; -} - -#comments p { - font-size: 95%; -} - -#comments ul { - list-style-type: none; - padding: 0!important; -} - -#comments li { - list-style-type: none; - padding-bottom: 10px; -} - - -#comments ul li a { -display: block; -padding: 7px; -border-radius: 7px; -} - -#comments ul li a:hover { - color: {{ theme_download_button }}; -} - -#comments .caption { - display: none; -} - -#comments > ul > li:not(.current) { - display: none; -} - -#comments > ul.current > li.current > a { - display: none; -} - -/* Next and previous links --------------------------------------------------- */ - - -.footer-relations { - font-size: 15px; - display: block; - padding: 20px 40px 0 40px; - border-radius: 0px; - border-top: 1px solid lightgray; -} - -.footer-relations > .pull-left { - display: inline-block; - float: left; -} - -.footer-relations > .pull-right { - display: inline-block; - float: right; -} - -.rel-spacer { - height: 40px; -} - -/* Footer styling --------------------------------------------------- */ - -div.footer { - padding: 25px; - font-size: 14px; - color: #888; - text-align: right; - max-width: 1200px; - width: 100%; - background: white; -} - -div.footer a { - color: #888; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background: url(file.png) no-repeat 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- general index --------------------------------------------------------- */ - -table { - margin-bottom: 20px; -} - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- general body styles --------------------------------------------------- */ - -.body { - padding: 0 45px; -} - -div.body p.caption { - text-align: inherit; -} - -table.field-list { - /*border: 1px solid #ddd;*/ - border-collapse: collapse; - border-spacing: 0; - width: 100%; -} - -table.field-list td, -table.field-list th { - /*border: 1px solid #ddd;*/ - padding: 8px; - vertical-align: top; - line-height: 1.4; -} - -.field-list ul { - padding-left: 1em; -} - -.field-name { - width: 110px; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -div.figure { - padding-bottom: 10px; - padding-top: 10px; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #e8e8e8; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; - background-color: #f8f8f8; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- contents-------------------------------------------------------------- */ - -div.topic.contents { - /*display: inline-block;*/ - border-radius: 3px; - padding: 24px 36px 18px 36px; -} - -div.topic.contents > ul { - padding-left: 20px; - padding-left: 20px; - max-height: 100px; - display: flex; - flex-direction: column; - flex-wrap: wrap; -} - -div.topic.contents > ul > li { - margin-bottom: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -.admonition { - margin: 20px 0; - padding: 20px; - background-color: #fff; - /*border: 1px solid #eee;*/ - border-left-width: 0px; - border-radius: 3px; -} - -.admonition p { - font-weight: inherit; -} - -.admonition dt { - font-weight: bold; -} - -.admonition dl { - margin-bottom: 0; -} - -.admonition-title { - margin: 0px 0 5px; - padding: 0; - font-weight: bold!important; - font-size: 16px; - line-height: 1.1; - font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; -} - -.admonition.danger, -.admonition.error { - border-left-color: #d9534f; - background-color: #ffcdd2; -} - -.admonition.danger .admonition-title, -.admonition.error .admonition-title { - color: #d9534f; -} - -.admonition.important, -.admonition.warning, -.admonition.attention, -.admonition.caution { - border-left-color: #f0ad4e; - background-color: #fff1e3; -} - -.admonition.important .admonition-title, -.admonition.warning .admonition-title, -.admonition.attention .admonition-title, -.admonition.caution .admonition-title { - color: #9B581F; -} - -.admonition-todo .admonition-title { - color: #8e700d; -} - -.admonition.defn { - border-left-color: #119a68; - /*background-color: #daf0e9;*/ - background-color: #fff; -} - -.admonition.defn .admonition-title { - color: #119a68; -} - -.admonition.aside { - border-left-color: #119a68; - background-color: #f8f8f8; -} - -.admonition.aside .admonition-title { - color: #119a68; -} - -.admonition.note, -.admonition.hint { - border-left-color: #31708f; - background-color: #dae1f0; -} - -.admonition.note .admonition-title, -.admonition.hint .admonition-title { - color: #31708f; -} - -.admonition-todo { - border-left-color: #FDD835; - background-color: #fffdf2; -} - -.admonition.tip { - padding: 5px 0 0 24px; - margin-top: -24px; - background-color: #F9F9F9; - border-top: 0px solid #EAEAEA; - border-left-color: #119A68; -} - -.admonition.tip p { - margin: 0; -} - -.admonition.tip .admonition-title { - color: #3c763d; - display: none; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; - padding: 20px 10px 0px 20px; - display: block ruby; -} - - -.admonition.see { - font-style: italic; - margin: -15px 0px 10px 0px; - padding: 5px; - border-color: #ddd white white white; -} - -div.admonition tt.xref, div.admonition a tt { - border-bottom: 1px solid #fafafa; -} - -div.admonition p.last { - margin-bottom: 0; -} - -/* restructured text tables -------------------------- */ - -.docstable { - width: 100%; - max-width: 100%; - margin-bottom: 1rem; - border: 1px solid #fff; -} - - -.docstable th:first-child, -.docstable td:first-child { - text-align: center !important; -} - -.docstable tr.row-even th, -.docstable tr.row-even td{ - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #fff; - border-right: 1px solid #fff; - text-align: left; - vertical-align: middle; -} - -.docstable tr.row-odd th, -.docstable tr.row-odd td { - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #fff; - border-right: 1px solid #eee; - text-align: left; - vertical-align: middle; -} - -.docstable th:last-child, -.docstable td:last-child { - border-right: 1px solid #fff; -} - -.docstable thead th { - vertical-align: bottom; - border-bottom: 2px solid {{ theme_table_header_border }} !important; - border-right: 1px solid {{ theme_table_header_bg }} !important; - background-color: {{ theme_table_header_bg }}; - text-align: center !important; -} - -.docstable tbody + tbody { - border-top: 2px solid #eee; -} - -.docstable .docstable { - background-color: #fff; -} - -.docstable tbody tr:nth-of-type(odd) { - background-color: #fff; -} - -.docstable, -.docstable > th, -.docstable > td { - background-color: #eee; -} - -.docstable p.first { - margin-bottom: 0 !important; -} - -.docstable-nohead tr.row-even th, -.docstable-nohead tr.row-even td{ - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #fff; - border-right: 1px solid #eee; - text-align: center; - vertical-align: middle; -} - -.docstable-nohead tr.row-odd th, -.docstable-nohead tr.row-odd td { - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #fff; - border-right: 1px solid #fff; - text-align: center; - vertical-align: middle; -} - - -/* Gallery tables -------------------------- */ - -.gallery-table { - width: 100%; - max-width: 100%; - margin-bottom: 1rem; - border: 1px solid #fff; -} - -.gallery-table a { - color: #119a68; - font-size: 13pt; -} - -.gallery-table a:hover { - color: #119a68; -} -.gallery-table img { - padding-bottom: 20px; -} - -.gallery-table .gallery-table { - background-color: #fff; -} - -.gallery-table p.first { - margin-bottom: 0 !important; -} - -.gallery-table tr th, -.gallery-table tr td{ - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid #fff; - border-right: 1px solid #fff; - text-align: center; - vertical-align: middle; -} -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -.highlighted { - background-color: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.refcount { - color: #060; -} - -.optional { - font-size: 1.3em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -dt:target, .highlight { - /*background: #fff176 !important*/; /*tomorrow night*/ - background: none !important; -} - -dt:target { - /*background-color: white !important;*/ -} - -dt:target code { - background-color: white !important; - border-bottom: 3px {{theme_download_button}} solid; -} - -.method dt:target, -.attribute dt:target, -.staticmethod dt:target, -.classmethod dt:target - { - padding: 5px; - /*border-radius: 5px;*/ -} - -.exception > dt { - background: #ffebee; - border-radius: 5px; - padding: 5px; -} - -.exception > dt code { - background: #ffebee; -} - -.function > dt { - background: #daf0e9; - border-radius: 5px; - padding: 5px; -} - -.function > dt code { - background: #daf0e9; -} - -.function > dt::before { - content: 'function '; - font-style: italic; -} - -.method > dt::before { - content: 'meth '; - font-style: italic; -} - -.attribute > dt::before { - content: 'attr '; - font-style: italic; -} - -.class > dt { - background: #eee; - border-radius: 5px; - padding: 5px; -} - -.class > dt code { - background: #eee; -} - -/* -- code displays --------------------------------------------------------- */ - -td.linenos pre { - padding: 0px 0px; - border: 0; - background-color: transparent; - color: #aaa; - /*width: 12px;*/ -} - -table.highlighttable { - width: 100%; - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0 0 0; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - padding-right: 0.08em; -} - -tt.descclassname { - background-color: transparent; -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -code.descname { - padding-left: 0; -} - -code.descclassname { - padding-right: 0; -} - -tt.xref, a tt { - background-color: transparent; - font-weight: bold; -} - -h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -/* -- Theme specific classes - */ - -.overflow-height-500px { - overflow: auto; - height: 500px; -} - -.overflow-height-250px { - overflow: auto; - height: 250px; -} - -/* Toggle mobile view --------------------------------------------------- */ - -.social-section { - font-size: 22px; -} - -.footer-heading { - margin-bottom: -10px; - font-size:22px; -} - -.page-footer { - z-index: 0; - background-color: white; - position: relative; - color: black!important; - padding-top: 0!important; - margin-left: 300px; -} - -.page-footer a { - color: #009688!important; - color: #19b37b!important; -} - -.page-footer p { - color: #808080; -} - -footer.page-footer .footer-copyright { - color: #808080!important; - background-color: white!important; - -} -/* Small screen styles --------------------------------------------------- */ - -@media screen and (max-width: 560px) { - .sphx-glr-thumbcontainer { - width: calc(100% / 2.2); - } - - .sphx-glr-thumbcontainer img { - transform: scale(0.8); - } - - .sphx-glr-thumbcontainer .figure { - margin: 0px!important; - } -} - -@media screen and (max-width: 768px) { - - body { - padding: 0px; - margin: 0px; - background-color: #fff; - } - - h1 { - margin-left: 0; - width: 100%; - padding: 10px; - font-size: 40px; - } - - h2 { - margin-top: 20px; - font-size: 26px; - } - - #mobile-toggle { - display: block; - width: 56px; - height: 40px; - display: inline-flex; - align-items: center; - box-shadow: none; - font-size: unset; - padding: unset; - } - - .container-wrapper { - margin-top: -29px; - } - - #left-column { - position: relative; - top: 0; - left: 0; - display: none; - width: 100%; - float: none; - margin-left: 0; - box-shadow: none!important; - } - - .sidebar-toc { - position: relative; - } - - .nano .nano-content { - position: relative; - } - - div.sphinxsidebar { - word-wrap: break-word; - position: relative; - overflow-y: scroll; - top: 0; - left: 0; - bottom: 0; - right: -20px; - height: 100%; - } - - #showsource { - display: none; - } - - .footer-relations { - padding: 12px 10px 12px 10px; - left: 0; - } - - #right-column { - margin-left: 0; - margin-top: -30px; - padding: 50px 20px 80px 20px; - width: 100%; - float: none; - margin-bottom: -25px; - } - - .comment-container { - margin-left: auto; - margin-right: auto; - padding-left: 0; - padding-right: 0; - width: 100%; - position: inherit; - float: none; - margin-top: unset; - margin-bottom: unset; - } - - .comment-container { - display: none; - } - - .document { - position: relative; - padding: 0; - width: 100% - } - - .body { - padding: 0px; - } - - p { - padding: 0; - } - - .xanadu-call-to-action-links { - display: none; - } - - .gallery-grid { - justify-content: center!important; - } - - .nav-item.active { - font-weight: bold; - } - - .nav-item:hover:after, - .nav-item.active:after { - border-bottom: 0px!important; - } - - code, pre, tt { - font-size: 12px; - } - - pre { - padding: 2px 0 2px 2px; - line-height: 20px; - } - - .footer-heading { - font-weight: unset!important; - font-size: 18px!important; - } - - footer.page-footer .footer-copyright { - font-size: x-small; - } - - .page-footer { - margin-left: 0; - } - - -} - -/* Account for when the left column is closed then page is expanded. --------------------------------------------------- */ - -@media screen and (min-width: 768px) { - #left-column { - display: block !important; - } - - #showsource { - display: block !important; - } -} - -@media screen and (max-width: 968px) { - .navbar { - box-shadow: none!important; - border-bottom: 1px #ddd solid; - } - - .nav-item.active { - font-weight: bold; - } - - .nav-item:hover:after, - .nav-item.active:after { - border-bottom: 0px!important; - } -} - -@media screen and (max-width: 1500px) and (min-width: 768px){ - .comment-container { - margin-left: calc(50% - 300px); - padding-left: 0; - padding-right: 0; - max-width: 900px; - width: -webkit-calc(100% - 300px); - width: -moz-calc(100% - 300px); - width: calc(100% - 300px); - position: inherit; - float: left; - margin-top: unset; - margin-bottom: unset; - } - - .container-wrapper { - margin-top: -29px; - } - - .page-footer { - margin-left: 260px; - } - - .xanadu-call-to-action-links { - display: none; - } - - #right-column { - width: -webkit-calc(100% - 260px); - width: -moz-calc(100% - 260px); - width: calc(100% - 260px); - margin: -30px 0 -20px 260px; - padding: 50px 20px 80px 20px; - float: none; - } - - .comment-container { - display: none; - } - - #mobile-toggle { - display: none; - } - - .navbar { - box-shadow: none!important; - border-bottom: 1px #ddd solid; - } - - #left-column { - box-shadow: none!important; - border-right: 1px #ddd solid; - width: 260px; - } -} - -/* Sphinx gallery ------------------------------------------*/ - - -#tutorial-type { - display: none; -} - -.xanadu-call-to-action-links { - /*padding-top: 25px;*/ - /*display: flex;*/ - justify-content: center; -} - -@media (min-width: 1100px) and (max-width: 1239px) { - .xanadu-call-to-action-links { - padding-top: rem(40px); - } - } - -.xanadu-call-to-action-links #tutorial-type { - display: none; - } - -.xanadu-call-to-action-links a { - padding-right: 20px; - color: #000; - cursor: pointer; -} - -.xanadu-call-to-action-links a:hover { - color: #fdb104; - text-decoration: none; -} - -#download-python-link, -#download-notebook-link, -#github-view-link { - padding-bottom: 10px; - /*border-bottom: 1px solid #c3c3c3;*/ - padding-right: 40px; - display: flex; - align-items: center; - color: #747474; -} - -#download-python-link:hover, -#download-notebook-link:hover, -#github-view-link:hover { - /*border-bottom-color: {{ theme_download_button }};*/ - color: {{ theme_download_button }}; -} - -/* Navbar */ - -.section::before { - content: ""; - display: block; - height: 50px; /* fixed header height*/ - margin: -70px 0 0; /* negative fixed header height */ -} - -.navbar { - background-color: white; - z-index: 10000; - box-shadow: -1px 14px 30px -20px rgba(0,0,0,0.3); -} - -.navbar-brand { - padding-bottom: 0px; -} - -.navbar-nav { - padding-bottom: 1px; - padding-left: 30px; -} - - -.navbar .navbar-nav > li { - transition-duration: 0s; - margin-left: 20px; - font-size: initial; - color: black; - font-family: 'Noto Sans', 'Roboto', sans-serif !important; - margin-bottom: -9px; - border-bottom: 3px solid; - border-bottom-color: white; -} - -.nav-item:hover, -.nav-item.active { - position: relative; -} - -.nav-item:hover:after, -.nav-item.active:after { - border-bottom: 3px solid; - content: ""; - border-bottom-color: {{ theme_download_button }}!important; - position: absolute; - bottom: -3px; - width: 80%; - left: 10%; -} - - -.navbar.navbar-light .breadcrumb .nav-item .nav-link, .navbar.navbar-light .navbar-nav .nav-item .nav-link { - color: #000; - transition: 0s; -} - -.nav-link:hover { - color: rgba(0,0,0,.7)!important; -} - -.navbar.navbar-light .breadcrumb .nav-item.active > .nav-link, .navbar.navbar-light .navbar-nav .nav-item.active > .nav-link { - background-color: inherit!important; -} - - - - -.card { - box-shadow: 0 2px 5px 0 rgba(0,0,0,.05),0 2px 25px 2px rgba(0,0,0,.05)!important; - border: 0; - border-radius: 10px!important; - transition-duration: 0.4s; - background-color: white; -} - - -.card:hover { - box-shadow: 0 2px 5px 0 rgba(0,0,0,.05),0 2px 25px 2px rgba(0,0,0,.2)!important; - border: 0; - transition-duration: 0.4s; - border-radius: 10px!important; -} - -/* Input text ------------------------------------------*/ -.md-input { - position:relative; - left: -10px; -} - -.md-input input { - font-size:18px; - padding: 15px 10px 10px 20px; - display:block; - width: 109%; - border:none!important; - border-bottom:1px solid #ddd!important; - font-family: unset; - background-color: #f9f9f9; -} - -.md-input input:focus { - outline:none; -} - -.md-input label { - color: #999; - font-size: 18px; - font-weight: 300; - position: absolute; - pointer-events: none; - left: 20px; - top: 15px; - transition:0.2s ease all; - -moz-transition:0.2s ease all; - -webkit-transition:0.2s ease all; -} - -/* active state */ -.md-input input:focus ~ label, -.md-input input:valid ~ label { - top: 4px; - font-size: 10px; - color: #5264AE; -} - -.md-input input:invalid { - box-shadow: none; -} - -.md-input .bar { - position:relative; - display:block; - width:300px; -} - -.md-input .bar:before, -.md-input .bar:after { - content:''; - height:1px; - width:0; - bottom:1px; - position:absolute; - background: {{ theme_download_button }}; - transition:0.2s ease all; - -moz-transition:0.2s ease all; - -webkit-transition:0.2s ease all; - opacity: 0; -} - -.md-input .bar:before { - left:50%; -} - -.md-input .bar:after { - right:50%; -} - -.md-input input:focus ~ .bar:before, -.md-input input:focus ~ .bar:after { - width:50%; - opacity: 1; -} - -div.body > div > span, -.section > span { - display: block; - position: relative; - top: -40px; - visibility: hidden; -} - -dl.attribute > dt:before, -dl.staticmethod > dt:before, -dl.classmethod > dt:before, -dl.method > dt:before { - content: ''; - display: block; - position: relative; - width: 0; - margin-top: 60px -} - -dl.class { - padding-bottom: 20px; -} - -dl.class dd > .rubric { - margin-top: 60px; -} - -dl.class dd > .rubric:last-of-type { - margin-bottom: -40px; -} - -dl.class > dd > table.docutils { - margin-bottom: -40px; - /*border-bottom: 1px solid lightgray;*/ -} - -dd > .collapse-header:first-of-type > h2 { - /*margin-top: 70px;*/ -} - - -dd > .collapse-header { - margin-top: 60px; -} - -.rotate { - -moz-transition: all .1s linear; - -webkit-transition: all .1s linear; - transition: all .1s linear; -} -.rotate.up { - -moz-transform:rotate(180deg); - -webkit-transform:rotate(180deg); - transform:rotate(180deg); -} - -.o-tooltip--left::after { - top: -2px; - left: -10px; - font-size: 12px; -} - -a.copybtn { - top: 20px; - right: 14px; - opacity: 0.5; - padding: 0; -} -/* Syntax highlighting --------------------------------------------------- */ - -.highlight .hll { background-color: #d6d6d6 !important} -/*.highlight { background: #ffffff; color: #4d4d4c !important}*/ -.highlight .c { color: #8e908c !important} /* Comment */ -.highlight .err { color: #c82829 !important} /* Error */ -.highlight .k { color: #8959a8 !important} /* Keyword */ -.highlight .l { color: #f5871f !important} /* Literal */ -.highlight .n { color: #2d2c2c !important} /* Name */ -.highlight .o { color: #3e999f !important} /* Operator */ -.highlight .p { color: #4d4d4c !important} /* Punctuation */ -.highlight .cm { color: #8e908c !important} /* Comment.Multiline */ -.highlight .cp { color: #8e908c !important} /* Comment.Preproc */ -.highlight .c1 { color: #8e908c !important} /* Comment.Single */ -.highlight .cs { color: #8e908c !important} /* Comment.Special */ -.highlight .gd { color: #c82829 !important} /* Generic.Deleted */ -.highlight .ge { font-style: italic !important} /* Generic.Emph */ -.highlight .gh { color: #4d4d4c; font-weight: bold !important} /* Generic.Heading */ -.highlight .gi { color: #718c00 !important} /* Generic.Inserted */ -/*.highlight .gp { color: #8e908c; font-weight: bold !important} /* Generic.Prompt */*/ -.highlight .gs { font-weight: bold !important} /* Generic.Strong */ -.highlight .gu { color: #3e999f; font-weight: bold !important} /* Generic.Subheading */ -.highlight .kc { color: #8959a8 !important} /* Keyword.Constant */ -.highlight .kd { color: #8959a8 !important} /* Keyword.Declaration */ -.highlight .kn { color: #3e999f !important} /* Keyword.Namespace */ -.highlight .kp { color: #8959a8 !important} /* Keyword.Pseudo */ -.highlight .kr { color: #8959a8 !important} /* Keyword.Reserved */ -.highlight .kt { color: #eab700 !important} /* Keyword.Type */ -.highlight .ld { color: #718c00 !important} /* Literal.Date */ -.highlight .m { color: #d27014 !important} /* Literal.Number */ -.highlight .s { color: #718c00 !important} /* Literal.String */ -.highlight .na { color: #4271ae !important} /* Name.Attribute */ -.highlight .nb { color: #4d4d4c !important} /* Name.Builtin */ -.highlight .nc { color: #eab700 !important} /* Name.Class */ -.highlight .no { color: #c82829 !important} /* Name.Constant */ -.highlight .nd { color: #3e999f !important} /* Name.Decorator */ -.highlight .ni { color: #4d4d4c !important} /* Name.Entity */ -.highlight .ne { color: #c82829 !important} /* Name.Exception */ -.highlight .nf { color: #4271ae !important} /* Name.Function */ -.highlight .nl { color: #4d4d4c !important} /* Name.Label */ -.highlight .nn { color: #B13A59 !important} /* Name.Namespace */ -.highlight .nx { color: #4271ae !important} /* Name.Other */ -.highlight .py { color: #4d4d4c !important} /* Name.Property */ -.highlight .nt { color: #3e999f !important} /* Name.Tag */ -.highlight .nv { color: #c82829 !important} /* Name.Variable */ -.highlight .ow { color: #3e999f !important} /* Operator.Word */ -.highlight .w { color: #4d4d4c !important} /* Text.Whitespace */ -.highlight .mf { color: #d27014 !important} /* Literal.Number.Float */ -.highlight .mh { color: #d27014 !important} /* Literal.Number.Hex */ -.highlight .mi { color: #d27014 !important} /* Literal.Number.Integer */ -.highlight .mo { color: #d27014 !important} /* Literal.Number.Oct */ -.highlight .sb { color: #718c00 !important} /* Literal.String.Backtick */ -.highlight .sc { color: #4d4d4c !important} /* Literal.String.Char */ -.highlight .sd { color: #8e908c !important} /* Literal.String.Doc */ -.highlight .s2 { color: #718c00 !important} /* Literal.String.Double */ -.highlight .se { color: #d27014 !important} /* Literal.String.Escape */ -.highlight .sh { color: #718c00 !important} /* Literal.String.Heredoc */ -.highlight .si { color: #d27014 !important} /* Literal.String.Interpol */ -.highlight .sx { color: #718c00 !important} /* Literal.String.Other */ -.highlight .sr { color: #718c00 !important} /* Literal.String.Regex */ -.highlight .s1 { color: #718c00 !important} /* Literal.String.Single */ -.highlight .ss { color: #718c00 !important} /* Literal.String.Symbol */ -.highlight .bp { color: #4d4d4c !important} /* Name.Builtin.Pseudo */ -.highlight .vc { color: #c82829 !important} /* Name.Variable.Class */ -.highlight .vg { color: #c82829 !important} /* Name.Variable.Global */ -.highlight .vi { color: #c82829 !important} /* Name.Variable.Instance */ -.highlight .il { color: #d27014 !important} /* Literal.Number.Integer.Long */ diff --git a/doc/xanadu_theme/theme.conf b/doc/xanadu_theme/theme.conf deleted file mode 100644 index 5248671e..00000000 --- a/doc/xanadu_theme/theme.conf +++ /dev/null @@ -1,44 +0,0 @@ -[theme] -inherit = basic -stylesheet = xanadu.css - -[options] -# Set to an html template to load custom HTML for the homepage -index_template = -# Set the name of the project to appear in the left sidebar. -project_nav_name = -# set the path to a logo to appear in the left sidebar. -project_logo = -# Path to a touch icon -touch_icon = -# Path to a smaller touch icon -touch_icon_small = -# Set this value to enable Disqus comments -disqus_comments_shortname = -# Set to enable google analytics -google_analytics_account = -# Specify a base_url used to generate sitemap.xml links. If not specified, then -# no sitemap will be built. -base_url = -# Allow a separate homepage from the "master_doc" -homepage = -# Allow the project link to be overwritten to a custom URL. -projectlink = -# if the table of contents is large -large_toc = -# latex macros -latex_macros = - -# the following are custom CSS colors than can be set -navigation_button = #1f9094 -navigation_button_hover = #1c6e71 -toc_caption = #1f9094 -toc_hover = #1f9094 -table_header_bg = #e2f5f6 -table_header_border = #1f9094 -logo_hover_bg = #efefef -download_button = #1f9094 - -# sphinx gallery options -gallery_dirs = -github_repo = From 2d6d07f499a6d2046a5261f3ba6089bda7eee6bc Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 3 Jan 2023 22:52:08 +0000 Subject: [PATCH 19/34] prepare release v1.10.4 --- CHANGELOG.md | 10 ++++++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60134ba4..941acc9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.10.4 (2023-01-03) + +### Bug Fixes and Other Changes + + * Cap pennylane version at v0.27 + +### Testing and Release Infrastructure + + * Use the new Pennylane Sphinx Theme + ## v1.10.3 (2022-12-13) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 6d090028..e3448a6a 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.4.dev0" +__version__ = "1.10.4" From 5d7eedb368d81df9674dfced0e72d731a20ea5bb Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 3 Jan 2023 22:52:08 +0000 Subject: [PATCH 20/34] update development version to v1.10.5.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index e3448a6a..dffc7693 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.4" +__version__ = "1.10.5.dev0" From 8a72493a7ca72fc1065c2fa7214549d45d359904 Mon Sep 17 00:00:00 2001 From: "Tim (Yi-Ting)" Date: Tue, 31 Jan 2023 13:39:08 -0500 Subject: [PATCH 21/34] feat: Braket noise model for density matrix simulators (#123) * feat: DM1 and local dm simulator accept Braket noise model for noise simulation. * clean up * address comments: improve tests and type hints * use device capability to validate noise support * fix: use only pragma to validate supported devices * fix: linters --------- Co-authored-by: Cody Wang --- src/braket/pennylane_plugin/braket_device.py | 25 +++ test/unit_tests/test_braket_device.py | 154 ++++++++++++++++++- 2 files changed, 176 insertions(+), 3 deletions(-) diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index 5da29cfe..73502392 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -41,6 +41,7 @@ from braket.aws import AwsDevice, AwsDeviceType, AwsQuantumTask, AwsQuantumTaskBatch, AwsSession from braket.circuits import Circuit, Instruction +from braket.circuits.noise_model import NoiseModel from braket.device_schema import DeviceActionType from braket.devices import Device, LocalSimulator from braket.simulator import BraketSimulator @@ -82,6 +83,8 @@ class BraketQubitDevice(QubitDevice): shots (int or None): Number of circuit evaluations or random samples included, to estimate expectation values of observables. If this value is set to ``None`` or ``0``, the device runs in analytic mode (calculations will be exact). + noise_model (NoiseModel or None): The Braket noise model to apply to the circuit before + execution. **run_kwargs: Variable length keyword arguments for ``braket.devices.Device.run()`. """ name = "Braket PennyLane plugin" @@ -95,16 +98,21 @@ def __init__( device: Device, *, shots: Union[int, None], + noise_model: Optional[NoiseModel] = None, **run_kwargs, ): super().__init__(wires, shots=shots or None) self._device = device self._circuit = None self._task = None + self._noise_model = noise_model self._run_kwargs = run_kwargs self._supported_ops = supported_operations(self._device) self._check_supported_result_types() + if noise_model: + self._validate_noise_model_support() + def reset(self): super().reset() self._circuit = None @@ -286,6 +294,8 @@ def execute(self, circuit: CircuitGraph, compute_gradient=False, **run_kwargs) - self._circuit = self._pl_to_braket_circuit( circuit, compute_gradient=compute_gradient, **run_kwargs ) + if self._noise_model: + self._circuit = self._noise_model.apply(self._circuit) param_index = 0 param_dict = {} for operation in circuit.operations: @@ -342,6 +352,21 @@ def _check_supported_result_types(self): result_type.name for result_type in supported_result_types ) + def _validate_noise_model_support(self): + supported_pragmas = [ + ops.lower().replace("_", "") + for ops in (self._device.properties.action[DeviceActionType.OPENQASM].supportedPragmas) + ] + noise_pragmas = [ + ("braket_noise_" + noise_instr.noise.name).lower().replace("_", "") + for noise_instr in self._noise_model._instructions + ] + if not all([noise in supported_pragmas for noise in noise_pragmas]): + raise ValueError( + f"{self._device.name} does not support noise or the noise model includes noise " + + f"that is not supported by {self._device.name}." + ) + def _run_task(self, circuit, inputs=None): raise NotImplementedError("Need to implement task runner") diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 1bbb2100..721c741d 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -21,7 +21,8 @@ import pennylane as qml import pytest from braket.aws import AwsDevice, AwsDeviceType, AwsQuantumTask, AwsQuantumTaskBatch -from braket.circuits import Circuit, FreeParameter, Observable, result_types +from braket.circuits import Circuit, FreeParameter, Gate, Noise, Observable, result_types +from braket.circuits.noise_model import GateCriteria, NoiseModel, NoiseModelInstruction from braket.device_schema import DeviceActionType from braket.device_schema.openqasm_device_action_properties import OpenQASMDeviceActionProperties from braket.device_schema.simulators import GateModelSimulatorDeviceCapabilities @@ -58,6 +59,37 @@ ) ) +ACTION_PROPERTIES_DM_DEVICE = OpenQASMDeviceActionProperties.parse_raw( + json.dumps( + { + "actionType": "braket.ir.openqasm.program", + "version": ["1"], + "supportedOperations": ["rx", "ry", "h", "cy", "cnot", "unitary"], + "supportedResultTypes": [ + {"name": "StateVector", "observables": None, "minShots": 0, "maxShots": 0}, + ], + "supportedPragmas": [ + "braket_noise_bit_flip", + "braket_noise_depolarizing", + "braket_noise_kraus", + "braket_noise_pauli_channel", + "braket_noise_generalized_amplitude_damping", + "braket_noise_amplitude_damping", + "braket_noise_phase_flip", + "braket_noise_phase_damping", + "braket_noise_two_qubit_dephasing", + "braket_noise_two_qubit_depolarizing", + "braket_unitary_matrix", + "braket_result_type_sample", + "braket_result_type_expectation", + "braket_result_type_variance", + "braket_result_type_probability", + "braket_result_type_density_matrix", + ], + } + ) +) + GATE_MODEL_RESULT = GateModelTaskResult( **{ "measurements": [[0, 0], [0, 0], [0, 0], [1, 1]], @@ -1443,11 +1475,12 @@ def _aws_device( device_type=AwsDeviceType.QPU, shots=SHOTS, device_arn="baz", + action_properties=ACTION_PROPERTIES, **kwargs, ): - properties_mock.action = {DeviceActionType.OPENQASM: ACTION_PROPERTIES} + properties_mock.action = {DeviceActionType.OPENQASM: action_properties} properties_mock.return_value.action.return_value = { - DeviceActionType.OPENQASM: ACTION_PROPERTIES + DeviceActionType.OPENQASM: action_properties } type_mock.return_value = device_type dev = BraketAwsQubitDevice( @@ -1510,3 +1543,118 @@ def get_test_result_object(result_types=[], source="qubit[2] q; cnot q[0], q[1]; } ) return GateModelQuantumTaskResult.from_string(json_str) + + +@pytest.fixture +def noise_model(): + return ( + NoiseModel() + .add_noise(Noise.BitFlip(0.05), GateCriteria(Gate.H)) + .add_noise(Noise.TwoQubitDepolarizing(0.10), GateCriteria(Gate.CNot)) + ) + + +@pytest.mark.parametrize("backend", ["braket_dm"]) +def test_valid_local_device_for_noise_model(backend, noise_model): + dev = BraketLocalQubitDevice(wires=2, backend=backend, noise_model=noise_model) + assert dev._noise_model.instructions == [ + NoiseModelInstruction(Noise.BitFlip(0.05), GateCriteria(Gate.H)), + NoiseModelInstruction(Noise.TwoQubitDepolarizing(0.10), GateCriteria(Gate.CNot)), + ] + + +@pytest.mark.parametrize( + "backend, device_name", + [("default", "StateVectorSimulator"), ("braket_sv", "StateVectorSimulator")], +) +def test_invalid_local_device_for_noise_model(backend, device_name, noise_model): + with pytest.raises( + ValueError, + match=( + f"{device_name} does not support noise or the noise model " + + f"includes noise that is not supported by {device_name}." + ), + ): + BraketLocalQubitDevice(wires=2, backend=backend, noise_model=noise_model) + + +@pytest.mark.parametrize("device_name", ["dm1"]) +@patch.object(AwsDevice, "name", new_callable=mock.PropertyMock) +def test_valide_aws_device_for_noise_model(name_mock, device_name, noise_model): + name_mock.return_value = device_name + dev = _aws_device( + wires=2, + device_type=AwsDeviceType.SIMULATOR, + noise_model=noise_model, + action_properties=ACTION_PROPERTIES_DM_DEVICE, + ) + + assert dev._noise_model.instructions == [ + NoiseModelInstruction(Noise.BitFlip(0.05), GateCriteria(Gate.H)), + NoiseModelInstruction(Noise.TwoQubitDepolarizing(0.10), GateCriteria(Gate.CNot)), + ] + + +@pytest.mark.parametrize("device_name", ["sv1", "tn1", "foo", "bar"]) +@patch.object(AwsDevice, "name", new_callable=mock.PropertyMock) +def test_invalide_aws_device_for_noise_model(name_mock, device_name, noise_model): + name_mock.return_value = device_name + with pytest.raises( + ValueError, + match=( + f"{device_name} does not support noise or the noise model " + + f"includes noise that is not supported by {device_name}." + ), + ): + _aws_device(wires=2, device_type=AwsDeviceType.SIMULATOR, noise_model=noise_model) + + +@patch.object(AwsDevice, "run") +@patch.object(AwsDevice, "name", new_callable=mock.PropertyMock) +def test_execute_with_noise_model(mock_name, mock_run, noise_model): + mock_run.return_value = TASK + mock_name.return_value = "dm1" + dev = _aws_device( + wires=4, + device_type=AwsDeviceType.SIMULATOR, + noise_model=noise_model, + action_properties=ACTION_PROPERTIES_DM_DEVICE, + ) + + with QuantumTape() as circuit: + qml.Hadamard(wires=0) + qml.QubitUnitary(1 / np.sqrt(2) * np.array([[1, 1], [1, -1]]), wires=0) + qml.RX(0.432, wires=0) + qml.CNOT(wires=[0, 1]) + qml.probs(wires=[0]) + qml.expval(qml.PauliX(1)) + qml.var(qml.PauliY(2)) + qml.sample(qml.PauliZ(3)) + + _ = dev.execute(circuit) + + assert dev.task == TASK + + EXPECTED_CIRC = ( + Circuit() + .h(0) + .bit_flip(0, 0.05) + .unitary([0], 1 / np.sqrt(2) * np.array([[1, 1], [1, -1]])) + .rx(0, 0.432) + .cnot(0, 1) + .two_qubit_depolarizing(0, 1, 0.10) + .i(2) + .i(3) + .probability(target=[0]) + .expectation(observable=Observable.X(), target=1) + .variance(observable=Observable.Y(), target=2) + .sample(observable=Observable.Z(), target=3) + ) + mock_run.assert_called_with( + EXPECTED_CIRC, + s3_destination_folder=("foo", "bar"), + shots=SHOTS, + poll_timeout_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, + poll_interval_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, + inputs={"p_0": 0.432}, + ) From 47c6ceeb8b5409b62b90271cf3b16283e8c8d20d Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 1 Feb 2023 16:17:03 +0000 Subject: [PATCH 22/34] prepare release v1.11.0 --- CHANGELOG.md | 6 ++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 941acc9c..c3112db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.11.0 (2023-02-01) + +### Features + + * Braket noise model for density matrix simulators + ## v1.10.4 (2023-01-03) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index dffc7693..6ad8bf3b 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.10.5.dev0" +__version__ = "1.11.0" From f74ed75842050cf3518b88e654707a8b7947bc31 Mon Sep 17 00:00:00 2001 From: ci Date: Wed, 1 Feb 2023 16:17:03 +0000 Subject: [PATCH 23/34] update development version to v1.11.1.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 6ad8bf3b..7b1da559 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.0" +__version__ = "1.11.1.dev0" From 59417cc4ee9f148766871a94f412c8b53a300295 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 9 Feb 2023 16:18:53 +0000 Subject: [PATCH 24/34] prepare release v1.11.1 --- CHANGELOG.md | 8 ++++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3112db5..390af689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v1.11.1 (2023-02-09) + +### Bug Fixes and Other Changes + + * update: adding build for python 3.10 + * Merge branch 'main' into test310 + * testing python 3.10 + ## v1.11.0 (2023-02-01) ### Features diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 7b1da559..f9bc49a0 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.1.dev0" +__version__ = "1.11.1" From eb905ed74c394d6f9954f93bfed5e9a7a87b87a3 Mon Sep 17 00:00:00 2001 From: ci Date: Thu, 9 Feb 2023 16:18:53 +0000 Subject: [PATCH 25/34] update development version to v1.11.2.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index f9bc49a0..e708eff3 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.1" +__version__ = "1.11.2.dev0" From 6dd05dd4de02b9130f4ede59f52bb01356a9c4bc Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Fri, 10 Feb 2023 16:52:47 -0800 Subject: [PATCH 26/34] fix: `shots=0` measurements with trainable params (#131) --- src/braket/pennylane_plugin/braket_device.py | 23 ++++-- test/unit_tests/test_braket_device.py | 84 +++++++++++++++++++- 2 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index 73502392..f5620edd 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -46,11 +46,13 @@ from braket.devices import Device, LocalSimulator from braket.simulator import BraketSimulator from braket.tasks import GateModelQuantumTaskResult, QuantumTask -from pennylane import CircuitGraph, QuantumFunctionError, QubitDevice +from pennylane import QuantumFunctionError, QubitDevice from pennylane import numpy as np +from pennylane.gradients import param_shift from pennylane.measurements import Expectation, Probability, Sample, State, Variance from pennylane.operation import Observable, Operation from pennylane.ops.qubit.hamiltonian import Hamiltonian +from pennylane.tape import QuantumTape from braket.pennylane_plugin.translation import ( get_adjoint_gradient_result_type, @@ -149,7 +151,7 @@ def task(self) -> QuantumTask: """QuantumTask: The task corresponding to the last run circuit.""" return self._task - def _pl_to_braket_circuit(self, circuit: CircuitGraph, compute_gradient=False, **run_kwargs): + def _pl_to_braket_circuit(self, circuit: QuantumTape, compute_gradient=False, **run_kwargs): """Converts a PennyLane circuit to a Braket circuit""" braket_circuit = self.apply( circuit.operations, @@ -289,7 +291,7 @@ def _tracking_data(task): else: return {"braket_failed_task_id": task.id} - def execute(self, circuit: CircuitGraph, compute_gradient=False, **run_kwargs) -> np.ndarray: + def execute(self, circuit: QuantumTape, compute_gradient=False, **run_kwargs) -> np.ndarray: self.check_validity(circuit.operations, circuit.observables) self._circuit = self._pl_to_braket_circuit( circuit, compute_gradient=compute_gradient, **run_kwargs @@ -544,17 +546,26 @@ def execute_and_gradients(self, circuits, **kwargs): """Execute a list of circuits and calculate their gradients. Returns a list of circuit results and a list of gradients/jacobians, one of each for each circuit in circuits. - of floats, 1 float for every instance of a trainable parameter in a gate in the circuit. - Functions like qml.grad or qml.jacobian then use that format to generate a per-parameter - format. + + The gradient is returned as a list of floats, 1 float for every instance + of a trainable parameter in a gate in the circuit. Functions like qml.grad or qml.jacobian + then use that format to generate a per-parameter format. """ res = [] jacs = [] for circuit in circuits: + observables = circuit.observables if not circuit.trainable_params: new_res = self.execute(circuit, compute_gradient=False) # don't bother computing a gradient when there aren't any trainable parameters. new_jac = np.tensor([]) + elif len(observables) != 1 or observables[0].return_type != Expectation: + gradient_circuits, post_processing_fn = param_shift(circuit) + grad_circuit_results = [ + self.execute(c, compute_gradient=False) for c in gradient_circuits + ] + new_jac = post_processing_fn(grad_circuit_results) + new_res = self.execute(circuit, compute_gradient=False) else: results = self.execute(circuit, compute_gradient=True) new_res, new_jac = results[0] diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 721c741d..729d82b0 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -349,6 +349,15 @@ def test_execute(mock_run): qml.expval(qml.PauliX(1)) CIRCUIT_4.trainable_params = [] +PARAMS_5 = np.array([0.432, 0.543], requires_grad=True) +with QuantumTape() as CIRCUIT_5: + qml.Hadamard(wires=0) + qml.CNOT(wires=[0, 1]) + qml.RX(PARAMS_5[0], wires=0) + qml.RY(PARAMS_5[1], wires=0) + qml.var(qml.PauliX(0) @ qml.PauliY(1)) +CIRCUIT_5.trainable_params = [0, 1] + @patch.object(AwsDevice, "run") @pytest.mark.parametrize( @@ -471,7 +480,7 @@ def test_execute_with_gradient( task = Mock() type(task).id = PropertyMock(return_value="task_arn") task.state.return_value = "COMPLETED" - task.result.return_value = get_test_result_object(result_types=result_types) + task.result.return_value = get_test_result_object(rts=result_types) mock_run.return_value = task dev = _aws_device(wires=wires, foo="bar", shots=0, device_type=AwsDeviceType.SIMULATOR) @@ -1332,7 +1341,7 @@ def test_execute_and_gradients( task = Mock() type(task).id = PropertyMock(return_value="task_arn") task.state.return_value = "COMPLETED" - task.result.return_value = get_test_result_object(result_types=result_types) + task.result.return_value = get_test_result_object(rts=result_types) mock_run.return_value = task dev = _aws_device( wires=wires, @@ -1359,6 +1368,73 @@ def test_execute_and_gradients( assert (jacs == expected_pl_result[1]).all() +@patch("braket.pennylane_plugin.braket_device.param_shift") +@patch.object(AwsDevice, "run") +@pytest.mark.parametrize( + "pl_circ, expected_braket_circ, wires, result_types, expected_pl_result", + [ + ( + CIRCUIT_5, + Circuit() + .h(0) + .cnot(0, 1) + .rx(0, 0.432) + .ry(0, 0.543) + .variance(observable=Observable.X() @ Observable.Y(), target=[0, 1]), + 2, + [ + { + "type": {"observable": ["x", "y"], "targets": [0, 1], "type": "variance"}, + "value": 0.0, + } + ], + [np.tensor([0]), np.tensor([0])], + ), + ], +) +def test_execute_and_gradients_non_adjoint( + mock_run, + mock_param_shift, + pl_circ, + expected_braket_circ, + wires, + result_types, + expected_pl_result, +): + task = Mock() + type(task).id = PropertyMock(return_value="task_arn") + task.state.return_value = "COMPLETED" + task.result.return_value = get_test_result_object(rts=result_types) + mock_run.return_value = task + + grad = [1, 2] + mock_param_shift.return_value = [pl_circ, pl_circ], lambda x: grad + + dev = _aws_device( + wires=wires, + foo="bar", + shots=0, + device_type=AwsDeviceType.SIMULATOR, + device_arn="arn:aws:braket:::device/quantum-simulator/amazon/sv1", + ) + + results, jacs = dev.execute_and_gradients([pl_circ]) + assert dev.task == task + mock_run.assert_called_with( + expected_braket_circ, + s3_destination_folder=("foo", "bar"), + shots=0, + poll_timeout_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_TIMEOUT, + poll_interval_seconds=AwsQuantumTask.DEFAULT_RESULTS_POLL_INTERVAL, + foo="bar", + inputs={}, + ) + + # assert results & jacs are right + assert (results == expected_pl_result[0]).all() + assert jacs == [grad] + + def test_capabilities_class_and_instance_method(): class_caps = BraketAwsQubitDevice.capabilities() instance_caps = _aws_device(wires=2).capabilities() @@ -1512,7 +1588,7 @@ def _bad_aws_device(properties_mock, session_mock, wires, **kwargs): ) -def get_test_result_object(result_types=[], source="qubit[2] q; cnot q[0], q[1]; measure q;"): +def get_test_result_object(rts=[], source="qubit[2] q; cnot q[0], q[1]; measure q;"): json_str = json.dumps( { "braketSchemaHeader": { @@ -1520,7 +1596,7 @@ def get_test_result_object(result_types=[], source="qubit[2] q; cnot q[0], q[1]; "version": "1", }, "measurements": [[0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 1]], - "resultTypes": result_types, + "resultTypes": rts, "measuredQubits": [0, 1, 2, 3], "taskMetadata": { "braketSchemaHeader": { From cf01fa3bb56d55793d927370aadcb3895f89b8ca Mon Sep 17 00:00:00 2001 From: ci Date: Sat, 11 Feb 2023 01:10:28 +0000 Subject: [PATCH 27/34] prepare release v1.11.2 --- CHANGELOG.md | 6 ++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 390af689..bb48768c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.11.2 (2023-02-11) + +### Bug Fixes and Other Changes + + * `shots=0` measurements with trainable params + ## v1.11.1 (2023-02-09) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index e708eff3..e6d1f6ad 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.2.dev0" +__version__ = "1.11.2" From 7f29b95ac467e118ed1513ee8b6a511209c9667a Mon Sep 17 00:00:00 2001 From: ci Date: Sat, 11 Feb 2023 01:10:28 +0000 Subject: [PATCH 28/34] update development version to v1.11.3.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index e6d1f6ad..13094dfa 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.2" +__version__ = "1.11.3.dev0" From 94f57c0bf6be887e0a0221a72290c13be5135da1 Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+math411@users.noreply.github.com> Date: Mon, 13 Feb 2023 12:16:43 -0800 Subject: [PATCH 29/34] infra: update github workflows for node12 retirement (#130) Co-authored-by: Abe Coull --- .github/workflows/publish-to-pypi.yml | 4 ++-- .github/workflows/python-package.yml | 6 +++--- README.rst | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index d1439d2b..ea0c5702 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -9,9 +9,9 @@ jobs: name: Build and publish distribution to PyPi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install wheel diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 4d429ec2..272bafd8 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -22,9 +22,9 @@ jobs: python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install dependencies @@ -40,4 +40,4 @@ jobs: run: | tox -e unit-tests - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 diff --git a/README.rst b/README.rst index 7c40a697..0f796339 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ Amazon Braket PennyLane Plugin .. image:: https://img.shields.io/pypi/pyversions/amazon-braket-pennylane-plugin.svg :alt: Supported Python Versions :target: https://pypi.python.org/pypi/amazon-braket-pennylane-plugin -.. image:: https://img.shields.io/github/workflow/status/aws/amazon-braket-pennylane-plugin-python/Python%20package/main?logo=github +.. image:: https://img.shields.io/github/actions/workflow/status/aws/amazon-braket-strawberryfields-plugin-python/python-package.yml?branch=main&logo=github :alt: Build Status :target: https://github.com/aws/amazon-braket-pennylane-plugin-python/actions?query=workflow%3A%22Python+package%22 .. image:: https://codecov.io/gh/aws/amazon-braket-pennylane-plugin-python/branch/main/graph/badge.svg?token=VPPM8BJKW4 From 6a042054c2302c1b20fe9c331ed094f94ae9bd71 Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 14 Feb 2023 16:17:07 +0000 Subject: [PATCH 30/34] prepare release v1.11.2.post0 --- CHANGELOG.md | 6 ++++++ src/braket/pennylane_plugin/_version.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb48768c..861e0341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v1.11.2.post0 (2023-02-14) + +### Testing and Release Infrastructure + + * update github workflows for node12 retirement + ## v1.11.2 (2023-02-11) ### Bug Fixes and Other Changes diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 13094dfa..6f903ad1 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.3.dev0" +__version__ = "1.11.2.post0" From 9bc66c1099bbaca40a45a7e9646f798c6a223df4 Mon Sep 17 00:00:00 2001 From: ci Date: Tue, 14 Feb 2023 16:17:07 +0000 Subject: [PATCH 31/34] update development version to v1.11.3.dev0 --- src/braket/pennylane_plugin/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/braket/pennylane_plugin/_version.py b/src/braket/pennylane_plugin/_version.py index 6f903ad1..13094dfa 100644 --- a/src/braket/pennylane_plugin/_version.py +++ b/src/braket/pennylane_plugin/_version.py @@ -15,4 +15,4 @@ Version number (major.minor.patch[-label]) """ -__version__ = "1.11.2.post0" +__version__ = "1.11.3.dev0" From 69c16385b4fd5650784f86db867536e1e91c9a7f Mon Sep 17 00:00:00 2001 From: Abe Coull <85974725+math411@users.noreply.github.com> Date: Wed, 1 Mar 2023 15:44:59 -0800 Subject: [PATCH 32/34] deprecation: deprecate python 3.7 (#136) * deprecation: deprecate python 3.7 --------- Co-authored-by: Abe Coull Co-authored-by: Cody Wang --- .github/workflows/python-package.yml | 2 +- .readthedocs.yml | 2 +- README.rst | 3 --- setup.py | 4 ++-- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 272bafd8..46f14c92 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v3 diff --git a/.readthedocs.yml b/.readthedocs.yml index 26bc27fa..a52ab5c2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -15,7 +15,7 @@ formats: # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 + version: 3.8 install: - method: pip path: . diff --git a/README.rst b/README.rst index 0f796339..8a112b8c 100644 --- a/README.rst +++ b/README.rst @@ -16,9 +16,6 @@ Amazon Braket PennyLane Plugin .. image:: https://img.shields.io/readthedocs/amazon-braket-pennylane-plugin-python.svg?logo=read-the-docs :alt: Documentation Status :target: https://amazon-braket-pennylane-plugin-python.readthedocs.io/en/latest/?badge=latest -.. image:: https://img.shields.io/badge/code_style-black-000000.svg - :alt: Code Style: Black - :target: https://github.com/psf/black The Amazon Braket PennyLane plugin offers two Amazon Braket quantum devices to work with PennyLane: diff --git a/setup.py b/setup.py index b926693f..6bee1e0b 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ name="amazon-braket-pennylane-plugin", version=version, license="Apache License 2.0", - python_requires=">= 3.7.2", + python_requires=">= 3.8.2", packages=find_namespace_packages(where="src", exclude=("test",)), package_dir={"": "src"}, install_requires=[ @@ -78,8 +78,8 @@ "Natural Language :: English", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", ], ) From 414e1329648ab7f8ec70f1c3481e18cce311622f Mon Sep 17 00:00:00 2001 From: Albert Mitjans Date: Thu, 2 Mar 2023 03:16:26 +0100 Subject: [PATCH 33/34] fix: Remove use of in-place inversion. Replace it with `qml.adjoint`. (#134) * :wrench: refactor (inv): Remove use of in-place inversion. Replace it with qml.adjoint. * :rewind: change: Revert changes from isort. * :rewind: change: Remove dead code. * :rewind: change: Change comment. * :wrench: change: Raise an error when the adjoint of a Braket operation contains more than one operation. * :wrench: change: Change error message. --- src/braket/pennylane_plugin/braket_device.py | 7 --- src/braket/pennylane_plugin/translation.py | 60 ++++++++++++-------- test/integ_tests/test_apply.py | 2 +- test/unit_tests/test_braket_device.py | 2 - test/unit_tests/test_translation.py | 38 ++++++++++--- 5 files changed, 67 insertions(+), 42 deletions(-) diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py index f5620edd..3eaeab59 100644 --- a/src/braket/pennylane_plugin/braket_device.py +++ b/src/braket/pennylane_plugin/braket_device.py @@ -120,13 +120,6 @@ def reset(self): self._circuit = None self._task = None - @classmethod - def capabilities(cls): - """Add support for inverse""" - capabilities = super().capabilities().copy() - capabilities.update(supports_inverse_operations=True) - return capabilities - @property def operations(self) -> FrozenSet[str]: """FrozenSet[str]: The set of names of PennyLane operations that the device supports.""" diff --git a/src/braket/pennylane_plugin/translation.py b/src/braket/pennylane_plugin/translation.py index 44c39b43..227a3c2f 100644 --- a/src/braket/pennylane_plugin/translation.py +++ b/src/braket/pennylane_plugin/translation.py @@ -31,6 +31,7 @@ from pennylane import numpy as np from pennylane.measurements import ObservableReturnTypes from pennylane.operation import Observable, Operation +from pennylane.ops import Adjoint from braket.pennylane_plugin.ops import ( MS, @@ -52,11 +53,11 @@ "rx": "RX", "rz": "RZ", "s": "S", - "si": "S.inv", + "si": "Adjoint(S)", "v": "SX", - "vi": "SX.inv", + "vi": "Adjoint(SX)", "t": "T", - "ti": "T.inv", + "ti": "Adjoint(T)", "cnot": "CNOT", "cy": "CY", "cz": "CZ", @@ -196,17 +197,17 @@ def _(_: qml.ECR, _parameters): @_translate_operation.register def _(s: qml.S, _parameters): - return gates.Si() if s.inverse else gates.S() + return gates.S() @_translate_operation.register def _(sx: qml.SX, _parameters): - return gates.Vi() if sx.inverse else gates.V() + return gates.V() @_translate_operation.register def _(t: qml.T, _parameters): - return gates.Ti() if t.inverse else gates.T() + return gates.T() @_translate_operation.register @@ -242,31 +243,31 @@ def _(_: qml.Toffoli, _parameters): @_translate_operation.register def _(rx: qml.RX, parameters): phi = parameters[0] - return gates.Rx(-phi) if rx.inverse else gates.Rx(phi) + return gates.Rx(phi) @_translate_operation.register def _(ry: qml.RY, parameters): phi = parameters[0] - return gates.Ry(-phi) if ry.inverse else gates.Ry(phi) + return gates.Ry(phi) @_translate_operation.register def _(rz: qml.RZ, parameters): phi = parameters[0] - return gates.Rz(-phi) if rz.inverse else gates.Rz(phi) + return gates.Rz(phi) @_translate_operation.register def _(phase_shift: qml.PhaseShift, parameters): phi = parameters[0] - return gates.PhaseShift(-phi) if phase_shift.inverse else gates.PhaseShift(phi) + return gates.PhaseShift(phi) @_translate_operation.register def _(qubit_unitary: qml.QubitUnitary, parameters): U = np.asarray(parameters[0]) - return gates.Unitary(U.conj().T) if qubit_unitary.inverse else gates.Unitary(U) + return gates.Unitary(U) @_translate_operation.register @@ -315,60 +316,60 @@ def _(_: qml.QubitChannel, parameters): @_translate_operation.register def _(c_phase_shift: qml.ControlledPhaseShift, parameters): phi = parameters[0] - return gates.CPhaseShift(-phi) if c_phase_shift.inverse else gates.CPhaseShift(phi) + return gates.CPhaseShift(phi) @_translate_operation.register def _(c_phase_shift_00: CPhaseShift00, parameters): phi = parameters[0] - return gates.CPhaseShift00(-phi) if c_phase_shift_00.inverse else gates.CPhaseShift00(phi) + return gates.CPhaseShift00(phi) @_translate_operation.register def _(c_phase_shift_01: CPhaseShift01, parameters): phi = parameters[0] - return gates.CPhaseShift01(-phi) if c_phase_shift_01.inverse else gates.CPhaseShift01(phi) + return gates.CPhaseShift01(phi) @_translate_operation.register def _(c_phase_shift_10: CPhaseShift10, parameters): phi = parameters[0] - return gates.CPhaseShift10(-phi) if c_phase_shift_10.inverse else gates.CPhaseShift10(phi) + return gates.CPhaseShift10(phi) @_translate_operation.register def _(iswap: qml.ISWAP, _parameters): - return gates.PSwap(3 * np.pi / 2) if iswap.inverse else gates.ISwap() + return gates.ISwap() @_translate_operation.register def _(pswap: PSWAP, parameters): phi = parameters[0] - return gates.PSwap(-phi) if pswap.inverse else gates.PSwap(phi) + return gates.PSwap(phi) @_translate_operation.register def _(xy: qml.IsingXY, parameters): phi = parameters[0] - return gates.XY(-phi) if xy.inverse else gates.XY(phi) + return gates.XY(phi) @_translate_operation.register def _(xx: qml.IsingXX, parameters): phi = parameters[0] - return gates.XX(-phi) if xx.inverse else gates.XX(phi) + return gates.XX(phi) @_translate_operation.register def _(yy: qml.IsingYY, parameters): phi = parameters[0] - return gates.YY(-phi) if yy.inverse else gates.YY(phi) + return gates.YY(phi) @_translate_operation.register def _(zz: qml.IsingZZ, parameters): phi = parameters[0] - return gates.ZZ(-phi) if zz.inverse else gates.ZZ(phi) + return gates.ZZ(phi) @_translate_operation.register @@ -380,13 +381,26 @@ def _(_gpi: GPi, parameters): @_translate_operation.register def _(gpi2: GPi2, parameters): phi = parameters[0] - return gates.GPi2(phi + np.pi) if gpi2.inverse else gates.GPi2(phi) + return gates.GPi2(phi) @_translate_operation.register def _(ms: MS, parameters): phi_0, phi_1 = parameters[:2] - return gates.MS(phi_0 + np.pi, phi_1) if ms.inverse else gates.MS(phi_0, phi_1) + return gates.MS(phi_0, phi_1) + + +@_translate_operation.register +def _(adjoint: Adjoint, parameters): + if isinstance(adjoint.base, qml.ISWAP): + # gates.ISwap.adjoint() returns a different value + return gates.PSwap(3 * np.pi / 2) + base = _translate_operation(adjoint.base, parameters) + if len(base.adjoint()) > 1: + raise NotImplementedError( + f"The adjoint of the Braket operation {base} contains more than one operation." + ) + return base.adjoint()[0] def get_adjoint_gradient_result_type( diff --git a/test/integ_tests/test_apply.py b/test/integ_tests/test_apply.py index 4ef7b881..4986affc 100755 --- a/test/integ_tests/test_apply.py +++ b/test/integ_tests/test_apply.py @@ -186,7 +186,7 @@ def circuit(): @qml.qnode(dev) def circuit_inv(): qml.QubitStateVector.compute_decomposition(state, wires=wires) - op(*op_args, wires=wires).inv() + qml.adjoint(op(*op_args, wires=wires)) return qml.probs(wires=wires) assert np.allclose( diff --git a/test/unit_tests/test_braket_device.py b/test/unit_tests/test_braket_device.py index 729d82b0..edb878d8 100644 --- a/test/unit_tests/test_braket_device.py +++ b/test/unit_tests/test_braket_device.py @@ -1444,7 +1444,6 @@ def test_capabilities_class_and_instance_method(): "supports_finite_shots": True, "supports_tensor_observables": True, "returns_probs": True, - "supports_inverse_operations": True, } assert class_caps == expected_caps # the instance should not have provides_jacobian, even though AdjointGradient is in the @@ -1462,7 +1461,6 @@ def test_capabilities_adjoint_shots_0(): "supports_finite_shots": True, "supports_tensor_observables": True, "returns_probs": True, - "supports_inverse_operations": True, # the instance should have provides_jacobian because AdjointGradient is in the # supported result types and shots == 0 "provides_jacobian": True, diff --git a/test/unit_tests/test_translation.py b/test/unit_tests/test_translation.py index 34a970dd..24d3dd1e 100644 --- a/test/unit_tests/test_translation.py +++ b/test/unit_tests/test_translation.py @@ -13,6 +13,7 @@ import json import re +from unittest.mock import patch import numpy as np import pennylane as qml @@ -299,23 +300,42 @@ def test_translate_operation_with_unique_params( @pytest.mark.parametrize("pl_cls, braket_cls, qubits, params, inv_params", testdata_inverses) def test_translate_operation_inverse(pl_cls, braket_cls, qubits, params, inv_params): """Tests that inverse gates are translated correctly""" - pl_op = pl_cls(*params, wires=qubits).inv() + pl_op = qml.adjoint(pl_cls(*params, wires=qubits)) braket_gate = braket_cls(*inv_params) assert translate_operation(pl_op) == braket_gate - if isinstance(pl_op, (GPi, GPi2, MS)): - assert _braket_to_pl[ - re.match("^[a-z0-2]+", braket_gate.to_ir(qubits, ir_type=IRType.OPENQASM)).group(0) - ] == pl_op.name.replace(".inv", "") + if isinstance(pl_op.base, (GPi, GPi2, MS)): + op_name = _braket_to_pl[ + re.match( + "^[a-z0-2]+", + braket_gate.to_ir(qubits, ir_type=IRType.OPENQASM), + )[0] + ] else: - assert _braket_to_pl[ + op_name = _braket_to_pl[ braket_gate.to_ir(qubits).__class__.__name__.lower().replace("_", "") - ] == pl_op.name.replace(".inv", "") + ] + + assert f"Adjoint({op_name})" == pl_op.name + + +@patch("braket.circuits.gates.X.adjoint") +def test_translate_operation_multiple_inverses_unsupported(adjoint): + """Test that an error is raised when translating a Braket operation which adjoint contains + multiple operations.""" + # Mock ``gates.X.adjoint()`` to return two gates + adjoint.return_value = [gates.X(), gates.I()] + pl_op = qml.adjoint(qml.PauliX(0)) + with pytest.raises( + NotImplementedError, + match="The adjoint of the Braket operation X", + ): + translate_operation(pl_op) @pytest.mark.parametrize("pl_cls, braket_cls, qubit", testdata_named_inverses) def test_translate_operation_named_inverse(pl_cls, braket_cls, qubit): """Tests that operations whose inverses are named Braket gates are inverted correctly""" - pl_op = pl_cls(wires=[qubit]).inv() + pl_op = qml.adjoint(pl_cls(wires=[qubit])) braket_gate = braket_cls() assert translate_operation(pl_op) == braket_gate assert ( @@ -326,7 +346,7 @@ def test_translate_operation_named_inverse(pl_cls, braket_cls, qubit): def test_translate_operation_iswap_inverse(): """Tests that the iSwap gate is inverted correctly""" - assert translate_operation(qml.ISWAP(wires=[0, 1]).inv()) == gates.PSwap(3 * np.pi / 2) + assert translate_operation(qml.adjoint(qml.ISWAP(wires=[0, 1]))) == gates.PSwap(3 * np.pi / 2) @pytest.mark.parametrize( From a3635d61aec57197ca586393c8cf161b37f6f124 Mon Sep 17 00:00:00 2001 From: Albert Mitjans Date: Thu, 2 Mar 2023 08:29:34 +0100 Subject: [PATCH 34/34] Add support for new custom measurements (#122) --- test/unit_tests/test_translation.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/unit_tests/test_translation.py b/test/unit_tests/test_translation.py index 24d3dd1e..552b814f 100644 --- a/test/unit_tests/test_translation.py +++ b/test/unit_tests/test_translation.py @@ -31,7 +31,7 @@ from braket.circuits.serialization import IRType from braket.tasks import GateModelQuantumTaskResult from pennylane import numpy as pnp -from pennylane.measurements import MeasurementProcess, ObservableReturnTypes +from pennylane.measurements import ObservableReturnTypes from pennylane.wires import Wires from braket.pennylane_plugin import PSWAP, CPhaseShift00, CPhaseShift01, CPhaseShift10 @@ -423,7 +423,7 @@ def test_translate_result_type_hamiltonian_unsupported_return(return_type): def test_translate_result_type_probs(): """Tests if a PennyLane probability return type is successfully converted into a Braket result using translate_result_type""" - mp = MeasurementProcess(ObservableReturnTypes.Probability, wires=Wires([0])) + mp = qml.probs(wires=Wires([0])) braket_result_type_calculated = translate_result_type(mp, [0], frozenset()) braket_result_type = Probability([0]) @@ -434,7 +434,7 @@ def test_translate_result_type_probs(): def test_translate_result_type_state_vector(): """Tests if a PennyLane state vector return type is successfully converted into a Braket result using translate_result_type""" - mp = MeasurementProcess(ObservableReturnTypes.State) + mp = qml.state() braket_result_type_calculated = translate_result_type( mp, [], frozenset(["StateVector", "DensityMatrix"]) ) @@ -447,7 +447,7 @@ def test_translate_result_type_state_vector(): def test_translate_result_type_density_matrix(): """Tests if a PennyLane density matrix return type is successfully converted into a Braket result using translate_result_type""" - mp = MeasurementProcess(ObservableReturnTypes.State) + mp = qml.state() braket_result_type_calculated = translate_result_type(mp, [], frozenset(["DensityMatrix"])) braket_result_type = DensityMatrix() @@ -458,7 +458,7 @@ def test_translate_result_type_density_matrix(): def test_translate_result_type_density_matrix_partial(): """Tests if a PennyLane partial density matrix return type is successfully converted into a Braket result using translate_result_type""" - mp = MeasurementProcess(ObservableReturnTypes.State, wires=[0]) + mp = qml.density_matrix(wires=[0]) braket_result_type_calculated = translate_result_type( mp, [0], frozenset(["StateVector", "DensityMatrix"]) ) @@ -471,7 +471,7 @@ def test_translate_result_type_density_matrix_partial(): def test_translate_result_type_state_unimplemented(): """Tests if a NotImplementedError is raised by translate_result_type when a PennyLane state return type is converted while not supported by the device""" - mp = MeasurementProcess(ObservableReturnTypes.State) + mp = qml.state() with pytest.raises(NotImplementedError, match="Unsupported return type"): translate_result_type(mp, [0], frozenset()) @@ -503,7 +503,7 @@ def test_translate_result(): targets = [0] result_dict["measuredQubits"]: targets result = GateModelQuantumTaskResult.from_string(json.dumps(result_dict)) - mp = MeasurementProcess(ObservableReturnTypes.Probability, wires=Wires([0])) + mp = qml.probs(wires=Wires([0])) translated = translate_result(result, mp, targets, frozenset()) assert (translated == result.result_types[0].value).all()