qml.devices.default_qubit.DefaultQubit¶
- class DefaultQubit(wires=None, shots=None, seed='global', max_workers=None)[source]¶
Bases:
pennylane.devices.device_api.Device
A PennyLane device written in Python and capable of backpropagation derivatives.
- Parameters
wires (int, Iterable[Number, str]) – Number of wires present on the device, or iterable that contains unique labels for the wires as numbers (i.e.,
[-1, 0, 2]
) or strings (['ancilla', 'q1', 'q2']
). DefaultNone
if not specified.shots (int, Sequence[int], Sequence[Union[int, Sequence[int]]]) – The default number of shots to use in executions involving this device.
seed (Union[str, None, int, array_like[int], SeedSequence, BitGenerator, Generator, jax.random.PRNGKey]) – A seed-like parameter matching that of
seed
fornumpy.random.default_rng
, or a request to seed from numpy’s global random number generator. The default,seed="global"
pulls a seed from NumPy’s global generator.seed=None
will pull a seed from the OS entropy. If ajax.random.PRNGKey
is passed as the seed, a JAX-specific sampling function usingjax.random.choice
and thePRNGKey
will be used for sampling rather thannumpy.random.default_rng
.max_workers (int) – A
ProcessPoolExecutor
executes tapes asynchronously using a pool of at mostmax_workers
processes. Ifmax_workers
isNone
, only the current process executes tapes. If you experience any issue, say using JAX, TensorFlow, Torch, try settingmax_workers
toNone
.
Example:
n_layers = 5 n_wires = 10 num_qscripts = 5 shape = qml.StronglyEntanglingLayers.shape(n_layers=n_layers, n_wires=n_wires) rng = qml.numpy.random.default_rng(seed=42) qscripts = [] for i in range(num_qscripts): params = rng.random(shape) op = qml.StronglyEntanglingLayers(params, wires=range(n_wires)) qs = qml.tape.QuantumScript([op], [qml.expval(qml.Z(0))]) qscripts.append(qs)
>>> dev = DefaultQubit() >>> program, execution_config = dev.preprocess() >>> new_batch, post_processing_fn = program(qscripts) >>> results = dev.execute(new_batch, execution_config=execution_config) >>> post_processing_fn(results) [-0.0006888975950537501, 0.025576307134457577, -0.0038567269892757494, 0.1339705146860149, -0.03780669772690448]
This device currently supports backpropagation derivatives:
>>> from pennylane.devices import ExecutionConfig >>> dev.supports_derivatives(ExecutionConfig(gradient_method="backprop")) True
For example, we can use jax to jit computing the derivative:
import jax @jax.jit def f(x): qs = qml.tape.QuantumScript([qml.RX(x, 0)], [qml.expval(qml.Z(0))]) program, execution_config = dev.preprocess() new_batch, post_processing_fn = program([qs]) results = dev.execute(new_batch, execution_config=execution_config) return post_processing_fn(results)
>>> f(jax.numpy.array(1.2)) DeviceArray(0.36235774, dtype=float32) >>> jax.grad(f)(jax.numpy.array(1.2)) DeviceArray(-0.93203914, dtype=float32, weak_type=True)
Tracking
DefaultQubit
tracks:executions
: the number of unique circuits that would be required on quantum hardwareshots
: the number of shotsresources
: theResources
for the executed circuit.simulations
: the number of simulations performed. One simulation can cover multiple QPU executions, such as for non-commuting measurements and batched parameters.batches
: The number of timesexecute()
is called.results
: The results of each call ofexecute()
derivative_batches
: How many timescompute_derivatives()
is called.execute_and_derivative_batches
: How many timesexecute_and_compute_derivatives()
is calledvjp_batches
: How many timescompute_vjp()
is calledexecute_and_vjp_batches
: How many timesexecute_and_compute_vjp()
is calledjvp_batches
: How many timescompute_jvp()
is calledexecute_and_jvp_batches
: How many timesexecute_and_compute_jvp()
is calledderivatives
: How many circuits are submitted tocompute_derivatives()
orexecute_and_compute_derivatives()
.vjps
: How many circuits are submitted tocompute_vjp()
orexecute_and_compute_vjp()
jvps
: How many circuits are submitted tocompute_jvp()
orexecute_and_compute_jvp()
Accelerate calculations with multiprocessing
Suppose one has a processor with 5 cores or more, these scripts can be executed in parallel as follows
>>> dev = DefaultQubit(max_workers=5) >>> program, execution_config = dev.preprocess() >>> new_batch, post_processing_fn = program(qscripts) >>> results = dev.execute(new_batch, execution_config=execution_config) >>> post_processing_fn(results)
If you monitor your CPU usage, you should see 5 new Python processes pop up to crunch through those
QuantumScript
’s. Beware not oversubscribing your machine. This may happen if a single device already uses many cores, if NumPy uses a multi- threaded BLAS library like MKL or OpenBLAS for example. The number of threads per process times the number of processes should not exceed the number of cores on your machine. You can control the number of threads per process with the environment variables:OMP_NUM_THREADS
MKL_NUM_THREADS
OPENBLAS_NUM_THREADS
where the last two are specific to the MKL and OpenBLAS libraries specifically.
Warning
Multiprocessing may fail depending on your platform and environment (Python shell, script with a protected entry point, Jupyter notebook, etc.) This may be solved changing the so-called start method. The supported start methods are the following:
Windows (win32): spawn (default).
macOS (darwin): spawn (default), fork, forkserver.
Linux (unix): spawn, fork (default), forkserver.
which can be changed with
multiprocessing.set_start_method()
. For example, if multiprocessing fails on macOS in your Jupyter notebook environment, try restarting the session and adding the following at the beginning of the file:import multiprocessing multiprocessing.set_start_method("fork")
Additional information can be found in the multiprocessing doc.
Attributes
The name of the device.
Default shots for execution workflows containing this device.
A
Tracker
that can store information about device executions, shots, batches, intermediate results, or any additional device dependent information.The device wires.
- name¶
The name of the device.
- shots¶
Default shots for execution workflows containing this device.
Note that the device itself should always pull shots from the provided
QuantumTape
and itsshots
, not from this property. This property is used to provide a default at the start of a workflow.
- 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()
- wires¶
The device wires.
Note that wires are optional, and the default value of None means any wires can be used. If a device has wires defined, they will only be used for certain features. This includes:
Validation of tapes being executed on the device
Defining the wires used when evaluating a
state()
measurement
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.
get_prng_keys
([num])Get
num
new keys withjax.random.split
.preprocess
([execution_config])This function defines the device transform program to be applied and an updated device configuration.
Reset the RNG key to its initial value.
supports_derivatives
([execution_config, circuit])Check whether or not derivatives are available for a given configuration and circuit.
supports_jvp
([execution_config, circuit])Whether or not this device defines a custom jacobian vector product.
supports_vjp
([execution_config, circuit])Whether or not this device defines a custom vector jacobian product.
- compute_derivatives(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[source]¶
The vector jacobian product used in reverse-mode differentiation.
DefaultQubit
uses the adjoint differentiation method to compute the VJP.- Parameters
circuits (Union[QuantumTape, Sequence[QuantumTape]]) – the circuit or batch of circuits
cotangents (Tuple[Number, Tuple[Number]]) – Gradient-output vector. Must have shape matching the output shape of the corresponding circuit. If the circuit has a single output, cotangents may be a single number, not an iterable of numbers.
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()
. For computing the full Jacobian, the cotangents can be batched to vectorize the computation. In this case, the cotangents can have the following shapes.batch_size
below refers to the number of entries in the Jacobian:For a state measurement, the cotangents must have shape
(batch_size, 2 ** n_wires)
For
n
expectation values, the cotangents must have shape(n, batch_size)
. Ifn = 1
, then the shape must be(batch_size,)
.
- execute(circuits, execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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:
The provided
circuits
may contain interface specific data-types liketorch.Tensor
orjax.Array
whengradient_method
of"backprop"
is requested. If the gradient method is not backpropagation, then only vanilla numpy parameters or builtins will be present in the circuits.Return Shape
See Return Type Specification for more detailed information.
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.Z(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.Z(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, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[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
cotangents (Tuple[Number, Tuple[Number]]) – Gradient-output vector. Must have shape matching the output shape of the corresponding circuit. If the circuit has a single output, cotangents may be a single number, not an iterable of numbers.
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
- get_prng_keys(num=1)[source]¶
Get
num
new keys withjax.random.split
.A user may provide a
jax.random.PRNGKey
as a random seed. It will be used by the device when executing circuits with finite shots. The JAX RNG is notably different than the NumPy RNG as highlighted in the JAX documentation. JAX does not keep track of a global seed or key, but needs one anytime it draws from a random number distribution. Generating randomness therefore requires changing the key every time, which is done by “splitting” the key. For example, when executingn
circuits, thePRNGkey
is splitn
times into 2 new keys usingjax.random.split
to simulate a non-deterministic behaviour. The device seed is modified in-place using the first key, and the second key is fed to the circuit, and hence can be discarded after returning the results. This same key may be split further down the stack if necessary so that no one key is ever reused.
- preprocess(execution_config=ExecutionConfig(grad_on_execution=None, use_device_gradient=None, use_device_jacobian_product=None, gradient_method=None, gradient_keyword_arguments={}, device_options={}, interface=None, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None)))[source]¶
This function defines the device transform program to be applied and an updated device configuration.
- Parameters
execution_config (Union[ExecutionConfig, Sequence[ExecutionConfig]]) – A data structure describing the parameters needed to fully describe the execution.
- Returns
A transform program that when called returns QuantumTapes that the device can natively execute as well as a postprocessing function to be called after execution, and a configuration with unset specifications filled in.
- Return type
This device supports any qubit operations that provide a matrix
- supports_derivatives(execution_config=None, circuit=None)[source]¶
Check whether or not derivatives are available for a given configuration and circuit.
DefaultQubit
supports backpropagation derivatives with analytic results, as well as adjoint differentiation.- Parameters
execution_config (ExecutionConfig) – The configuration of the desired derivative calculation
circuit (QuantumTape) – An optional circuit to check derivatives support for.
- Returns
Whether or not a derivative can be calculated provided the given information
- Return type
Bool
- supports_jvp(execution_config=None, circuit=None)[source]¶
Whether or not this device defines a custom jacobian vector product.
DefaultQubit
supports backpropagation derivatives with analytic results, as well as adjoint differentiation.- Parameters
execution_config (ExecutionConfig) – The configuration of the desired derivative calculation
circuit (QuantumTape) – An optional circuit to check derivatives support for.
- Returns
Whether or not a derivative can be calculated provided the given information
- Return type
bool
- supports_vjp(execution_config=None, circuit=None)[source]¶
Whether or not this device defines a custom vector jacobian product.
DefaultQubit
supports backpropagation derivatives with analytic results, as well as adjoint differentiation.- Parameters
execution_config (ExecutionConfig) – A description of the hyperparameters for the desired computation.
circuit (None, QuantumTape) – A specific circuit to check differentation for.
- Returns
Whether or not a derivative can be calculated provided the given information
- Return type
bool