compute_continuation_ranks#

t3toolbox.backend.ranks.compute_continuation_ranks(shape, tucker_singular_values, tt_singular_values, tau=10.0, n_chunk=1, kappa_guard=1000000000000.0, max_grow=None, sharing=None)#
def compute_continuation_ranks(
        shape:                  typ.Sequence[int],      # (N0, ..., N(d-1))
        tucker_singular_values: typ.Sequence[NDArray],  # len=d,   elm_shape=(n_i,), descending
        tt_singular_values:     typ.Sequence[NDArray],  # len=d+1, elm_shape=(r_i,), descending
        tau:                    float = 10.0,           # grow edge i only if kappa_i < kappa_max / tau  (tau > 1)
        n_chunk:                int   = 1,              # rank increment added to each grown edge
        kappa_guard:            float = 1e12,           # absolute safety cap: never grow an edge with kappa_i >= this
        max_grow:               typ.Optional[int] = None,  # cap on #edges grown per call (None = all eligible)
        sharing:                typ.Optional[typ.Sequence] = None,  # len=d, static; one hashable group label per mode (None = unshared)
) -> typ.Tuple[
    typ.Tuple[int, ...],  # (n0', ..., n(d-1)')  new Tucker ranks
    typ.Tuple[int, ...],  # (r0', ..., rd')      new TT ranks
]:

Rank-continuation update: choose new ranks from the current iterate’s unfolding singular values.

Section 5.4.1 (“Choosing the new ranks”) of Alger et al. (2026), “Tucker Tensor Train Taylor Series” (arXiv:2603.21141). Grow only the well-conditioned edges – those a factor tau below the worst-conditioned edge – so the increases bring all edges toward comparable conditioning:

n_i' = n_i + n_chunk  if kappa^Tucker_i < kappa_max / tau  else n_i
r_i' = r_i + n_chunk  if kappa^TT_i     < kappa_max / tau  else r_i

with kappa_max the largest (finite) edge condition number (edge_condition_numbers()). The current ranks n_i = len(tucker_singular_values[i]) and r_i = len(tt_singular_values[i]) are read off the provided singular values, so pass the structural-rank T3-SVD output (t3svd() with no truncation); a truncated SVD instead grows from the numerical rank. The boundary TT bonds r_0, r_d are never grown.

Warning

Do not pass uniform (``ut3svd``) singular values here. This is a ragged, host-side function and it infers the current ranks from len(s[i]). Uniform spectra are padded to the supercore’s nominal rank, so every len is the padded width rather than the true rank, and the padding zeros make kappa_i infinite – the call type-checks and returns silently wrong ranks (in a measured case ((2,2,2),(1,2,2,1)) where the truth was ((3,3,3),(1,3,3,1)), i.e. a spurious “stop continuing”). Rank continuation is deliberately a ragged-layer activity: run the bookkeeping on the ragged point and drop into the uniform layer only for the fit itself (docs/rank_continuation.md, “On the uniform layer”).

Proposed ranks are then de-degenerated by compute_minimal_ranks() (the paper’s “useless-rank removal” – shape and ranks only, no linear algebra); if that leaves the ranks unchanged (every edge already comparably conditioned, or all increases removed) every (below-guard) rank is bumped by n_chunk and re-cleaned, so continuation makes progress unless the structure is already maximal.

Absolute conditioning guard (kappa_guard, a numerical safety net distinct from the relative tau rule): an edge is grown only if kappa_i < kappa_guard as well – so an edge that is well conditioned relative to a catastrophic edge but ill conditioned in absolute terms is still frozen. If no edge is below the guard (every growable edge is extremely ill conditioned or rank-deficient), nothing grows and the returned ranks equal the input ranks – the caller’s signal to stop the whole continuation. The default 1e12 is large: it should fire only on genuine near-degeneracy, never during a well-behaved fit. (Note “ranks unchanged” is also returned when the structure is already maximal; both mean “stop”. The caller can call edge_condition_numbers() to tell the two apart for reporting.)

Edges per round (max_grow): None (default) grows every eligible edge at once – the Section 5.4.1 rule. An integer k grows only the k best-conditioned eligible edges that survive useless-rank removal (greedy, smallest condition number first, skipping a structurally-capped edge for the next candidate). max_grow=1 is one edge at a time (the tau -> infinity intent, made robust against the spectrum-dependence and structural caps that make a large tau unreliable); pair it with tau=1.0 to grow the single best-conditioned edge each round regardless of the conditioning spread. The uniform-bump fallback is not capped by max_grow, so continuation can still escape a degenerate start (e.g. all-ones, where no single edge can grow – a Tucker rank and its neighboring bond must grow together).

The paper uses tau = 10.0 and typically n_chunk = 1. Pure host arithmetic on ranks (structure), hence numpy-only – a between-solves decision, never inside a jit trace.

With sharing (one hashable group label per mode – validate_sharing()), a sharing group’s Tucker edges are ONE edge: the group modes must carry the IDENTICAL spectrum (the group spectrum s_g, as the grouped t3svd reports at every group mode; a mismatch raises – unequal spectra are not a shared spectrum family), the group contributes one kappa_g = s_g[0]/s_g[-1] to the pool, one growth decision applies group-wide (kappa_guard guards kappa_g; max_grow counts the group as ONE candidate; the uniform-bump fallback bumps the group once), and useless-rank removal is the shared one (compute_minimal_ranks() with sharing – the group ceiling, so a shared rank is never clipped to a single mode’s local ceiling).

s_g is representation-independent – the singular values of the concatenated matricization [T_(i1)|...|T_(ik)], equivalently the Jacobian spectrum of a gauged tied motion of the shared factor (see SharedFrameData) – so kappa_g is exactly the conditioning of the tied Tucker subproblem, playing the same role the per-edge condition number plays for unshared edges in Section 5.4.1. It is never worse than the group’s worst per-mode condition number, and can be far better (under tying, a direction is well-determined if SOME mode of the group informs it); the sqrt(k) scale inflation of s_g cancels in every ratio, so group and singleton edges compete fairly in one pool. Cf. Molozhavenko & Rakhuba (2026, SF-ETT); the shared-factor format originates with SF-Tucker (Peshekhonov, Arzhantsev & Rakhuba, 2024).

Parameters:
  • shape (t3toolbox.backend.common.typ.Sequence[int])

  • tucker_singular_values (t3toolbox.backend.common.typ.Sequence[NDArray])

  • tt_singular_values (t3toolbox.backend.common.typ.Sequence[NDArray])

  • tau (float)

  • n_chunk (int)

  • kappa_guard (float)

  • max_grow (t3toolbox.backend.common.typ.Optional[int])

  • sharing (t3toolbox.backend.common.typ.Optional[t3toolbox.backend.common.typ.Sequence])

Return type:

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