t3svd#

t3toolbox.backend.t3_svd.t3svd(x, max_tt_ranks=None, max_tucker_ranks=None, rtol=None, atol=None, assume_orthogonal=False, sharing=None)#
def t3svd(
        x: typ.Tuple[
            typ.Tuple[NDArray,...], # tucker_cores
            typ.Tuple[NDArray,...], # tt_cores
        ],
        max_tt_ranks:       typ.Sequence[int] = None, # len=d+1
        max_tucker_ranks:   typ.Sequence[int] = None, # len=d
        rtol: float = None,
        atol: float = None,
        assume_orthogonal: bool = False,
        sharing:            typ.Sequence = None,      # len=d, static; group labels (None = unshared)
) -> typ.Tuple[
    typ.Tuple[
        typ.Tuple[NDArray, ...],  # new_tucker_cores
        typ.Tuple[NDArray, ...],  # new_tt_cores
    ],
    typ.Tuple[NDArray,...], # Tucker singular values, len=d
    typ.Tuple[NDArray,...], # TT singular values, len=d+1
]:

Compute (truncated) T3-SVD of TuckerTensorTrain.

Implicit T3-SVD (Algorithm 10), Appendix A.2, of Alger et al. (2026), “Tucker Tensor Train Taylor Series” (arXiv:2603.21141) – the basic algorithm, analogous to Oseledets’ TT-SVD.

Orthogonalize, then a single left-to-right truncating sweep. The result is always left-orthogonal. It is not re-tuned to minimal ranks: a hard rank cap can leave a Tucker rank / bond above its structural minimum (non-minimal), exactly as the paper’s algorithm does. To reduce to minimal ranks, follow with t3_rank_adjustment_sweep() – the output is left-orthogonal, so t3_rank_adjustment_sweep(x, 'right_to_left') minimizes it; check with TuckerTensorTrain.has_minimal_ranks. See docs/t3svd_minimal_ranks.md.

assume_orthogonal=True skips the initial orthogonalization, asserting the input is already right-orthogonal (Tucker down-orthogonal + TT right-orthogonal – the form the L->R sweep needs). Not enforced (verify with TuckerTensorTrain.is_right_orthogonal). A left-orthogonal input must be reversed by the caller (a left-orthogonal T3 reversed is right-orthogonal).

sharing (SF-T3 grouped truncation): a per-mode tuple of hashable group labels ties the Tucker factors within each group – ONE truncated SVD of the concatenated group centers picks one shared basis per group, applied to every group mode (the input’s factors must already be tied within groups; the frontend checks this in safe mode). sharing=None and all-singleton partitions dispatch to the literal unshared sweep above (bit-identical); any partition with a real group runs the two-phase grouped algorithm of _t3svd_shared() for ALL modes (Molozhavenko & Rakhuba 2026, Algorithm 1) – so under truncation, shared and unshared results differ even on exactly-shared input; only the lossless case agrees. The returned Tucker singular values carry the GROUP spectrum s_g at every mode of a group: the singular values of the concatenated matricization [T_(i1) | ... | T_(ik)] of the (phase-1 TT-rounded) tensor – equivalently the Jacobian spectrum of the shared factor (see SharedFrameData). Scale note: sum_j s_gj^2 = k * ||T||^2, so at group modes the per-mode norm identity ||ss_tucker[i]|| = ||T|| is replaced by the sqrt(k)-inflated group version (cancels in condition-number ratios).

Parameters:
  • x (t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Tuple[NDArray, ...], t3toolbox.backend.common.typ.Tuple[NDArray, ...]])

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

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

  • rtol (float)

  • atol (float)

  • assume_orthogonal (bool)

  • sharing (t3toolbox.backend.common.typ.Sequence)

Return type:

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