TuckerTensorTrain.inner#

t3toolbox.tucker_tensor_train.TuckerTensorTrain.inner(other, use_orthogonalization=True)#
def inner(
        self,
        other,
        use_orthogonalization: bool = True,  # for numerical stability
):

Compute Hilbert-Schmidt inner product of this TuckerTensorTrain with other tensor, result=(self, other)_HS.

The Hilbert-Schmidt inner product is defined with respect to the dense N0 x ... x N(d-1) tensor represented by the TuckerTensorTrain.

For corewise dot product, see t3toolbox.corewise.corewise_dot()

Allowed types are as follows:

  • other: TuckerTensorTrain

    self.inner(other) = np.sum(self.to_dense() * other.to_dense())

  • other: NDArray

    self.inner(other) = np.sum(self.to_dense() * other)

Parameters:
  • other (TuckerTensorTrain) – Other tensor to take the inner product with. Requires other.shape=(N0,...,N(d-1)).

  • use_orthogonalization (bool, optional) – If True, orthogonalize tensors before computing inner product (more stable). If False, use simple zippering without orthogonalization (faster, better for automatic differentiation). Default: use_orthogonalization=True.

Returns:

Hilbert-Schmidt inner product of Tucker tensor trains, (self, other)_HS. If stacked, result.shape=self.stack_shape. Otherwise, result is scalar.

Return type:

scalar or NDArray

Raises:

ValueError

  • Error raised if the TuckerTensorTrains have different shapes and/or stack shapes.

Examples

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((14, 15, 16), (4, 5, 6), (2, 3, 2, 2))
>>> y = t3.TuckerTensorTrain.randn((14, 15, 16), (3, 7, 2), (3, 5, 6, 3))
>>> hs = x.inner(y)                               # Hilbert-Schmidt inner product (a scalar)
>>> print(np.allclose(hs, np.sum(x.to_dense() * y.to_dense())))
True

(T3, T3) with stacking – one inner product per stack element:

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((14, 15, 16), (4, 5, 6), (2, 3, 2, 2), stack_shape=(2, 3))
>>> y = t3.TuckerTensorTrain.randn((14, 15, 16), (3, 7, 2), (3, 5, 6, 3), stack_shape=(2, 3))
>>> hs = x.inner(y)
>>> print(hs.shape)                               # result carries the stack shape
(2, 3)
>>> print(np.allclose(hs, np.sum(x.to_dense() * y.to_dense(), axis=(2, 3, 4))))
True

Inner product of a T3 with a dense tensor:

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((14, 15, 16), (3, 7, 2), (3, 5, 6, 3))
>>> y = np.random.randn(14, 15, 16)
>>> print(np.allclose(x.inner(y), np.sum(x.to_dense() * y)))
True

…with stacking (the dense array carries the stack axes):

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((14, 15, 16), (3, 7, 2), (3, 5, 6, 3), stack_shape=(2, 3))
>>> y = np.random.randn(2, 3, 14, 15, 16)         # shape = stack_shape + shape
>>> print(np.allclose(x.inner(y), np.einsum('ijxyz,ijxyz->ij', x.to_dense(), y)))
True

Gotcha – the two tensors must have the same shape (raises otherwise):

>>> import t3toolbox.tucker_tensor_train as t3
>>> x = t3.TuckerTensorTrain.randn((4, 5), (2, 2), (1, 2, 1))
>>> y = t3.TuckerTensorTrain.randn((4, 6), (2, 2), (1, 2, 1))   # different shape!
>>> x.inner(y)
Traceback (most recent call last):
    ...
ValueError