TuckerTensorTrain.continuation_ranks#
- t3toolbox.tucker_tensor_train.TuckerTensorTrain.continuation_ranks(tau=10.0, n_chunk=1, kappa_guard=1000000000000.0, max_grow=None, rtol=None, atol=None, sharing=None)#
def continuation_ranks( self: 'TuckerTensorTrain', tau: float = 10.0, # grow an edge 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) rtol: float = None, atol: float = None, sharing: typ.Sequence = None, # len=d; group labels (None = unshared) ) -> Tuple[ Tuple[int, ...], # (n0', ..., n(d-1)') new Tucker ranks Tuple[int, ...], # (r0', ..., rd') new TT ranks ]:
Rank-continuation update (Section 5.4.1): the ranks to grow to next, from this iterate’s spectra.
Computes the implicit T3-SVD of
selfand feeds the unfolding singular values tot3toolbox.backend.ranks.compute_continuation_ranks(), which grows the well-conditioned edges (each edge’s condition number a factortaubelow the worst) so the ranks trend toward comparable conditioning across edges. Pair withresize()for the zero-padded warm start of the next fit – this is the outer loop of Riemannian fitting with rank continuation:new_tucker, new_tt = X.continuation_ranks() X0 = X.resize(X.shape, new_tucker, new_tt) # warm start at the grown ranks (same tensor)
The current ranks are read from the SVD: with the default (no
rtol/atol) these are the structural ranks ofself– which, for a converged minimal-rank iterate, are its core ranks; passrtol/atolto continue from the numerical rank at that tolerance instead.kappa_guardis an absolute conditioning safety net (see the backend function): when no edge is below it, the returned ranks equalself’s current ranks – the caller’s signal to stop continuation. (The current ranks are also returned when the structure is already maximal; both mean “stop”.) Defined for a single (unstacked) T3 only.max_growcaps how many edges grow per call:None(default) grows every eligible edge at once;max_grow=1grows one edge at a time (the single best-conditioned edge that has structural room) – pair withtau=1.0for the most conservative, finest-grained continuation.With
sharing(Tucker factors tied within groups; the T3 must already be tied – safe mode checks), a group’s modes are ONE edge: the groupedt3svd()reports the group spectrums_gat every group mode (the singular values of the concatenated matricization[T_(i1)|...|T_(ik)]= the Jacobian spectrum of the shared factor, so its condition number is exactly the tied subproblem’s conditioning), the group contributes one condition number to the pool, one growth decision applies group-wide (a group counts as ONEmax_growcandidate), and useless-rank removal is the shared one (the group ceiling). Pair withresize(..., sharing=...)so the zero-padded warm start stays exactly tied (one array per group).See also
t3toolbox.backend.ranks.compute_continuation_ranks(),t3toolbox.backend.ranks.edge_condition_numbers(),TuckerTensorTrain.resize(),TuckerTensorTrain.t3svd()Examples
Mid-continuation: at a low-rank iterate, ask which ranks to grow to next, then warm-start there by zero-padding (
resize) – the represented tensor is unchanged, ready for the next fit:>>> import numpy as np >>> import t3toolbox.tucker_tensor_train as t3 >>> i, j, k = np.ogrid[1:7, 1:7, 1:7] >>> A = 1.0 / (i + 2 * j + 4 * k) # smooth, anisotropic per mode >>> X = t3.TuckerTensorTrain.t3svd_dense(A, max_tucker_ranks=2, max_tt_ranks=2)[0] >>> print(X.tucker_ranks, X.tt_ranks) # a rank-2 iterate (2, 2, 2) (1, 2, 2, 1) >>> new_tucker, new_tt = X.continuation_ranks() >>> print(new_tucker, new_tt) # the grown ranks for the next fit (3, 3, 3) (1, 3, 3, 1) >>> X0 = X.resize(X.shape, new_tucker, new_tt) # zero-padded warm start >>> print(X0.tucker_ranks, bool(np.allclose(X0.to_dense(), X.to_dense()))) (3, 3, 3) True
The edge condition numbers that drive the choice (length-1 boundary TT bonds are 1.0). Here all edges are comparably conditioned (~15–24), so none is a factor
tau=10below the worst and the fallback grows them uniformly:>>> import t3toolbox.backend.ranks as ranks >>> _, ss_tucker, ss_tt = X.t3svd() >>> kappa_tucker, kappa_tt = ranks.edge_condition_numbers(ss_tucker, ss_tt) >>> print([round(k, 2) for k in kappa_tucker]) [23.94, 15.91, 14.91]
A stricter
taugrows only edges well below the worst – here it holds back the stiffest Tucker mode and TT bond (condition number ~24) while growing the better-conditioned ones:>>> print(X.continuation_ranks(tau=1.5)) ((2, 3, 3), (1, 2, 3, 1))
max_grow=1grows only the single best-conditioned edge that has room (one edge at a time), instead of every eligible edge at once:>>> print(X.continuation_ranks(tau=1.5, max_grow=1)) ((2, 3, 2), (1, 2, 2, 1))
Shared factors: at a tied iterate, the group’s modes grow (or hold) TOGETHER, from the one group spectrum – and with
max_grow=1the whole group counts as the single grown edge:>>> np.random.seed(0) >>> Xs = t3.TuckerTensorTrain.t3svd_dense(A)[0].share((0, 0, 1), max_tucker_ranks=2, ... max_tt_ranks=2) >>> print(Xs.tucker_ranks, Xs.tt_ranks) (2, 2, 2) (1, 2, 2, 1) >>> print(Xs.continuation_ranks(sharing=(0, 0, 1))) ((3, 3, 3), (1, 3, 3, 1)) >>> print(Xs.continuation_ranks(tau=1.0, max_grow=1, sharing=(0, 0, 1))) ((3, 3, 2), (1, 2, 2, 1))
- Parameters:
tau (float)
n_chunk (int)
kappa_guard (float)
max_grow (Optional[int])
rtol (float)
atol (float)
sharing (Sequence)
- Return type:
Tuple[Tuple[int, …], Tuple[int, …]]