qml.math.TensorBox

class TensorBox(tensor)[source]

Bases: abc.ABC

A container for array-like objects that allows array manipulation to be performed in a unified manner for supported tensor/array manipulation frameworks.

Parameters

tensor (tensor_like) – instantiate the TensorBox container with an array-like object

Warning

The TensorBox class is designed for internal use only, to ensure that PennyLane templates, cost functions, and optimizers retain differentiability across all supported interfaces.

Consider instead using the function wrappers provided in tensorbox.

By wrapping array-like objects in a TensorBox class, array manipulations are performed by simply chaining method calls. Under the hood, the method call is dispatched to the corresponding tensor/array manipulation library based on the wrapped array type, without the need to import any external libraries manually. As a result, autodifferentiation is preserved where needed.

Example

While this is an abstract base class, this class may be ‘instantiated’ directly; by overloading __new__, the tensor argument is inspected, and the correct subclass is returned:

>>> x = tf.Variable([0.4, 0.1, 0.5])
>>> y = TensorBox(x)
>>> print(y)
TensorBox: <tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([0.4, 0.1, 0.5], dtype=float32)>

The original tensor is available via the unbox() method or the data attribute:

>>> y.unbox()
<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([0.4, 0.1, 0.5], dtype=float32)>

In addition, this class defines various abstract methods that all subclasses must define. These methods allow for common manipulations and linear algebra transformations without the need for importing.

>>> y.ones_like()
tf.Tensor([1. 1. 1.], shape=(3,), dtype=float32)

Unless specified, the returned tensors are also TensorBox instances, allowing for method chaining:

>>> y.ones_like().expand_dims(0)
tf.Tensor([[1. 1. 1.]], shape=(1, 3), dtype=float32)

interface

The package that the TensorBox class will dispatch to.

requires_grad

Whether the TensorBox is considered trainable.

shape

returns the shape of the tensor as a tuple of integers

interface

The package that the TensorBox class will dispatch to. The returned strings correspond to those used for PennyLane interfaces.

Type

str, None

requires_grad

Whether the TensorBox is considered trainable.

Note that the implemetation depends on the contained tensor type, and may be context dependent.

For example, Torch tensors and PennyLane tensors track trainability as a property of the tensor itself. TensorFlow, on the other hand,

only tracks trainability if being watched by a gradient tape.

Type

bool

shape

returns the shape of the tensor as a tuple of integers

Type

tuple[int]

T()

Returns the transpose of the tensor.

abs()

TensorBox: Returns the element-wise absolute value.

angle()

TensorBox: Returns the elementwise complex angle.

arcsin()

Returns the element-wise inverse sine of the tensor

astensor(tensor)

Converts the input to the native tensor type of the TensorBox.

block_diag(values)

Combine a sequence of 2D tensors to form a block diagonal tensor.

cast(dtype)

Cast the dtype of the TensorBox.

concatenate(values[, axis])

Join a sequence of tensors along an existing axis.

conj()

TensorBox: Returns the elementwise conjugation.

diag(values[, k])

Construct a diagonal tensor from a list of scalars.

dot(x, y)

Returns the matrix or dot product of two tensors.

expand_dims(axis)

Expand the shape of the tensor.

gather(indices)

Gather tensor values given a tuple of indices.

numpy()

Converts the tensor to a standard, non-differentiable NumPy ndarray, or to a Python scalar if the tensor is 0-dimensional.

ones_like()

Returns a unified tensor of all ones, with the shape and dtype of the unified tensor.

reshape(shape)

Gives a new shape to a tensor without changing its data.

scatter_element_add(index, value)

Add a scalar value to an element of the tensor.

sqrt()

Returns the square root of the tensor

stack(values[, axis])

Stacks a list of tensors along the specified index.

sum([axis, keepdims])

TensorBox: Returns the sum of the tensor elements across the specified dimensions.

take(indices[, axis])

Gather elements from a tensor.

unbox()

Unboxes the TensorBox container, returning the raw interface tensor.

unbox_list(tensors)

Unboxes or unwraps a list of tensor-like objects, converting any TensorBox

where(condition, x, y)

Return a tensor of elements selected from x if the condition is True, y otherwise.

abstract T()[source]

Returns the transpose of the tensor.

abstract abs()[source]

TensorBox: Returns the element-wise absolute value.

abstract angle()[source]

TensorBox: Returns the elementwise complex angle.

abstract arcsin()[source]

Returns the element-wise inverse sine of the tensor

abstract static astensor(tensor)[source]

Converts the input to the native tensor type of the TensorBox.

Parameters

tensor (tensor_like) – array to convert

abstract static block_diag(values)[source]

Combine a sequence of 2D tensors to form a block diagonal tensor.

Parameters

values (Sequence[tensor_like]) – Sequence of 2D arrays/tensors to form the block diagonal tensor.

Returns

the block diagonal tensor

Return type

tensor_like

abstract cast(dtype)[source]

Cast the dtype of the TensorBox.

Parameters

dtype (np.dtype, str) – the NumPy datatype to cast to If the boxed tensor is not a NumPy array, the equivalent datatype in the target framework is chosen.

abstract static concatenate(values, axis=0)[source]

Join a sequence of tensors along an existing axis.

Parameters
  • values (Sequence[tensor_like]) – sequence of arrays/tensors to concatenate

  • axis (int) – axis on which to concatenate

Example

>>> x = tf.Variable([[1, 2], [3, 4]])
>>> a = tf.constant([[5, 6]])
>>> y = TensorBox(x)
>>> y.concatenate([a, y], axis=0)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1, 2],
       [3, 4],
       [5, 6]]), dtype=float32)>
>>> y.concatenate([a, y], axis=1)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1, 2, 5],
       [3, 4, 6]]), dtype=float32)>
>>> y.concatenate([a, y], axis=None)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([1, 2, 3, 4, 5, 6]), dtype=float32)>

Note that this is a static method, so we must pass the unified tensor itself if we would like it to be included.

abstract conj()[source]

TensorBox: Returns the elementwise conjugation.

abstract static diag(values, k=0)[source]

Construct a diagonal tensor from a list of scalars.

Parameters
  • values (Sequence[int or float or complex]) – sequence of numeric values that make up the diagonal

  • k (int) – The diagonal in question. k=0 corresponds to the main diagonal. Use k>0 for diagonals above the main diagonal, and k<0 for diagonals below the main diagonal.

Returns

TensorBox containing the 2D diagonal tensor

Return type

TensorBox

abstract static dot(x, y)[source]

Returns the matrix or dot product of two tensors.

  • If both tensors are 0-dimensional, elementwise multiplication is performed and a 0-dimensional scalar returned.

  • If both tensors are 1-dimensional, the dot product is returned.

  • If the first array is 2-dimensional and the second array 1-dimensional, the matrix-vector product is returned.

  • If both tensors are 2-dimensional, the matrix product is returned.

  • Finally, if the the first array is N-dimensional and the second array M-dimensional, a sum product over the last dimension of the first array, and the second-to-last dimension of the second array is returned.

Parameters

other (tensor_like) – the tensor-like object to right-multiply the TensorBox by

abstract expand_dims(axis)[source]

Expand the shape of the tensor.

Parameters

axis (int or tuple[int]) – the axis or axes where the additional dimensions should be inserted

abstract gather(indices)[source]

Gather tensor values given a tuple of indices.

This is equivalent to the following NumPy fancy indexing:

..code-block:: python

tensor[indices]

Parameters

indices (Sequence[int]) – the indices of the values to extract

abstract numpy()[source]

Converts the tensor to a standard, non-differentiable NumPy ndarray, or to a Python scalar if the tensor is 0-dimensional.

Returns

NumPy ndarray, or Python scalar if the input is 0-dimensional

Return type

array, float, int

Example

>>> x = tf.Variable([0.4, 0.1, 0.5])
>>> y = TensorBox(x)
>>> y.numpy()
array([0.4, 0.1, 0.5], dtype=float32)
abstract ones_like()[source]

Returns a unified tensor of all ones, with the shape and dtype of the unified tensor.

Returns

all ones array

Return type

TensorBox

Example

>>> x = tf.Variable([[0.4, 0.1], [0.1, 0.5]])
>>> y = TensorBox(x)
>>> y.ones_like()
tf.Tensor(
[[1. 1.]
 [1. 1.]], shape=(2, 2), dtype=float32)
abstract reshape(shape)[source]

Gives a new shape to a tensor without changing its data.

Parameters

shape (tuple[int]) – The new shape. The special value of -1 indicates that the size of that dimension is computed so that the total size remains constant. A dimension of -1 can only be specified once.

Returns

TensorBox containing a new view into the tensor with shape shape

Return type

TensorBox

abstract scatter_element_add(index, value)[source]

Add a scalar value to an element of the tensor.

Parameters
  • index (tuple[int]) – the index of the tensor to update

  • value (int or float or complex) – Scalar value to add to the tensor element, in place.

abstract sqrt()[source]

Returns the square root of the tensor

abstract static stack(values, axis=0)[source]

Stacks a list of tensors along the specified index.

Parameters
  • values (Sequence[tensor_like]) – sequence of arrays/tensors to stack

  • axis (int) – axis on which to stack

Returns

TensorBox containing the stacked array

Return type

TensorBox

Example

>>> x = tf.Variable([0.4, 0.1, 0.5])
>>> a = tf.constant([1., 2., 3.])
>>> y = TensorBox(x)
>>> y.stack([a, y])
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[1. , 2. , 3. ],
       [0.4, 0.1, 0.5]], dtype=float32)>

Note that this is a static method, so we must pass the unified tensor itself if we would like it to be included.

abstract sum(axis=None, keepdims=False)[source]

TensorBox: Returns the sum of the tensor elements across the specified dimensions.

Parameters
  • axis (int or tuple[int]) – The axis or axes along which to perform the sum. If not specified, all elements of the tensor across all dimensions will be summed, returning a tensor.

  • keepdims (bool) – If True, retains all summed dimensions.

Example

Summing over all dimensions:

>>> x = tf.Variable([[1., 2.], [3., 4.]])
>>> y = TensorBox(x)
>>> y.sum()
TensorBox: <tf.Tensor: shape=(), dtype=float32, numpy=10.0>

Summing over specified dimensions:

>>> x = np.array([[[1, 1], [5, 3]], [[1, 4], [-6, -1]]])
>>> y = TensorBox(x)
>>> y.shape
(2, 2, 2)
>>> y.sum(axis=(0, 2))
TensorBox: tensor([7, 1], requires_grad=True)
>>> y.sum(axis=(0, 2), keepdims=True)
TensorBox: tensor([[[7],
                    [1]]], requires_grad=True)
abstract take(indices, axis=None)[source]

Gather elements from a tensor.

Note that tensorbox.take(indices, axis=3) is equivalent to tensor[:, :, :, indices, ...] for frameworks that support NumPy-like fancy indexing.

This method is roughly equivalent to np.take and tf.gather. In the case of a 1-dimensional set of indices, it is roughly equivalent to torch.index_select, but deviates for multi-dimensional indices.

Parameters
  • indices (Sequence[int]) – the indices of the values to extract

  • axis – The axis over which to select the values. If not provided, the tensor is flattened before value extraction.

Example

>>> x = torch.tensor([[1, 2], [3, 4]])
>>> y = qml.math.TensorBox(x)
>>> y.take([[0, 0], [1, 0]], axis=1)
TensorBox: tensor([[[1, 1],
         [2, 1]],
[[3, 3],

[4, 3]]])

unbox()[source]

Unboxes the TensorBox container, returning the raw interface tensor.

static unbox_list(tensors)[source]

Unboxes or unwraps a list of tensor-like objects, converting any TensorBox

objects in the list into raw interface tensors.

Parameters

tensors (list[tensor_like]) – list of arrays, tensors, or TensorBox objects

Returns

list[tensor_like]: the input list with all TensorBox objects unwrapped

Example

>>> x = tf.Variable([0.4, 0.1, 0.5])
>>> y = TensorBox(x)
>>> z = tf.constant([0.1, 0.2])

Note that this is a static method, so we must pass the tensor represented by the TensorBox if we would like it to be included.

>>> res = y.unwrap([y, z])
>>> res
[<tf.Variable 'Variable:0' shape=(3,) dtype=float32, numpy=array([0.4, 0.1, 0.5], dtype=float32)>,
 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([0.1, 0.2], dtype=float32)>]
>>> print([type(v) for v in res])
[<class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>,
 <class 'tensorflow.python.framework.ops.EagerTensor'>]
abstract static where(condition, x, y)[source]

Return a tensor of elements selected from x if the condition is True, y otherwise.