Code Monkey home page Code Monkey logo

amazon-braket-pennylane-plugin-python's Introduction

Amazon Braket PennyLane Plugin

Latest Version

Supported Python Versions

codecov

Documentation Status

The Amazon Braket PennyLane plugin offers four Amazon Braket quantum devices to work with PennyLane:

  • braket.aws.qubit for running with the Amazon Braket service's quantum devices, both QPUs and simulators
  • braket.local.qubit for running the Amazon Braket SDK's local simulator where you can optionally specify the backend ("default", "braket_sv", "braket_dm" etc)
  • braket.aws.ahs for running with the Amazon Braket service's analog Hamiltonian simulation QPUs
  • braket.local.ahs for running analog Hamiltonian simulation on Amazon Braket SDK's local simulator

The Amazon Braket Python SDK is an open source library that provides a framework to interact with quantum computing hardware devices and simulators through Amazon Braket.

PennyLane is a machine learning library for optimization and automatic differentiation of hybrid quantum-classical computations.

The plugin documentation can be found here: https://amazon-braket-pennylane-plugin-python.readthedocs.io/en/latest/.

Features

Provides four devices to be used with PennyLane:

  • Two gate-based devices, braket.aws.qubit for running on the Amazon Braket service, and braket.local.qubit for running on the Amazon Braket SDK's local simulator.
  • Two analog Hamiltonian simulation devices, braket.aws.ahs for running on QPU via the Amazon Braket service, and braket.local.ahs for running on the Amazon Braket SDK's local simulator.
  • Combines Amazon Braket with PennyLane's automatic differentiation and optimization.

For the gate-based devices:

  • Both devices support most core qubit PennyLane operations.
  • All PennyLane observables are supported.
  • Provides custom PennyLane operations to cover additional Braket operations: ISWAP, PSWAP, and many more. Every custom operation supports analytic differentiation.

For the analog Hamiltonian simulation devices:

  • The devices support ParametrizedEvolution operators created via the PennyLane pulse programming module.
  • PennyLane observables in the measurement (Z) basis are supported
  • Provides translation of user-defined pulse level control to simulation and hardware implementation

Installation

Before you begin working with the Amazon Braket PennyLane Plugin, make sure that you installed or configured the following prerequisites:

  • Download and install Python 3.9 or greater. If you are using Windows, choose the option Add Python to environment variables before you begin the installation.
  • Make sure that your AWS account is onboarded to Amazon Braket, as per the instructions here.
  • Download and install PennyLane:

    pip install pennylane

You can then install the latest release of the PennyLane-Braket plugin as follows:

pip install amazon-braket-pennylane-plugin

You can also install the development version from source by cloning this repository and running a pip install command in the root directory of the repository:

git clone https://github.com/amazon-braket/amazon-braket-pennylane-plugin-python.git
cd amazon-braket-pennylane-plugin-python
pip install .

You can check your currently installed version of amazon-braket-pennylane-plugin with pip show:

pip show amazon-braket-pennylane-plugin

or alternatively from within Python:

from braket import pennylane_plugin
pennylane_plugin.__version__

Tests

Make sure to install test dependencies first:

pip install -e "amazon-braket-pennylane-plugin-python[test]"

Unit tests

Run the unit tests using:

tox -e unit-tests

To run an individual test:

tox -e unit-tests -- -k 'your_test'

To run linters, doc, and unit tests:

tox

Integration tests

To run the integration tests, set the AWS_PROFILE as explained in the amazon-braket-sdk-python README:

export AWS_PROFILE=Your_Profile_Name

Running the integration tests creates an S3 bucket in the same account as the AWS_PROFILE with the following naming convention amazon-braket-pennylane-plugin-integ-tests-{account_id}.

Run the integration tests with:

tox -e integ-tests

To run an individual integration test:

tox -e integ-tests -- -k 'your_test'

Documentation

To build the HTML documentation, run:

tox -e docs

The documentation can then be found in the doc/build/documentation/html/ directory.

Contributing

We welcome contributions - simply fork the repository of this plugin, and then make a pull request containing your contribution. All contributers to this plugin will be listed as authors on the releases.

We also encourage bug reports, suggestions for new features and enhancements, and even links to cool projects or applications built with the plugin.

Support

If you are having issues, please let us know by posting the issue on our Github issue tracker, or by asking a question in the forum.

License

This project is licensed under the Apache-2.0 License.

amazon-braket-pennylane-plugin-python's People

Contributors

ajberdy avatar albertmitjans avatar albi3ro avatar amazon-auto avatar amazon-braket-ci-bot avatar antalszava avatar ashlhans avatar avawang1 avatar borjarequena avatar christianbmadsen avatar co9olguy avatar dependabot[bot] avatar doctorperceptron avatar guomanmin avatar jacofeld avatar josh146 avatar krneta avatar kshitijc avatar kshyatt-aws avatar licedric avatar lillian542 avatar lundql avatar mariaschuld avatar math411 avatar randalld-aws avatar shpface avatar speller26 avatar trbromley avatar virajvchaudhari avatar yitchen-tim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

amazon-braket-pennylane-plugin-python's Issues

Several `Operator` methods have been modified in PennyLane master

Describe the bug

In the recent PennyLane master commit, several of our operator methods have been modified.

When creating operators:

  • Matrices: Operators should now define the static method compute_matrix() rather than the class method _matrix()

  • Decompositions: Operators should now define the static method compute_decompositions() rather than the static method decompositions().

This will require a small re-naming in https://github.com/aws/amazon-braket-pennylane-plugin-python/blob/main/src/braket/pennylane_plugin/ops.py.

When accessing operator information:

  • Operator.matrix will raise a deprecation warning - use qml.matrix(op) instead
  • Operator.eigvals will raise a deprecation warning - use qml.eigvals(op) instead
  • Operator.terms is now a method, Operator.terms().

This will require updates in the following places:

Update device non-support to raise a DeviceError

Describe the feature you'd like
On this line, a TypeError is currently raised when an operator is not supported. I would like this to be changed to qml.DeviceError.

How would this feature be used? Please describe.
The PennyLane device test suite checks for DeviceErrors with "supported" in the message in order to auto-skip any tests that fail because a device does not support an operator that the test expected support for. While updating the test suite, I noticed that some new tests were failing for support reasons, but they weren't being caught by this handler because they raised TypeErrors instead of DeviceErrors

Describe alternatives you've considered
In my change, I'm matching TypeErrors as well, but I feel like this is more of a hack/short-term patch than a proper fix for the situation. I believe that changing it to a DeviceError is a more proper/long-term fix.

Additional context
Two things:

  1. PennyLane maintainers strongly depend on the device test suite to know the health of plugins, so preserving its quality/utility and avoiding unnecessary errors is very important
  2. PennyLane is not usually very strict about the types of errors being raised, so this is an unfortunate matter of circumstance. My apologies for that 😞 this is one of those rare times when there is a (pseudo-)formalized error handling standard being enforced in PL tests, so please bear with us!

Test

Describe the feature you'd like
A clear and concise description of the functionality you want.

How would this feature be used? Please describe.
A clear and concise description of the use case for this feature. Please provide an example, if possible.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

Device tracker support

In the upcoming PennyLane v0.17.0 release, we will be introducing a Tracker. This tracker introduces the ability for devices to store arbitrary information on each execution and batch execution and lets the users interact with that information with a user-provided callback function.

While on standard PennyLane devices, we will track executions, shots, batches, and batch length, the tracker allows for storage of arbitrary keyword-value pairs of information. So the braket plugin can store task metadata and additional relevant details like price or total simulation time.

You can find additional information on incorporating the tracker in the documentation section on Device tracker support.

I developed a prototype on my own fork, that I can submit as a PR.

Support `LinearCombination` as an observable

Describe the feature you'd like
In v0.36.0 of PennyLane, the new LinearCombination is used in favour of the legacy Hamiltonian, which should also be supported as an observable.

Additional context
There are two classes now to represent a Hamiltonian: qml.ops.Hamiltonian, and qml.ops.LinearCombination. The latter is now used by default in favour of the former. With new opmath enabled, qml.Hamiltonian will refer to LinearCombination, and with new opmath disabled, qml.Hamiltonian will refer to the old Hamiltonian class.

Solution

  1. In braket_device.py, line 169 should be updated to return base_observables.union({"Hamiltonian", "LinearCombination"})
  2. Update all isinstance(..., Hamiltonian) checks to isinstance(..., (qml.ops.Hamiltonian, qml.ops.LinearCombination)), such as line 230 of braket_device.py, line 561 and 691 of translation.py
  3. Update line 584-585 of translation.py to:
@_translate_observable.register(qml.ops.Hamiltonian)
@_translate_observable.register(qml.ops.LinearCombination)
def _(H: Union[qml.ops.Hamiltonian, qml.ops.LinearCombination]):
    ...

Gate ControlledQubitUnitary not supported on device braket.local.qubit

Describe the bug
It mentions on the plugin site that all PennyLane operations are supported. https://amazon-braket-pennylane-plugin-python.readthedocs.io/en/latest/devices/braket_local.html#supported-operations

While running the QuantumPhaseEstimation template from Pennylane on the local device, this error is raised:

raise DeviceError(
pennylane._device.DeviceError: Gate ControlledQubitUnitary not supported on device braket.local.qubit

To reproduce
Use qml.QuantumPhaseEstimation

Expected behavior
Circuit should run without error.

Screenshots or logs
N/A

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version:1.11.2.post0
  • Amazon Braket Python SDK version:1.35.5
  • Amazon Braket Python Schemas version:1.14.1.post0
  • Amazon Braket Python Default Simulator version:1.11.5.post0
  • Python version:3.9.16

Additional context
N/A

Remove references to tape mode in documentation

The documentation on parallel execution of multiple circuits remotely references "tape mode". As of PennyLane v0.14.0 released earlier in the year, tape mode is default and does not need to be manually enabled. Indeed the qml.enable_tape() function will no longer even exist in the upcoming release of v0.15.0 .

We should therefore update the documentation to reflect this,

Xanadu

Describe the feature you'd like
A repository of data for each individual human. to be used in a process of exchange among other humans.

How would this feature be used? Please describe.
A digital fingerprint will enable each human to identify personal creations of art text and image along with copyright information.

Describe alternatives you've considered
Software and login certificates.

Additional context
image

Braket plugin import error for PennyLane version 0.23

Describe the bug
The Braket plugin for PennyLane will fail with import errors due to the renaming in PennyLaneAI/pennylane#2329.

To reproduce
Install PennyLane with the latest dev version and the Braket-PennyLane plugin, and try to import the Braket device.

Expected behavior
There should be no import errors.

Screenshots or logs
https://github.com/PennyLaneAI/plugin-test-matrix/runs/6070544197?check_suite_focus=true

System information

Additional context
PennyLaneAI/pennylane#2329

DEFAULT_RESULTS_POLL_TIMEOUT_SIMULATOR exists in master but not in stable/latest

executing the following commands

virtualenv braket
cd braket
source bin/activate
git clone -b stable/latest https://github.com/aws/braket-python-sdk.git
git clone -b stable/latest https://github.com/aws/amazon-braket-pennylane-plugin-python.git
pip install -e amazon-braket-pennylane-plugin-python
pip install -e braket-python-sdk
python -c "from braket.pennylane_plugin import AWSSimulatorDevice"

produces the error

AttributeError: type object 'AwsQuantumSimulator' has no attribute 'DEFAULT_RESULTS_POLL_TIMEOUT_SIMULATOR'

that is because DEFAULT_RESULTS_POLL_TIMEOUT_SIMULATOR does not exist in the stable/latest branch of the braket-python-sdk.

stable/latest
https://github.com/aws/braket-python-sdk/blob/stable/latest/src/braket/aws/aws_quantum_simulator.py

master
https://github.com/aws/braket-python-sdk/blob/master/src/braket/aws/aws_quantum_simulator.py#L30-L32

Support `batch_execute` with `BraketLocalQubitDevice`

Describe the feature you'd like
The Braket local simulators now support run_batch using local CPU resources. We should allow PennyLane to hook into that functionality.

How would this feature be used? Please describe.
Any use case with many similar small circuits to run, for example SPSA on a 10 qubit circuit or computing a shadows-expval with 5000 shots on a 12 qubit circuit.

Describe alternatives you've considered
N/A.

Additional context
Since both the child classes of BraketQubitDevice support parallelism, maybe it makes sense to move some of the logic up into the parent class?

Update the pinned version of autoray

The upcoming version of PennyLane requires an autoray pinned to a minimum of 0.6.11 (https://github.com/PennyLaneAI/pennylane/blob/2a36a355f212ffba12c8c49d5842eef8a7c6dbdb/setup.py#L32). Currently, the hard upper-limit of 0.6.10 on this plugin causes failures within our CI due to the incompatible version resolutions (see https://github.com/PennyLaneAI/plugin-test-matrix/actions/runs/9310762656/job/25628775590). Can this package version pin be either removed to allow free movement with PennyLane, or be updated to match PennyLane's minimum version of 0.6.11.

This would involve an update to the recently merged PR #256

pennylane>=0.15 for amazon-braket-pennylane-plugin

Describe the bug
pennylane-lightning 0.15.1 requires pennylane>=0.15, but you have pennylane 0.14.1 which is incompatible.
amazon-braket-pennylane-plugin 1.1.1 requires pennylane==0.14.1, but you have pennylane 0.15.1 which is incompatible.

To reproduce
pip install pennylane-lightning
pip install amazon-braket-pennylane-plugin

Expected behavior
Both needs to be version compatible

Additional context
Since some of the features are incompatible between pennylane>=0.15 and pennylane==0.14., it seems like one definitely needs to have Braket plugin support pennylane==0.15

qml.sample() returns error on SV1 simulator

Describe the bug
qml.sample() throws error when run on SV1 simulator . The task is however executed on aws simulator and generates the json.


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-204-05637f991537> in <module>
      4     qml.Hadamard(wires=1)
      5     return qml.sample()
----> 6 circuit()

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/qnode.py in __call__(self, *args, **kwargs)
    583             gradient_kwargs=self.gradient_kwargs,
    584             override_shots=override_shots,
--> 585             **self.execute_kwargs,
    586         )
    587 

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/interfaces/batch/__init__.py in execute(tapes, device, gradient_fn, interface, mode, gradient_kwargs, cache, cachesize, max_diff, override_shots, expand_fn, max_expansion, device_batch_transform)
    411 
    412     res = _execute(
--> 413         tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n=1, max_diff=max_diff, mode=_mode
    414     )
    415 

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/interfaces/batch/autograd.py in execute(tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff, mode)
     70         gradient_kwargs=gradient_kwargs,
     71         _n=_n,
---> 72         max_diff=max_diff,
     73     )[0]
     74 

~/anaconda3/envs/Braket/lib/python3.7/site-packages/autograd/tracer.py in f_wrapped(*args, **kwargs)
     46             return new_box(ans, trace, node)
     47         else:
---> 48             return f_raw(*args, **kwargs)
     49     f_wrapped.fun = f_raw
     50     f_wrapped._is_autograd_primitive = True

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/interfaces/batch/autograd.py in _execute(parameters, tapes, device, execute_fn, gradient_fn, gradient_kwargs, _n, max_diff)
    106     """
    107     with qml.tape.Unwrap(*tapes):
--> 108         res, jacs = execute_fn(tapes, **gradient_kwargs)
    109 
    110     for i, r in enumerate(res):

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/interfaces/batch/__init__.py in wrapper(tapes, **kwargs)
    171         else:
    172             # execute all unique tapes that do not exist in the cache
--> 173             res = fn(execution_tapes.values(), **kwargs)
    174 
    175         final_res = []

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/interfaces/batch/__init__.py in fn(tapes, **kwargs)
    123         def fn(tapes, **kwargs):  # pylint: disable=function-redefined
    124             tapes = [expand_fn(tape) for tape in tapes]
--> 125             return original_fn(tapes, **kwargs)
    126 
    127     @wraps(fn)

~/anaconda3/envs/Braket/lib/python3.7/contextlib.py in inner(*args, **kwds)
     72         def inner(*args, **kwds):
     73             with self._recreate_cm():
---> 74                 return func(*args, **kwds)
     75         return inner
     76 

~/anaconda3/envs/Braket/lib/python3.7/site-packages/braket/pennylane_plugin/braket_device.py in batch_execute(self, circuits, **run_kwargs)
    359     def batch_execute(self, circuits, **run_kwargs):
    360         if not self._parallel:
--> 361             return super().batch_execute(circuits)
    362 
    363         for circuit in circuits:

~/anaconda3/envs/Braket/lib/python3.7/site-packages/pennylane/_qubit_device.py in batch_execute(self, circuits)
    287             self.reset()
    288 
--> 289             res = self.execute(circuit)
    290             results.append(res)
    291 

~/anaconda3/envs/Braket/lib/python3.7/site-packages/braket/pennylane_plugin/braket_device.py in execute(self, circuit, **run_kwargs)
    218     def execute(self, circuit: CircuitGraph, **run_kwargs) -> np.ndarray:
    219         self.check_validity(circuit.operations, circuit.observables)
--> 220         self._circuit = self._pl_to_braket_circuit(circuit, **run_kwargs)
    221         self._task = self._run_task(self._circuit)
    222         braket_result = self._task.result()

~/anaconda3/envs/Braket/lib/python3.7/site-packages/braket/pennylane_plugin/braket_device.py in _pl_to_braket_circuit(self, circuit, **run_kwargs)
    151         for observable in circuit.observables:
    152             dev_wires = self.map_wires(observable.wires).tolist()
--> 153             translated = translate_result_type(observable, dev_wires, self._braket_result_types)
    154             if isinstance(translated, tuple):
    155                 for result_type in translated:

~/anaconda3/envs/Braket/lib/python3.7/site-packages/braket/pennylane_plugin/translation.py in translate_result_type(observable, targets, supported_result_types)
    353         raise NotImplementedError(f"Return type {return_type} unsupported for Hamiltonian")
    354 
--> 355     braket_observable = _translate_observable(observable)
    356     if return_type is ObservableReturnTypes.Expectation:
    357         return Expectation(braket_observable, targets)

~/anaconda3/envs/Braket/lib/python3.7/functools.py in wrapper(*args, **kw)
    838                             '1 positional argument')
    839 
--> 840         return dispatch(args[0].__class__)(*args, **kw)
    841 
    842     funcname = getattr(func, '__name__', 'singledispatch function')

~/anaconda3/envs/Braket/lib/python3.7/site-packages/braket/pennylane_plugin/translation.py in _translate_observable(observable)
    366 @singledispatch
    367 def _translate_observable(observable):
--> 368     raise TypeError(f"Unsupported observable: {observable}")
    369 
    370 

TypeError: Unsupported observable: sample(wires=[])

To reproduce

arn = "arn:aws:braket:::device/quantum-simulator/amazon/sv1"
dev = qml.device("braket.aws.qubit",device_arn=arn, wires=2,shots=1024)
@qml.qnode(dev)
def circuit():
    qml.PauliX(wires=0)
    qml.Hadamard(wires=1)
    return qml.sample()
circuit()

Expected behavior
Should return tensors containing samples.
tensor([[1, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
...,
[1, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0]], requires_grad=True)
Screenshots or logs
If applicable, add screenshots or logs to help explain your problem.

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version:
  • 1.6.5
  • Amazon Braket Python SDK version:
  • 1.24.0
  • Amazon Braket Python Schemas version:
  • 1.8.0.dev0
  • Amazon Braket Python Default Simulator version:
  • 1.3.0
  • Python version: 3.7

Additional context

Support `qml.counts` for circuits

Describe the feature you'd like
qml.counts is already supported for AHS programs. There is a great value in making qml.counts available for circuits.

How would this feature be used? Please describe.

import pennylane as qml
dev = qml.device("braket.local.qubit", wires=2, shots=100)

@qml.qnode(dev)
def test_circ():
    qml.PauliZ(0)
    return qml.counts()

test_circ()

returning measurement counts.

Describe alternatives you've considered
Today, users has to change their circuit to use a Braket supported return type such as qml.expval(qml.PauliZ(0))

@qml.qnode(dev)
def test_circ():
    qml.PauliZ(0)
    return qml.expval(qml.PauliZ(0))

and then do

test_circ.device.task.result().measurement_counts

Users could not use the same circuit to first test on a pennylane simulator before running on a Braket QPU. Also, users do not want to know qml.expval(qml.PauliZ(0)), they just use it to get the circuit to run, so that they can get the measurement_counts stored in the plugin device. Furthermore, when using batch_execute, test_circ.device.task is empty. Users need to go to console and find the results of the tasks they submitted.

Cannot launch Rigetti

I try to launch a Rigetti GPU following this example
https://github.com/aws/amazon-braket-pennylane-plugin-python/blob/5ead8b684d76a3fd7bca3d858b9f7ae7f4a3480a/example.py#L26-L28

But I encounter the Device does not exist error, even though I put device_arn='arn:aws:braket:us-west-1::device/qpu/rigetti/Aspen-M-2' in the function input:

~/opt/anaconda3/lib/python3.9/site-packages/pennylane/__init__.py in device(name, *args, **kwargs)
    335         return dev
    336 
--> 337     raise DeviceError("Device does not exist. Make sure the required plugin is installed.")
    338 
    339 

DeviceError: Device does not exist. Make sure the required plugin is installed.

I think it's because the device name "braket.rigetti" is not valid (or not supported yet?). Could you give some instructions on launching jobs to Rigetti QPUs with this braket-pennylane plugin?

`parametrize_differentiable` not compatible with `custom_decomps`

Describe the bug
pennylane circuits are un-parametrized if there the qnode has custom_decomps keyword argument.

To reproduce

import pennylane.numpy as np
import pennylane as qml

custom_decomps={"IsingXX": qml.IsingXX.compute_decomposition}

dev_local = qml.device(
    "braket.local.qubit",
    wires=2, 
    shots=1000,
    custom_decomps=custom_decomps,
    parametrize_differentiable=True
)

@qml.qnode(dev_local)
def my_pl_circuit(a, b):
    qml.RX(a, wires=0)
    qml.IsingXX(b, wires=[0,1])
    return [qml.expval(qml.PauliZ(i)) for i in range(2)]

a = np.array(0.1)
b = np.array(0.2)
_ = my_pl_circuit(a, b)

print(my_pl_circuit.device.circuit)

Expected behavior
The underlying Braket circuit is a circuit parametrized by free parameters a and b.

Screenshots or logs
The circuit is not parametrized. Even though custom_decomps only applies on the XX gate, the RX gate also loses parametrization and has the value of parameter a bound to it.

T  : |   0    |1|   2    |3| Result Types |
                                           
q0 : -Rx(0.10)-C-Rx(0.20)-C-Expectation(Z)-
               |          |                
q1 : ----------X----------X-Expectation(Z)-

T  : |   0    |1|   2    |3| Result Types |

If I remove the custom_decomps kwarg from qnode, the circuit become parametrized again.

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version: 1.19.2.dev0
  • Amazon Braket Python SDK version: 1.54.0
  • Amazon Braket Python Schemas version: 1.19.1
  • Amazon Braket Python Default Simulator version: 1.20.0
  • Python version: 3.9.7

Additional context
Add any other context about the problem here.

Support shots vectors in `execute` and `batch_execute`.

Describe the feature you'd like
Support for running QuantumTapes with different shot amounts in one fell swoop.

How would this feature be used? Please describe.
Would allow Braket to run tapes with multiple shot counts specified, which currently isn't supported.

Describe alternatives you've considered
We could continue to not support this.

Additional context
Shot vectors are already supported by PL's own devices and their interface with Qiskit.

Support for `SProd`, `Prod`, and `Sum`

Sum

Sum should be handled the same way as Hamiltonian and LinearCombination, which was partially addressed in #252, but the same treatment should be applied to translate_result_type and translate_result in translation.py as well.

Note: Sum.ops is deprecated, so instead of measurement.obs.ops, do _, ops = measurement.obs.terms(), and then use ops.

SProd and Prod

Since SProd and Prod could be nested, they are not guaranteed to be single-term observables. For example, an SProd could be 0.1 * (qml.Z(0) + qml.X(1)), in which case it's actually a Sum. Similarly, a Prod could be qml.Z(0) @ (qml.X(0) + qml.Y(1)).

This means that the same treatment for Hamiltonian, LinearCombination and Sum should extend to SProd and Prod as well, including _translate_observable, which should register Sum, SProd and Prod all under the same dispatch function as Hamiltonian, which uses H.terms().

Caveat: Prod.terms() will resolve to itself if the Prod only contains one term. For example:

>>> op = qml.X(0) @ qml.Y(1)
>>> op.terms()
([1.0], [X(0) @ Y(1)])

This may result in infinite recursion in _translate_observable, so a base case should be added to return reduce(lambda x, y: x @ y, [_translate_observable(factor) for factor in H.operands]) if H is a Prod with a single term.

Note: The terms() function will unwrap any nested structures but also simplify the observable. For example:

>>> op = qml.X(0) @ qml.I(1)
>>> op.terms()
([1.0], [X(0)])

This will create a mismatch between the number of targets in the translated observable and the original observable. We do plan on addressing this issue in PennyLane and have terms() recursively unwraps the observable without doing any simplification, but for now, in _pl_to_braket_circuit, do not use circuit.measurements directly, instead do something like

measurements = []
for mp in circuit.measurements:
    obs = mp.obs
    if isinstance(obs, (Hamiltonian, LinearCombination, Sum, SProd, Prod)):
        obs = obs.simplify()
        mp = type(mp)(obs)
   measurements.append(mp)

Then use measurements instead of circuit.measurements from this point on. The list of simplified measurements should also be passed into _apply_gradient_result_type and used there.

Device

Now since SProd, Prod, and Sum all could be nested, multi-term observables, they should be removed from the list of supported observables and added back if no shots are present:

@property
def observables(self) -> frozenset[str]:
    base_observables = frozenset(super().observables - {"Prod", "SProd", "Sum"})
    # Amazon Braket only supports coefficients and multiple terms when shots==0
    if not self.shots:
        return base_observables.union({"Hamiltonian", "LinearCombination", "Prod", "SProd", "Sum"})
    return base_observables

BraketAwsQubitDevice unnecessarily computes parameter-shifted gradients for SV1.

Describe the bug

Consider a circuit like:

sv1_device_arn = "arn:aws:braket:::device/quantum-simulator/amazon/sv1"
dm1_device_arn = "arn:aws:braket:::device/quantum-simulator/amazon/dm1"
dev = qml.device("braket.aws.qubit", device_arn=sv1_device_arn, wires=nqubits)
nqubits = 4
@qml.qnode(dev)
def quantum_circuit(input, weights):
    # Prepare circuit here
    for i in range(nqubits):
        qml.H(i)
    # Measurement layer
    return [qml.expval(qml.PauliZ(i)) for i in range(nqubits)]

When SV1 is used, this line is triggered. This will compute parameter-shifted derivatives even on the forward pass, when they should not be computed. This makes running with SV1 ~10x slower (and incurs extra costs) compared to DM1.

To reproduce
Run above code snippet.

Expected behavior
The Braket-PL device should only compute the gradient if it's "really" requested.

Screenshots or logs
N/A

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version: 1.23.0
  • Amazon Braket Python SDK version: 1.66.0
  • Amazon Braket Python Schemas version: N/A
  • Amazon Braket Python Default Simulator version: N/A
  • Python version: 3.9

Additional context
One other solution would be to avoid calling execute_and_gradients entirely in this case.

PennyLane v0.28.0 introduces breaking changes

There are breaking change introduced in Pennylane v0.28.0. Python3.7 is no longer supported, and MeasurementProcess is changed in how it's used. If you are using Python3.7, or if you encounter errors about MeasurementProcess, you can try pin the PennyLane version to lower than v0.28.0:

pip install pennylane==0.27.0

Detecting mismatching operations with Catalyst

Describe the bug
Hi,

I am working on Catalyst which is JIT compiler for PennyLane. We have an integration with Amazon Braket that allows users to write quantum circuits expressed as PennyLane's tapes and generate OpenQASM which is then sent to the Amazon Braket for execution.

Catalyst differs a little bit from PennyLane. In particular, Catalyst uses a TOML file to specify which gates and observables are available on the target device. For example, this is a TOML file we use for testing a test device.. PennyLane, on the other hand uses the operations and observables property on the instance of the device being executed. This sometimes leads to a conflict that may result in errors.

In particular amazon-braket-pennylane-plugins 1.27.1 release contained a modification to BraketQubitDevice's observables property (patch inlined below):

diff --git a/src/braket/pennylane_plugin/braket_device.py b/src/braket/pennylane_plugin/braket_device.py
index a45de88..f3866c3 100644
--- a/src/braket/pennylane_plugin/braket_device.py
+++ b/src/braket/pennylane_plugin/braket_device.py
@@ -162,7 +162,7 @@ class BraketQubitDevice(QubitDevice):
 
     @property
     def observables(self) -> frozenset[str]:
-        base_observables = frozenset(super().observables)
+        base_observables = frozenset(super().observables - {"SProd", "Sum"})
         # 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:

The commit removes SProd and Sum observables from the list of supported observables by the device. However, SProd and Sum were not removed Catalyst's TOML file which corresponds to the local braket simulator. And this lead to errors.

The error went away with the release of amazon-braket-pennylane-plugin version 1.27.2 which added back the Sum and SProd observables to the list of supported observables. However, it would be nice if we could guarantee that amazon-braket-pennylane-plugin's list of supported observables and operations doesn't go out of sync with Catalyst's.

To reproduce
pip install pennylane-catalyst amazon-braket-pennylane-plugin==1.27.1

import pennylane as qml

@qml.qjit
@qml.qnode(qml.device("braket.local.qubit", wires=2))
def all_measurements(x):
    qml.RY(x, wires=0)
    return (
        qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)),
        qml.var(qml.PauliZ(1) @ qml.PauliZ(0)),
    )

all_measurements(3.14)

will produce the following error:

catalyst.utils.exceptions.CompileError: Observables in qml.device.observables and specification file do not match.
Observables that present only in spec: {'Sum', 'SProd'}

Expected behavior
It should not throw the CompileError and return instead the following values:

(array(-0.99999873), array(2.53654331e-06))

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version: 1.27.1
  • Amazon Braket Python SDK version: amazon-braket-sdk==1.78.0
  • Amazon Braket Python Schemas version: amazon-braket-sdk==1.78.0
  • Amazon Braket Python Default Simulator version:
  • Python version: 3.10

Use PennyLane measurement processes instead of observables

Hello from PennyLane! I'm here to request a migration from using the Observable type to using the MeasurementProcess type in this plugin, because Observable.return_type is being deprecated in the upcoming release of PennyLane. As this CI run shows, the PL-Braket plugin will need some updating to be compatible with the latest PennyLane.

Request for this plugin

There are various functions that use/accept observables, but some of them actually need measurement processes. For example, BraketQubitDevice.statistics expects a list of Observables, then checks the return_type of the observables. This is a good indicator that we actually want the measurement processes. The proposed fix would be to call statistics with circuit.measurements instead of circuit.observables, probably updating variable names and type-hints along the way.

On the other hand, sometimes we intend on looking at the Observable and not the MeasurementProcess. From what I see, we only want to use Observables when we're about to call _translate_observable. Assuming you rename the observable argument for translate_result_type to something like measurement, you could add something like observable = measurement.obs (perhaps gracefully handling the case where it's None) before translating any Observables, and that should do it!

Background

In PennyLane, measurement processes would previously be described using the Observable class. However, we've been moving towards using the MeasurementProcess class instead, as this encapsulates more accurate/general information about circuit measurements. As an example, consider the qml.probs() measurement - there is no PennyLane Observable being measured per se, but there is a measurement to be processed. This issue has been masked for some time by being able to sneak the type of measurement process onto an Observable (on the return_type property), but it is now deprecated. Comparing QuantumTape.observables to QuantumTape.measurements best highlights this distinction, so I'll show an example here:

>>> tape = qml.tape.QuantumTape(measurements=[qml.expval(qml.PauliZ(0)), qml.state()])
>>> statemp = tape.observables[1]  # note that this is not an Observable
>>> isinstance(statemp, qml.operation.Observable), isinstance(statemp, qml.measurements.MeasurementProcess)
(False, True)
>>> all(isinstance(mp, qml.measurements.MeasurementProcess) for mp in tape.measurements)
True
>>> [mp.obs for mp in tape.measurements]
[PauliZ(wires=[0]), None]

tape.observables will quietly return something that isn't an Observable, which can lead to unexpected behaviour. On the other hand, tape.measurements will always return MeasurementProcess instances. The standard way to check if a process is measuring an observable is mp.obs is not None.

tl;dr, tape.observables returns a mish-mash of Observable and MeasurementProcess instances, whereas tape.measurements always returns a list of MeasurementProcess instances, with the mp.obs property either being an Observable, or None. So, if you need information about a measurement process, you should use tape.measurements.

Word of warning

The Tensor class actually has a property called obs, so there exists a funny case in which you might accidentally refer to the wrong attribute. For example:

>>> tape = qml.tape.QuantumTape(measurements=[qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))])
>>> tape.measurements[0].obs, tape.observables[0].obs
(PauliZ(wires=[0]) @ PauliZ(wires=[1]), [PauliZ(wires=[0]), PauliZ(wires=[1])])

Update the Linux wheels for PennyLane-Lightning simulators to be based on manylinux_2_28

Describe the feature you'd like
PennyLane-Lightning (lightning.qubit, lightning.kokkos and lightning.gpu) PyPI packages are built on manylinux2014 (CentOS 7 with glibc 2.17) up to version 0.36.0. CentOS 7 will reach EOL on June 30th, 2024. As a result, we have updated the PennyLane-Lightning simulators' build system to use the manylinux_2_28 toolchain, which includes glibc version 2.28. This change means that next releases of PennyLane-Lightning simulators will no longer support older distributions that cannot meet the glibc 2.28 requirements.

How would this feature be used? Please describe.
PR PennyLaneAI/pennylane-lightning#667 updates the build system of PennyLane-Lightning simulators to be based on manylinux_2_28. These new Linux wheels should be tested on Amazon Braket Linux systems to ensure compatibility and support.

SV1 calculates only the gradient if parameters are explicitly marked `requires_grad=True`

Describe the bug
If parameters passed into a qnode are PennyLane tensors explicitly marked with requires_grad=True, BraketAwsQubitDevice with SV1 will only calculate measurements through the AdjointGradient result type, which in turn only supports expectation values. As another consequence, attempting to run circuits with other measurements (like var), with more than one observable, or no observables at all (like the Probability measurement) will fail altogether.

To reproduce

In [1]: import pennylane as qml
   ...: from pennylane import numpy as qnp

In [2]: device_arn = "arn:aws:braket:::device/quantum-simulator/amazon/sv1"
   ...: dev = qml.device("braket.aws.qubit", device_arn=device_arn, wires=2, shots=0)

In [3]: weights = qnp.array([0.1, 0.2, 0.3], requires_grad=True)  # trainable

In [4]: weights2 = [0.1, 0.2, 0.3]  # not trainable

In [5]: @qml.qnode(dev)
   ...: def circuit1(a, weights):
   ...:     qml.RZ(a, wires=0)
   ...:     qml.RY(a, wires=1)
   ...:     qml.RX(weights[0], wires=0)
   ...:     qml.RY(weights[1], wires=1)
   ...:     qml.CNOT(wires=[0, 1])
   ...:     qml.RZ(3.14, wires=1)
   ...:     qml.RX(weights[0], wires=1)
   ...:     qml.RX(a, wires=1)
   ...:     return qml.expval(qml.PauliX(wires=0) @ qml.PauliY(wires=1))
   ...: 

In [6]: circuit1(3, weights)  # trainable
   ...: print(dev.circuit)
T  : |  0  |   1   |2|   3    |   4   |  5  |    Result Types    |
                                                                  
q0 : -Rz(3)-Rx(p_2)-C------------------------AdjointGradient(X@Y)-
                    |                        |                    
q1 : -Ry(3)-Ry(p_3)-X-Rz(3.14)-Rx(p_5)-Rx(3)-AdjointGradient(X@Y)-

T  : |  0  |   1   |2|   3    |   4   |  5  |    Result Types    |

Unassigned parameters: [p_2, p_3, p_5].

In [7]: circuit1(3, weights2)  # not trainable
   ...: print(dev.circuit)
T  : |  0  |   1    |2|   3    |   4    |  5  |  Result Types  |
                                                                
q0 : -Rz(3)-Rx(0.10)-C-------------------------Expectation(X@Y)-
                     |                         |                
q1 : -Ry(3)-Ry(0.20)-X-Rz(3.14)-Rx(0.10)-Rx(3)-Expectation(X@Y)-

T  : |  0  |   1    |2|   3    |   4    |  5  |  Result Types  |

Expected behavior
The device should calculate any requested measurement rather than just expectation.

Screenshots or logs
If applicable, add screenshots or logs to help explain your problem.

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version: v1.10.0 (and up)
  • Amazon Braket Python SDK version:
  • Amazon Braket Python Schemas version:
  • Amazon Braket Python Default Simulator version:
  • Python version:

Workaround
Please use versions of the plugin <1.10.0 if you want to use tensors with requires_grad=True.

`batch_execute` doesn't use provided noise model.

Describe the bug
execute will apply a user-provided NoiseModel to circuits, but batch_execute does not.

To reproduce
Run a circuit (e.g. Bell circuit) with a BitFlip(0.5) on all gates using execute and batch_execute - the measurement outcomes will differ substantially.

Expected behavior
batch_execute should apply the device's NoiseModel to all circuits in the batch.

Screenshots or logs
N/A.

System information
A description of your system. Please provide:

  • Amazon Braket Python PennyLane Plugin version: 1.16.1
  • Amazon Braket Python SDK version: 1.42.1
  • Amazon Braket Python Schemas version: 1.17.0
  • Amazon Braket Python Default Simulator version: 1.15.0
  • Python version: 3.10

Additional context
Add any other context about the problem here.

Support `Prod` as observables

Describe the feature you'd like

In the latest version of PennyLane (0.36.0-dev), new opmath is enabled by default. Observables made with @ will now be instances of Prod instead of Tensor. This will not work:

qml.expval(qml.PauliX(0) @ qml.PauliY(1))

because the pennylane-braket plugin currently do not know how to handle Prod.

Solution

In translation.py, add

@_translate_observable.register
def _(t: qml.ops.Prod):
    return reduce(lambda x, y: x @ y, [_translate_observable(factor) for factor in t.operands])

should make it work with new opmath.

Print noisy circuit when a Braket noise model is applied to PL device with `parallel=True`

PennyLane device with Braket backend supports noise model. The noise model added to the device will automatically apply to circuit executed by the device.

Normally, one can call print(device.circuit) to visualize the circuit after the device has executed it. This allows users to check if the noise is applied as expected. But in the case where the device is set to parallel=True, this does not work. The underlying issue is that batch_execute does not populate the deivce's circuit field (because there are multiple circuits being executed on the device).

Describe the feature you'd like
If the device is initialized with parallel=True, the device should cache all of the circuits that have been run on the device so that they can be accessed later. We should also have updated documentation on how to attach a noise model to a device and how to print the resulting circuit(s).

Describe alternatives you've considered
The alternative is to use parallel=False so that only a single circuit is run and populated in the circuit field of the device, and then call print(device.circuit).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.