dense_t3svd#

t3toolbox.backend.t3_svd.dense_t3svd(T, stack_shape=(), max_tucker_ranks=None, max_tt_ranks=None, rtol=None, atol=None)#
def dense_t3svd(
        T: common.NDArray, # shape=stack_shape+(N0, .., N(d-1))
        stack_shape: typ.Sequence[int] = (),
        max_tucker_ranks:  typ.Sequence[int] = None,  # len=d
        max_tt_ranks:  typ.Sequence[int] = None,  # len=d+1
        rtol: float = None,
        atol: float = None,
) -> typ.Tuple[
    typ.Tuple[
        typ.Tuple[common.NDArray,...], # tucker_cores
        typ.Tuple[common.NDArray,...], # tt_cores
    ], # Approximation of T by Tucker tensor train
    typ.Tuple[common.NDArray,...], # Tucker singular values, len=d
    typ.Tuple[common.NDArray,...], # TT singular values, len=d+1
]:

Compute TuckerTensorTrain and edge singular values for dense tensor.

Examples

No truncation – a lossless T3 (Tucker + tensor-train) decomposition. Each Tucker basis B is contracted into its TT core G to rebuild the dense tensor:

>>> import numpy as np
>>> import t3toolbox.backend.t3_svd as t3_svd
>>> np.random.seed(0)
>>> T = np.random.randn(5, 6, 7)
>>> (tucker_cores, tt_cores), ss_tucker, ss_tt = t3_svd.dense_t3svd(T)
>>> print([B.shape for B in tucker_cores], [G.shape for G in tt_cores])
[(5, 5), (6, 6), (7, 7)] [(1, 5, 5), (5, 6, 7), (7, 7, 1)]
>>> GG_big = [np.einsum('io,aib->aob', B, G) for B, G in zip(tucker_cores, tt_cores)]
>>> T2 = np.einsum('aib,bjc,ckd->ijk', *GG_big)
>>> print(np.allclose(T, T2))                      # exact reconstruction
True
>>> print(len(ss_tucker), len(ss_tt))              # d Tucker spectra, d+1 TT spectra
3 4

Stacked – a leading stack_shape rides along on every core; the decomposition is vectorized over the stack:

>>> import numpy as np
>>> import t3toolbox.backend.t3_svd as t3_svd
>>> np.random.seed(0)
>>> T = np.random.randn(2, 3, 5, 6, 7)
>>> (tucker_cores, tt_cores), _, _ = t3_svd.dense_t3svd(T, stack_shape=(2, 3))
>>> print([B.shape for B in tucker_cores])         # stack_shape=(2,3) prefixes each core
[(2, 3, 5, 5), (2, 3, 6, 6), (2, 3, 7, 7)]
>>> GG_big = [np.einsum('...io,...aib->...aob', B, G) for B, G in zip(tucker_cores, tt_cores)]
>>> T2 = np.einsum('...aib,...bjc,...ckd->...ijk', *GG_big)
>>> print(np.allclose(T, T2))
True

Truncation – a smooth tensor has gradually decaying spectra, so rtol truncates meaningfully (a sharp random spectrum would not):

>>> import numpy as np
>>> import t3toolbox.backend.t3_svd as t3_svd
>>> i, j, k = np.ogrid[1:9, 1:9, 1:9]
>>> T = 1.0 / (i + j + k)                          # graded-spectrum tensor
>>> (tk_f, tt_f), ss_tk_full, ss_tt_full = t3_svd.dense_t3svd(T)        # full spectra
>>> (tk, tt), _, _ = t3_svd.dense_t3svd(T, rtol=1e-3)                   # truncate at rtol
>>> tucker_ranks = tuple(B.shape[0] for B in tk)
>>> tt_ranks = tuple(G.shape[0] for G in tt) + (1,)
>>> print(tuple(B.shape[0] for B in tk_f), '->', tucker_ranks)         # Tucker ranks drop
(8, 8, 8) -> (3, 3, 3)
>>> print(tuple(G.shape[0] for G in tt_f) + (1,), '->', tt_ranks)      # TT ranks drop
(1, 8, 8, 1) -> (1, 3, 3, 1)
>>> GG_big = [np.einsum('io,aib->aob', B, G) for B, G in zip(tk, tt)]
>>> T2 = np.einsum('aib,bjc,ckd->ijk', *GG_big)
>>> dropped_sq = (sum(float(np.sum(s[r:]**2)) for s, r in zip(ss_tt_full, tt_ranks))
...             + sum(float(np.sum(s[r:]**2)) for s, r in zip(ss_tk_full, tucker_ranks)))
>>> print(bool(np.linalg.norm(T - T2) <= np.sqrt(dropped_sq)))  # accuracy bound [Oseledets]
True

Tolerances need a single (unstacked) tensor – rtol/atol with a non-empty stack_shape raise, since different slices could truncate to different ranks (use max_*_ranks instead):

>>> import numpy as np
>>> import t3toolbox.backend.t3_svd as t3_svd
>>> np.random.seed(0)
>>> T = np.random.randn(2, 3, 5, 6, 7)
>>> t3_svd.dense_t3svd(T, stack_shape=(2, 3), rtol=1e-3)
Traceback (most recent call last):
    ...
ValueError
Parameters:
  • T (NDArray)

  • stack_shape (t3toolbox.backend.common.typ.Sequence[int])

  • max_tucker_ranks (t3toolbox.backend.common.typ.Sequence[int])

  • max_tt_ranks (t3toolbox.backend.common.typ.Sequence[int])

  • rtol (float)

  • atol (float)

Return type:

t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis], t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]], t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis], t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]]