Tensor#
- class Tensor(array, *, label_template=None)[source]#
Bases:
NDArrayOperatorsMixin
,TolerancesMixin
A tensor representation wrapping single numeric values, dense or sparse arrays.
This class is designed to unify the usage of tensors throughout the stack. It provides a central entry point for the handling of arrays enabling seamless interchange of dense and sparse arrays in any use-case. This is done by implementing this class as an
np.ndarray
container as described here. At the same time this class can also wrap asparse.SparseArray
(which in turn implements thenp.ndarray
interface).- Parameters:
array (Number | ARRAY_TYPE | Tensor) –
the wrapped array object. This can be any of the following objects:
- numpy.ndarray:
a dense matrix
- sparse.SparseArray:
a sparse matrix
- numbers.Number:
any numeric singular value
- Tensor:
another Tensor whose
array
attribute will be extracted
label_template (str | None) – the template string used during the translation procedure implemented in
SparseLabelOp.from_polynomial_tensor()
. WhenNone
, this will fall back to the default template string - see thelabel_template
property for more information.
Attributes
- array#
Returns the wrapped array object.
- atol = 1e-08#
- label_template#
The template string used during the translation implemented in
SparseLabelOp.from_polynomial_tensor()
.If the
label_template
is set toNone
(the default value) during initialization of aTensor
instance, this value will be substituted by the internal default template. Its value depends on the dimension of the wrapped matrix: it will repeat{}_{{}}
for every dimension (independent of its size). This is explained best with an example:print(Tensor(np.eye(4)).label_template) # "{}_{{}} {}_{{}}" print(Tensor(np.ones((3, 1, 2)).label_template) # "{}_{{}} {}_{{}} {}_{{}}" print(Tensor(np.ones((2, 2, 2, 2)).label_template) # "{}_{{}} {}_{{}} {}_{{}} {}_{{}}"
The format of this template allows to construct a
SparseLabelOp
from theTensor
s stored in aPolynomialTensor
. This operation is performed when callingSparseLabelOp.from_polynomial_tensor()
. There, the template is processed using the Python string formatter in two steps:First, the template is formatted using the key under which the
Tensor
object was stored inside of thePolynomialTensor
object. For example:poly = PolynomialTensor( { "+-": Tensor(np.eye(2)), "++--": Tensor(np.ones((2, 2, 2, 2))), } ) # the label_template will get expanded like so: for key, tensor in poly.items(): sparse_label_template = tensor.label_template.format(*key) print(key, "->", sparse_label_template) # "+-" -> "+_{} -_{}" # "++--" -> "+_{} +_{} -_{} -_{}"
Next, these templates are used to build the actual labels of the
SparseLabelOp
being constructed. For that, the indices encountered duringcoord_iter()
are used for example like so:sparse_label_template = "+_{} -_{}" for value, index in Tensor(np.eye(2)).coord_iter(): sparse_label = sparse_label_template.format(*index) print(sparse_label, value) # "+_0 -_0", 1 # "+_0 -_1", 0 # "+_1 -_1", 1 # "+_1 -_0", 0
Given that you now understand how the
label_template
attribute is being used, this allows you to modify how theTensor
objects stored inside aPolynomialTensor
are processed when they are being translated into aSparseLabelOp
.Here is a concrete example which enables you to use chemistry-ordered two-body terms:
eri_chem = ... # chemistry-ordered 2-body integrals (a 4-dimensional array) tensor = Tensor(eri_chem) tensor.label_template = "+_{{0}} +_{{2}} -_{{3}} -_{{1}}" poly = PolynomialTensor({"++--": tensor}) ferm_op_chem = FermionicOp.from_polynomial_tensor(poly) # ferm_op_chem is now identical to the following: from qiskit_nature.second_q.operators.tensor_ordering import to_physicist_ordering eri_phys = to_physicist_ordering(eri_chem) poly = PolynomialTensor({"++--": eri_phys}) ferm_op_phys = FermionicOp.from_polynomial_tensor(poly) print(ferm_op_chem.equiv(ferm_op_phys)) # True
Note
The string formatting in Python is a very powerful tool [1]. Note, that in the use case here, we only ever supply positional arguments in the
.format(...)
calls which means that you cannot use names to identify replacement fields in your label templates. However, you can modify their replacement order using numeric values (like shown below).Another detail to keep in mind, is that the number of replacement fields may _not_ exceed the number of arguments provided to the
.format(...)
call. However, the number of arguments _can_ exceed the number of replacement fields in your template (this will not cause any errors).Both of those noted features were actually used in the example provided above:
a custom ordering of the replacement fields in our template string
a smaller number of replacement fields than arguments (because we already hard-coded the
+
and-
operator strings such that the first expansion to thesparse_label_template
only unpacks one set of curly braces but does not actually inject anything into the template)
Note
You could have also used the following template:
{}_{{0}} {}_{{2}} {}_{{3}} {}_{{1}}
. This will work in the same way if the key under which yourTensor
is stored inside of thePolynomialTensor
is++--
. We did not do this in the example above to show that the number of replacement fields can be smaller than the number of arguments provided during the formatting step, and to simplify the example a little bit.However, if you were to try to use
+_{0} +_{2} -_{3} -_{1}
instead, this will not work as intended because the both string formatting steps are applied unconditionally! Thus, this wrong use case would in fact get expanded to+_+ +_- -_- -_+
in the first step of the processing leaving no replacement fields to be processed in the second step.
- ndim#
Returns the number of dimensions of the wrapped array object.
- rtol = 1e-05#
- shape#
Returns the shape of the wrapped array object.
Methods
- compose(other, qargs=None, front=False)[source]#
Returns the matrix multiplication with another
Tensor
.- Parameters:
- Returns:
The tensor resulting from the composition.
- Raises:
NotImplementedError – when composing
Tensor
instances whoselabel_template
attributes are not falling back to the default.- Return type:
- coord_iter()[source]#
Iterates a matrix yielding pairs of values and their coordinates.
This is best explained with a simple example:
for value, index in Tensor(np.arange(4).reshape((2, 2))).coord_iter(): print(value, index) # 0 (0, 0) # 1 (0, 1) # 2 (1, 0) # 3 (1, 1)
- equiv(other)[source]#
Check equivalence of
Tensor
instances.Note
This check only asserts the internal matrix elements for equivalence but ignores the type of the matrices. As such, it will indicate equivalence of two
Tensor
instances even if one contains sparse and the other dense numpy arrays, as long as their elements match.
- expand(other)[source]#
Returns the reverse-order tensor product with another
Tensor
.- Parameters:
other (Tensor) – the other Tensor.
- Returns:
The tensor resulting from the tensor product, \(other \otimes self\).
- Raises:
NotImplementedError – when expanding
Tensor
instances whoselabel_template
attributes are not falling back to the default.- Return type:
Note
Expand uses reversed operator ordering to
tensor()
. For two tensors of the same typea.expand(b) = b.tensor(a)
.
- tensor(other)[source]#
Returns the tensor product with another
Tensor
.- Parameters:
other (Tensor) – the other Tensor.
- Returns:
The tensor resulting from the tensor product, \(self \otimes other\).
- Raises:
NotImplementedError – when tensoring
Tensor
instances whoselabel_template
attributes are not falling back to the default.- Return type:
Note
Tensor uses reversed operator ordering to
expand()
. For two tensors of the same typea.tensor(b) = b.expand(a)
.
- to_dense()[source]#
Returns a new instance with the internal array converted to a dense numpy array.
If the instance on which this method was called already fulfilled this requirement, it is returned unchanged.
- Return type:
- to_sparse(*, sparse_type=<class 'sparse._coo.core.COO'>)[source]#
Returns a new instance with the internal array converted to a sparse array.
If the instance on which this method was called already fulfilled this requirement, it is returned unchanged.
- Parameters:
sparse_type (Type[COO] | Type[DOK] | Type[GCXS]) – the type to use for the conversion to sparse array. Note, that this will
sparse (only be applied if the wrapped array object was dense. Converting an already) –
explicitly. (array to another sparse type needs to be done) –
- Returns:
A new
Tensor
with the internal array converted to the requested sparse array type.- Return type: