Help device plugin developers deal with the Operation refactor
See original GitHub issueFeature details
As was discussed in #2023 with @josh146 and @mariaschuld in the light of the Operation refactor a smooth transition with useful deprecation warnings should be ensured so that device developers have time to update their devices and custom Operations and support at least a few versions of PennyLane.
Currently this has not been fully achieved.
Assume that some third party code (e.g a device plugin) defines a “old style” custom Operation as follows:
import pennylane as qml
from pennylane.operation import Operation
class MyOp(Operation):
num_wires = 1
num_params = 2
par_domain = "R"
grad_method = "F"
@staticmethod
def decomposition(*params, wires):
qml.RY(params[0], wires=wires[0])
qml.PauliZ(wires=wires[0])
qml.RX(params[1], wires=wires[0])
dev = qml.device('default.qubit', wires=1)
@qml.qnode(dev)
def qnode(*params):
MyOp(*params, wires=0)
return qml.state()
print(qml.draw(qnode)(0.1, 0.2))
print(qnode(0.1, 0.2))
This works until v0.21.0 but with master the user gets the unspecific error message:
TypeError: decomposition() missing 1 required keyword-only argument: 'wires'
Converting the implementation to “new style” will break the code with all PL versions prior to and including v0.21.0.
This is not nice.
Due to the smart re-naming of functions in #2023 it is indeed possible to define the above operation in a way that is compatible with both the old and the new style:
def decomposition(self, *params, wires=None):
if wires is None:
wires = self.wires
if not params:
params = self.parameters
qml.RY(params[0], wires=wires[0])
qml.PauliZ(wires=wires[0])
qml.RX(params[1], wires=wires[0])
Alternatively one can also directly implement the new compute_decomposition() and patch in a suitable preparation() if one is running on an old PL version. The following also works with both 0.21 and the current master:
class MyOp(Operation):
num_wires = 1
num_params = 2
par_domain = "R"
grad_method = "F"
if not hasattr(Operation, 'get_eigvals'): # pennylane <= v0.21
@classmethod
def decomposition(cls, *params, wires):
return cls.compute_decomposition(*params, wires=wires)
@staticmethod
def compute_decomposition(*params, wires=None):
qml.RY(params[0], wires=wires[0])
qml.PauliZ(wires=wires[0])
qml.RX(params[1], wires=wires[0])
There are of course a few further variants…
It would be nice to replace the above unspecific error message with a useful error that gives a hint for how the implementations can be made compatible across the 0.21/0.22 cut so that plugin developers can at all times support at least some range of PennyLane versions.
Implementation
No response
How important would you say this feature is?
3: Very important! Blocking work.
Additional information
No response
Issue Analytics
- State:
- Created 2 years ago
- Comments:27 (27 by maintainers)

Top Related StackOverflow Question
I can confirm that this works! Awesome! So me and other plugin developers actually have a good update path! Thanks for making this possible!
I plan to have a PR merged before 0.22 that:
qml.generator()function as the main UI/public APIgenerator()toget_generator()temporarilyI’ll have to think if there are any implications here - one reason for preferring
staticmethodsis that we make use of caching (e.g., via@lrucache()) down the line.I’m not 100% I follow here - are you wishing to call a class method from inside
compute_matrixfor example? Would you be able to do something like?