qml.devices.experimental.Device¶
-
class
Device
[source]¶ Bases:
abc.ABC
A device driver that can control one or more backends. A backend can be either a physical Quantum Processing Unit or a virtual one such as a simulator.
Warning
This interface is experimental and not yet integrated with the rest of PennyLane.
Device drivers should be configured to run under
enable_return()
, the newer return shape specification.Only the
execute
method must be defined to construct a device driver.Design Motivation
Streamlined interface: Only methods that are required to interact with the rest of PennyLane will be placed in the interface. Developers will be able to clearly see what they can change while still having a fully functional device.
Reduction of duplicate methods: Methods that solve similar problems are combined together. Only one place will have to solve each individual problem.
Support for dynamic execution configurations: Properties such as shots belong to specific executions.
Greater coverage for differentiation methods: Devices can define any order of derivative, the vector jacobian product, or the jacobian vector product. Calculation of derivatives can be done at the same time as execution to allow reuse of intermediate results.
Porting from the old interface
pennylane.Device.batch_execute()
andexecute()
are now a single method,execute()
batch_transform()
andexpand_fn()
are now a single method,preprocess()
Shot information is no longer stored on the device, but instead specified on individual input
QuantumTape
.The old devices defined a
capabilities()
dictionary that defined characteristics of the devices and controlled various preprocessing and validation steps, such as"supports_broadcasting"
. These capabilites should now be handled by thepreprocess()
method. For example, if a device does not support broadcasting,preprocess
should split a quantum script with broadcasted parameters into a batch of quantum scripts. If the device does not support mid circuit measurements, thenpreprocess
should applydefer_measurements()
. A set of default preprocessing steps will be available to make a seamless transition to the new interface.A class will be provided to easily construct default preprocessing steps from supported operations, supported observables, supported measurement processes, and various capabilities.
Utility functions will be added to the
devices
module to query whether or not the device driver can do certain things, such asdevices.supports_operator(op, dev, native=True)
. These functions will work by checking the behaviour ofpreprocess()
to certain inputs.Versioning should be specified by the package containing the device. If an external package includes a PennyLane device, then the package requirements should specify the minimium PennyLane version required to work with the device.
Execution Configuration
Execution config properties related to configuring a device include:
device_options
: A dictionary of device specific options. For example, the python device may havemultiprocessing_mode
as a key. These should be documented in the class docstring.gradient_method
: A device can choose to have native support for any type of gradient method. If the methodsupports_derivatives()
returnsTrue
for a particular gradient method, it will be treated as a device derivative and not handled by pennylane core code.gradient_keyword_arguments
: Options for the gradient method.derivative_order
: Relevant for requested device derivatives.
Attributes
The name of the device or set of devices.
A
Tracker
that can store information about device executions, shots, batches, intermediate results, or any additional device dependent information.-
name
¶ The name of the device or set of devices.
This property can either be the name of the class, or an alias to be used in the
device()
constructor, such as"default.qubit"
or"lightning.qubit"
.
-
tracker
: pennylane.tracker.Tracker = <pennylane.tracker.Tracker object>¶ A
Tracker
that can store information about device executions, shots, batches, intermediate results, or any additional device dependent information.A plugin developer can store information in the tracker by:
# querying if the tracker is active if self.tracker.active: # store any keyword: value pairs of information self.tracker.update(executions=1, shots=self._shots, results=results) # Calling a user-provided callback function self.tracker.record()
Methods
compute_derivatives
(circuits[, execution_config])Calculate the jacobian of either a single or a batch of circuits on the device.
compute_jvp
(circuits, tangents[, …])The jacobian vector product used in forward mode calculation of derivatives.
compute_vjp
(circuits, cotangents[, …])The vector jacobian product used in reverse-mode differentiation.
execute
(circuits[, execution_config])Execute a circuit or a batch of circuits and turn it into results.
execute_and_compute_derivatives
(circuits[, …])Compute the results and jacobians of circuits at the same time.
execute_and_compute_jvp
(circuits, tangents)Execute a batch of circuits and compute their jacobian vector products.
execute_and_compute_vjp
(circuits, cotangents)Calculate both the results and the vector jacobian product used in reverse-mode differentiation.
preprocess
(circuits[, execution_config])Device preprocessing function.
supports_derivatives
([execution_config, circuit])Determine whether or not a device provided derivative is potentially available.
supports_jvp
([execution_config, circuit])Whether or not a given device defines a custom jacobian vector product.
supports_vjp
([execution_config, circuit])Whether or not a given device defines a custom vector jacobian product.
-
compute_derivatives
(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Calculate the jacobian of either a single or a batch of circuits on the device.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuits to calculate derivatives for
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
The jacobian for each trainable parameter
- Return type
Tuple
See also
supports_derivatives()
andexecute_and_compute_derivatives()
.Execution Config:
The execution config has
gradient_method
andorder
property that describes the order of differentiation requested. If the requested method or order of gradient is not provided, the device should raise aNotImplementedError
. Thesupports_derivatives()
method can pre-validate supported orders and gradient methods.Return Shape:
If a batch of quantum scripts is provided, this method should return a tuple with each entry being the gradient of each individual quantum script. If the batch is of length 1, then the return tuple should still be of length 1, not squeezed.
-
compute_jvp
(circuits, tangents, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ The jacobian vector product used in forward mode calculation of derivatives.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuit or batch of circuits
tangents (tensor-like) – Gradient vector for input parameters.
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
A numeric result of computing the jacobian vector product
- Return type
Tuple
Definition of jvp:
If we have a function with jacobian:
\[\vec{y} = f(\vec{x}) \qquad J_{i,j} = \frac{\partial y_i}{\partial x_j}\]The Jacobian vector product is the inner product with the derivatives of \(x\), yielding only the derivatives of the output \(y\):
\[\text{d}y_i = \Sigma_{j} J_{i,j} \text{d}x_j\]Shape of tangents:
The
tangents
tuple should be the same length ascircuit.get_parameters()
and have a single number per parameter. If a number is zero, then the gradient with respect to that parameter does not need to be computed.
-
compute_vjp
(circuits, cotangents, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ The vector jacobian product used in reverse-mode differentiation.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuit or batch of circuits
cotangents (Tuple[Number]) – Gradient-output vector. Must have shape matching the output shape of the corresponding circuit
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
A numeric result of computing the vector jacobian product
- Return type
tensor-like
Definition of vjp:
If we have a function with jacobian:
\[\vec{y} = f(\vec{x}) \qquad J_{i,j} = \frac{\partial y_i}{\partial x_j}\]The vector jacobian product is the inner product of the derivatives of the output
y
with the Jacobian matrix. The derivatives of the output vector are sometimes called the cotangents.\[\text{d}x_i = \Sigma_{i} \text{d}y_i J_{i,j}\]Shape of cotangents:
The value provided to
cotangents
should match the output ofexecute()
.
-
abstract
execute
(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Execute a circuit or a batch of circuits and turn it into results.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the quantum circuits to be executed
execution_config (ExecutionConfig) – a datastructure with additional information required for execution
- Returns
A numeric result of the computation.
- Return type
TensorLike, tuple[TensorLike], tuple[tuple[TensorLike]]
Interface parameters:
Note that the parameters contained within the quantum script may contain interface-specific data types, such as
torch.Tensor
orjax.Array
. If the device does not wish to handle interface-specific parameters, they can implement an optional “internal preprocessing” step that converts all parameters to vanilla numpy. A convenience transform implementing this will be provided. This step allows device to be transparent to things like jitting if they so choose.Return Shape
The result for each
QuantumTape
must match the shape specified byshape
.The level of priority for dimensions from outer dimension to inner dimension is:
Quantum Script in batch
Shot choice in a shot vector
Measurement in the quantum script
Parameter broadcasting
Measurement shape for array-valued measurements like probabilities
For a batch of quantum scripts with multiple measurements, a shot vector, and parameter broadcasting:
result[0]
: the results for the first scriptresult[0][0]
: the first shot number in the shot vectorresult[0][0][0]
: the first measurement in the quantum scriptresult[0][0][0][0]
: the first parameter broadcasting choiceresult[0][0][0][0][0]
: the first value for an array-valued measurement
With the exception of quantum script batches, dimensions with only a single component should be eliminated.
For example:
With a single script and a single measurement process, execute should return just the measurement value in a numpy array.
shape
currently accepts a device, as historically devices stored shot information. In the future, this method will accept anExecutionConfig
instead.>>> tape = qml.tape.QuantumTape(measurements=qml.expval(qml.PauliZ(0))]) >>> tape.shape(dev) () >>> dev.execute(tape) array(1.0)
If execute recieves a batch of scripts, then it should return a tuple of results:
>>> dev.execute([tape, tape]) (array(1.0), array(1.0)) >>> dev.execute([tape]) (array(1.0),)
If the script has multiple measurments, then the device should return a tuple of measurements.
>>> tape = qml.tape.QuantumTape(measurements=[qml.expval(qml.PauliZ(0)), qml.probs(wires=(0,1))]) >>> tape.shape(dev) ((), (4,)) >>> dev.execute(tape) (array(1.0), array([1., 0., 0., 0.]))
-
execute_and_compute_derivatives
(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Compute the results and jacobians of circuits at the same time.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuits or batch of circuits
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
A numeric result of the computation and the gradient.
- Return type
tuple
See
execute()
andcompute_derivatives()
for more information about return shapes and behaviour. Ifcompute_derivatives()
is defined, this method should be as well.This method can be used when the result and execution need to be computed at the same time, such as during a forward mode calculation of gradients. For certain gradient methods, such as adjoint diff gradients, calculating the result and gradient at the same can save computational work.
-
execute_and_compute_jvp
(circuits, tangents, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Execute a batch of circuits and compute their jacobian vector products.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – circuit or batch of circuits
tangents (tensor-like) – Gradient vector for input parameters.
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
A numeric result of execution and of computing the jacobian vector product
- Return type
Tuple, Tuple
See also
-
execute_and_compute_vjp
(circuits, cotangents, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Calculate both the results and the vector jacobian product used in reverse-mode differentiation.
- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuit or batch of circuits to be executed
Tuple[Number] (cotangents) – Gradient-output vector. Must have shape matching the output shape of the corresponding circuit
execution_config (ExecutionConfig) – a datastructure with all additional information required for execution
- Returns
the result of executing the scripts and the numeric result of computing the vector jacobian product
- Return type
Tuple, Tuple
See also
-
preprocess
(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface='autograd', derivative_order=1))[source]¶ Device preprocessing function.
Warning
This function is tracked by machine learning interfaces and should be fully differentiable. The
pennylane.math
module can be used to construct fully differntiable transformations.Additional preprocessing independent of machine learning interfaces can be done inside of the
execute()
metod.- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – The circuit or a batch of circuits to preprocess before execution on the device
execution_config (ExecutionConfig) – A datastructure describing the parameters needed to fully describe the execution.
Tuple[QuantumTape] – QuantumTapes that the device can natively execute,
Callable – QuantumTapes that the device can natively execute,
ExecutionConfig – QuantumTapes that the device can natively execute,
postprocessing function to be called after execution (a) –
a configuration with unset specifications filled in. (and) –
- Raises
Exception – An exception is raised if the input cannot be converted into a form supported by the device.
Preprocessing steps may include:
expansion to
Operator
’s andMeasurementProcess
objects supported by the device.splitting a circuit with the measurement of non-commuting observables or Hamiltonians into multiple executions
splitting circuits with batched parameters into multiple executions
gradient specific preprocessing, such as making sure trainable operators have generators
validation of configuration parameters
choosing a best gradient method and
grad_on_execution
value.
-
supports_derivatives
(execution_config=None, circuit=None)[source]¶ Determine whether or not a device provided derivative is potentially available.
Default behaviour assumes first order device derivatives for all circuits exist if
compute_derivatives()
is overriden.- Parameters
execution_config (ExecutionConfig) – A description of the hyperparameters for the desired computation.
circuit (None, QuantumTape) – A specific circuit to check differentation for.
- Returns
Bool
The device can support multiple different types of “device derivatives”, chosen via
execution_config.gradient_method
. For example, a device can natively calculate"parameter-shift"
derivatives, in which casecompute_derivatives()
will be called for the derivative instead ofexecute()
with a batch of circuits.>>> config = ExecutionConfig(gradient_method="parameter-shift") >>> custom_device.supports_derivatives(config) True
In this case,
compute_derivatives()
orexecute_and_compute_derivatives()
will be called instead ofexecute()
with a batch of circuits.If
circuit
is not provided, then the method should return whether or not device derivatives exist for any circuit.Example:
For example, the Python device will support device differentiation via the adjoint differentiation algorithm if the order is
1
and the execution occurs with no shots (shots=None
).>>> config = ExecutionConfig(derivative_order=1, shots=None, gradient_method="adjoint") >>> dev.supports_derivatives(config) True >>> config = ExecutionConfig(derivative_order=1, shots=10, gradient_method="adjoint") >>> dev.supports_derivatives(config) False >>> config = ExecutionConfig(derivative_order=2, shots=None, gradient_method="adjoint") >>> dev.supports_derivatives(config) False
Adjoint differentiation will only be supported for circuits with expectation value measurements. If a circuit is provided and it cannot be converted to a form supported by differentiation method by
preprocess()
, thensupports_derivatives
should return False.>>> config = ExecutionConfig(derivative_order=1, shots=None, gradient_method="adjoint") >>> circuit = qml.tape.QuantumScript([qml.RX(2.0, wires=0)], [qml.probs(wires=(0,1))]) >>> dev.supports_derivatives(config, circuit=circuit) False
If the circuit is not natively supported by the differentiation method but can be converted into a form that is supported, it should still return
True
. For example,Rot
gates are not natively supported by adjoint differentation, as they do not have a generator, but they can be compiled into operations supported by adjoint differentiation. Therefore this method may reproduce compilation and validation steps performed bypreprocess()
.>>> config = ExecutionConfig(derivative_order=1, shots=None, gradient_method="adjoint") >>> circuit = qml.tape.QuantumScript([qml.Rot(1.2, 2.3, 3.4, wires=0)], [qml.expval(qml.PauliZ(0))]) >>> dev.supports_derivatives(config, circuit=circuit) True
Backpropagation:
This method is also used be to validate support for backpropagation derivatives. Backpropagation is only supported if the device is transparent to the machine learning framework from start to finish.
>>> config = ExecutionConfig(gradient_method="backprop", framework="torch") >>> python_device.supports_derivatives(config) True >>> cpp_device.supports_derivatives(config) False
-
supports_jvp
(execution_config=None, circuit=None)[source]¶ Whether or not a given device defines a custom jacobian vector product.
- Parameters
execution_config (ExecutionConfig) – A description of the hyperparameters for the desired computation.
circuit (None, QuantumTape) – A specific circuit to check differentation for.
Default behaviour assumes this to be
True
ifcompute_jvp()
is overridden.
-
supports_vjp
(execution_config=None, circuit=None)[source]¶ Whether or not a given device defines a custom vector jacobian product.
- Parameters
execution_config (ExecutionConfig) – A description of the hyperparameters for the desired computation.
circuit (None, QuantumTape) – A specific circuit to check differentation for.
Default behaviour assumes this to be
True
ifcompute_vjp()
is overridden.