compute_continuation_ranks ========================== .. py:function:: 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) .. code-block:: python 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) ) -> 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 (:py:func:`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. Proposed ranks are then de-degenerated by :py:func:`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 :py:func:`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.