qml.devices.default_tensor.DefaultTensor

class DefaultTensor(wires=None, method='mps', c_dtype=<class 'numpy.complex128'>, **kwargs)[source]

Bases: pennylane.devices.device_api.Device

A PennyLane device to perform tensor network simulations of quantum circuits using quimb.

This device is designed to simulate large-scale quantum circuits using tensor networks. For small circuits, other devices like default.qubit may be more suitable.

The backend uses the quimb library to perform the tensor network operations, and different methods can be used to simulate the quantum circuit. The supported methods are Matrix Product State (MPS) and Tensor Network (TN).

This device does not currently support finite-shots or differentiation. At present, the supported measurement types are expectation values, variances and state measurements. Finally, UserWarnings from the cotengra package may appear when using this device.

Parameters
  • wires (int, Iterable[Number, str]) – Number of wires present on the device, or iterable that contains unique labels for the wires as numbers (e.g., [-1, 0, 2]) or strings (e.g., ['aux_wire', 'q1', 'q2']).

  • method (str) – Supported method. The supported methods are "mps" (Matrix Product State) and "tn" (Tensor Network).

  • c_dtype (type) – Complex data type for the tensor representation. Must be one of numpy.complex64 or numpy.complex128.

  • **kwargs – Keyword arguments for the device, passed to the quimb backend.

Keyword Arguments
  • max_bond_dim (int) – Maximum bond dimension for the MPS method. It corresponds to the maximum number of Schmidt coefficients (singular values) retained at the end of the SVD algorithm when applying gates. Default is None (i.e. unlimited).

  • cutoff (float) – Truncation threshold for the Schmidt coefficients in the MPS method. Default is None (which is equivalent to retaining all coefficients).

  • contract (str) – The contraction method for applying gates. The possible options depend on the method chosen. For the MPS method, the options are "auto-mps", "swap+split" and "nonlocal". For a description of these options, see the quimb’s CircuitMPS documentation. Default is "auto-mps". For the TN method, the options are "auto-split-gate", "split-gate", "reduce-split", "swap-split-gate", "split", True, and False. For details, see the quimb’s tensor_core documentation. Default is "auto-split-gate".

  • contraction_optimizer (str) – The contraction path optimizer to use for the computation of local expectation values. For more information on the optimizer options accepted by quimb, see the quimb’s tensor_contract documentation. Default is "auto-hq".

  • local_simplify (str) – The simplification sequence to apply to the tensor network for computing local expectation values. For a complete list of available simplification options, see the quimb’s full_simplify documentation. Default is "ADCRS".

Example:

The following code shows how to create a simple short-depth quantum circuit with 100 qubits using the default.tensor device. Depending on the machine, the execution time for this circuit is around 0.3 seconds:

import pennylane as qml

num_qubits = 100

dev = qml.device("default.tensor", wires=num_qubits)

@qml.qnode(dev)
def circuit(num_qubits):
    for qubit in range(0, num_qubits - 1):
        qml.CZ(wires=[qubit, qubit + 1])
        qml.X(wires=[qubit])
        qml.Z(wires=[qubit + 1])
    return qml.expval(qml.Z(0))
>>> circuit(num_qubits)
tensor(-1., requires_grad=True)

We can provide additional keyword arguments to the device to customize the simulation. These are passed to the quimb backend.

In the following example, we consider a slightly more complex circuit. We use the default.tensor device with the MPS method, setting the maximum bond dimension to 100 and the cutoff to the machine epsilon.

We set "auto-mps" as the contraction technique to apply gates. With this option, quimb turns 3-qubit gates and 4-qubit gates into Matrix Product Operators (MPO) and applies them directly to the MPS. On the other hand, qubits involved in 2-qubit gates may be temporarily swapped to adjacent positions before applying the gate and then returned to their original positions.

import pennylane as qml
import numpy as np

theta = 0.5
phi = 0.1
num_qubits = 50
device_kwargs_mps = {
    "max_bond_dim": 100,
    "cutoff": np.finfo(np.complex128).eps,
    "contract": "auto-mps",
}

dev = qml.device("default.tensor", wires=num_qubits, method="mps", **device_kwargs_mps)

@qml.qnode(dev)
def circuit(theta, phi, num_qubits):
    for qubit in range(num_qubits - 4):
        qml.X(wires=qubit)
        qml.RX(theta, wires=qubit + 1)
        qml.CNOT(wires=[qubit, qubit + 1])
        qml.DoubleExcitation(phi, wires=[qubit, qubit + 1, qubit + 3, qubit + 4])
        qml.CSWAP(wires=[qubit + 1, qubit + 3, qubit + 4])
        qml.RY(theta, wires=qubit + 1)
        qml.Toffoli(wires=[qubit + 1, qubit + 3, qubit + 4])
    return [
        qml.expval(qml.Z(0)),
        qml.expval(qml.Hamiltonian([np.pi, np.e], [qml.Z(15) @ qml.Y(25), qml.Hadamard(40)])),
        qml.var(qml.Y(20)),
    ]
>>> circuit(theta, phi, num_qubits)
[-0.9953099539219951, 0.0036631029671767208, 0.9999999876072984]

After the first execution, the time to run this circuit for 50 qubits is around 0.5 seconds on a standard laptop. Increasing the number of qubits to 500 brings the execution time to approximately 15 seconds, and for 1000 qubits to around 50 seconds.

The time complexity and the accuracy of the results also depend on the chosen keyword arguments for the device, such as the maximum bond dimension. The specific structure of the circuit significantly affects how the time complexity and accuracy of the simulation scale with these parameters.

We can also simulate quantum circuits using the Tensor Network (TN) method. This can be particularly useful for circuits that build up entanglement. The following example shows how to execute a quantum circuit with the TN method and configurable depth using default.tensor.

We set the contraction technique to "auto-split-gate". With this option, each gate is lazily added to the tensor network and nothing is initially contracted, but the gate is automatically split if this results in a rank reduction.

import pennylane as qml

phi = 0.1
depth = 10
num_qubits = 100

dev = qml.device("default.tensor", method="tn", contract="auto-split-gate")

@qml.qnode(dev)
def circuit(phi, depth, num_qubits):
    for qubit in range(num_qubits):
        qml.X(wires=qubit)
    for _ in range(depth):
        for qubit in range(num_qubits - 1):
            qml.CNOT(wires=[qubit, qubit + 1])
        for qubit in range(num_qubits):
            qml.RX(phi, wires=qubit)
    for qubit in range(num_qubits - 1):
        qml.CNOT(wires=[qubit, qubit + 1])
    return qml.expval(qml.Z(0))
>>> circuit(phi, depth, num_qubits)
-0.9511499466743283

The execution time for this circuit with the above parameters is around 0.8 seconds on a standard laptop.

The tensor network method can be faster than MPS and state vector methods in some cases. As a comparison, the time for the exact calculation (i.e., with max_bond_dim = None) of the same circuit using the MPS method of the default.tensor device is approximately three orders of magnitude slower. Similarly, using the default.qubit device results in a much slower simulation.

c_dtype

Tensor complex data type.

method

Method used by the device.

name

The name of the device.

shots

Default shots for execution workflows containing this device.

tracker

A Tracker that can store information about device executions, shots, batches, intermediate results, or any additional device dependent information.

wires

The device wires.

c_dtype

Tensor complex data type.

method

Method used by the device.

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 its shots, not from this property. This property is used to provide a default at the start of a workflow.

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()
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

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.

draw([color])

Draw the current state (wavefunction) associated with the circuit using quimb’s functionality.

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.

expval(measurementprocess)

Expectation value of the supplied observable contained in the MeasurementProcess.

measurement(measurementprocess)

Measure the measurement required by the circuit.

preprocess([execution_config])

This function defines the device transform program to be applied and an updated device configuration.

simulate(circuit)

Simulate a single quantum script.

state(measurementprocess)

Returns the state vector.

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 a given device defines a custom jacobian vector product.

supports_vjp([execution_config, circuit])

Whether or not this device defines a custom vector-Jacobian product.

var(measurementprocess)

Variance of the supplied observable contained in the MeasurementProcess.

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 data structure with all additional information required for execution.

Returns

The Jacobian for each trainable parameter.

Return type

Tuple

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)))

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 as circuit.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.

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 data structure with all additional information required for execution.

Returns

A numeric result of computing the vector-Jacobian product.

Return type

tensor-like

draw(color='auto', **kwargs)[source]

Draw the current state (wavefunction) associated with the circuit using quimb’s functionality.

Internally, it uses quimb’s draw method.

Parameters
  • color (str) – The color of the tensor network diagram. Default is "auto".

  • **kwargs – Additional keyword arguments for the quimb’s draw function. For more information, see the quimb’s draw documentation.

Example

Here is a minimal example of how to draw the current state of the circuit:

import pennylane as qml

dev = qml.device("default.tensor", method="mps", wires=15)

dev.draw()

We can also customize the appearance of the tensor network diagram by passing additional keyword arguments:

dev = qml.device("default.tensor", method="tn", contract=False)

@qml.qnode(dev)
def circuit(num_qubits):
    for i in range(num_qubits):
        qml.Hadamard(wires=i)
    for _ in range(1, num_qubits - 1):
        for i in range(0, num_qubits, 2):
            qml.CNOT(wires=[i, i + 1])
        for i in range(10):
            qml.RZ(1.234, wires=i)
        for i in range(1, num_qubits - 1, 2):
            qml.CZ(wires=[i, i + 1])
        for i in range(num_qubits):
            qml.RX(1.234, wires=i)
    for i in range(num_qubits):
        qml.Hadamard(wires=i)
    return qml.expval(qml.Z(0))

num_qubits = 12

result = circuit(num_qubits)

dev.draw(color="auto", show_inds=True)
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 data structure with additional information required for execution.

Returns

A numeric result of the computation.

Return type

TensorLike, tuple[TensorLike], tuple[tuple[TensorLike]]

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 data structure with all additional information required for execution.

Returns

A numeric result of the computation and the gradient.

Return type

tuple

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)))

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_jvp()

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.

  • execution_config (ExecutionConfig) – a data structure 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

expval(measurementprocess)[source]

Expectation value of the supplied observable contained in the MeasurementProcess.

Parameters

measurementprocess (StateMeasurement) – measurement to apply.

Returns

Expectation value of the observable.

measurement(measurementprocess)[source]

Measure the measurement required by the circuit.

Parameters

measurementprocess (MeasurementProcess) – measurement to apply to the state.

Returns

the result of the measurement.

Return type

TensorLike

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 QuantumTape’s 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

TransformProgram, ExecutionConfig

This device currently:

  • Does not support finite shots.

  • Does not support derivatives.

  • Does not support vector-Jacobian products.

simulate(circuit)[source]

Simulate a single quantum script. This function assumes that all operations provide matrices.

Parameters

circuit (QuantumScript) – The single circuit to simulate.

Returns

The results of the simulation.

Return type

Tuple[TensorLike]

state(measurementprocess)[source]

Returns the state vector.

supports_derivatives(execution_config=None, circuit=None)[source]

Check whether or not derivatives are available for a given configuration and circuit.

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)

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 if compute_jvp() is overridden.

supports_vjp(execution_config=None, circuit=None)[source]

Whether or not this device defines a custom vector-Jacobian product.

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

var(measurementprocess)[source]

Variance of the supplied observable contained in the MeasurementProcess.

Parameters

measurementprocess (StateMeasurement) – measurement to apply.

Returns

Variance of the observable.

Contents

Using PennyLane

Release news

Development

API

Internals