amazon-braket / amazon-braket-pennylane-plugin-python

A plugin for allowing Xanadu PennyLane to use Amazon Braket devices
https://amazon-braket-pennylane-plugin-python.readthedocs.io/
Apache License 2.0
43 stars 37 forks source link

Use PennyLane measurement processes instead of observables #218

Closed timmysilv closed 9 months ago

timmysilv commented 12 months ago

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])])
math411 commented 11 months ago

Hello and thank you for opening this! Braket is looking at making the changes to prepare for this. I shall assign the issue to myself to ensure this is followed up with.

math411 commented 9 months ago

Merged in https://github.com/amazon-braket/amazon-braket-pennylane-plugin-python/pull/222 to unblock this issue.

math411 commented 9 months ago

I shall resolve this issue once the braket-stable-latest tests start to pass. The rest of the builds are passing within the test matrix. Currently, the Braket stable test is using 1.23.0. The changes were introduced in 1.24.0. The expectation is that once this version is being used for the test, we shall see it begin to pass.

math411 commented 9 months ago

All checks are passing.