Elementwise multiplication: the three t3m methods#
If you multiply two Tucker tensor trains elementwise, the ranks multiply: the product of a
(n_x, r_x)-rank and a (n_y, r_y)-rank T3 has Tucker ranks n_x·n_y and TT bonds r_x·r_y.
Plain x * y gives you exactly that – the exact full product, stack-aware, no truncation.
x.t3m(y, ...) is the same product with optional rank truncation, computed by one of three
interchangeable algorithms that cover complementary cost regimes. All three return the same
tensor; they differ in how much memory and compute they spend getting there.
TL;DR#
|
algorithm |
sweet spot |
|---|---|---|
|
form the full product ( |
small bonds; the forming step is embarrassingly parallel; the reference/oracle |
|
fused left-to-right sweep; truncates as it goes, never materializes the full product |
large |
|
swap-based chain merge (the TTM generalization), |
|
With no truncation requested, every method short-circuits to the exact full product – so
t3m(method=...) with no tolerances is fast and exact regardless of method, and * is method
'form_then_round' with no truncation.
What there is to truncate#
Write a T3 as T[x] = Σ_n (∏_i U_i[n_i, x_i]) · C[n], with the central Tucker core C stored as
a tensor train. The elementwise product splits into two truncatable rank families:
Tucker factors:
W_i = U_i^x ⊙ U_i^y(row-wise Khatri-Rao), rankn_x·n_y→ truncate toñ_i;central core-TT bonds:
G̃_i = G_i^x ⊗ G_i^y(Kronecker), bondr_x·r_y→ truncate tor̃_i.
Both families blow up quadratically, which is why an untruncated product chain gets expensive fast
and why t3m exists.
Choosing a method#
The design analysis (constants depend on whether the Tucker rank n or the bond r dominates;
full derivations in
ttm_t3m_ht_note.tex):
method |
compute |
memory |
|---|---|---|
|
|
|
|
|
|
|
|
|
The crossover is d versus r: the fused and swap methods both avoid forming the full
product (so they beat 'form_then_round' on memory everywhere); between the two,
'inplace_fused' wins for d ≳ r and 'swap' wins for r ≫ d. 'form_then_round'’s virtue is
that its forming step has no sweep at all – fully parallel – and it doubles as the oracle the
other two are tested against.
The quality guarantee (joint truncation)#
All three methods truncate the Tucker ranks jointly – weighted by the central TT environment,
exactly as t3svd’s per-site SVDs do – rather than by an unweighted per-mode SVD. The practical
consequence: for the same tolerance, 'inplace_fused' and 'swap' never keep larger ranks than
'form_then_round' – the memory-efficient methods compress at least as well as the reference,
not worse. (This property is pinned by tests/test_t3m.py::test_swap_joint_quality.)
Oversampling (method='swap' only)#
The swap method has one T3-specific wrinkle: the merged Tucker leg of the last-merged mode is
still full-rank at the moment its bonds are fixed, so purely in-process truncation is only
quasi-optimal under aggressive truncation. oversample = k ≥ 1 resolves it with a uniform rule:
relax every active criterion by k in-process (rank caps to ⌈k·target⌉, tolerances to
tol/k) purely to bound memory, then run a single t3svd cleanup at the exact targets for
the decisive truncation.
k = 1(default): no cleanup – the lowest-memory, lowest-quality corner. Withrtolatk = 1the per-step tolerances accumulate to roughlyd·rtoloverall; useoversample > 1when you need tighter quality from tolerance-based truncation.A modest
k ≈ 2is a good default (near-'form_then_round'quality); the backend recordsk ≈ 3as recovering fullt3svdquality. Memory staysO((k·r̃)²), still far below theO(r²)full product whenr̃ ≪ r.A per-position
max_tt_rankssequence also triggers the cleanup: the swaps themselves can only cap bonds uniformly, and the cleanup is what honors the sequence exactly.
Why the tension is intrinsic (and why converting to a balanced hierarchical format would not
avoid it):
ttm_t3m_ht_note.tex.
Code pointers#
Frontend:
TuckerTensorTrain.t3m(other, method=..., max_tucker_ranks=..., max_tt_ranks=..., rtol=..., atol=..., oversample=...); plain*is the exact product.Backend:
backend/t3_linalg.py–t3_mult(the exact product) andt3m_form_then_round/t3m_inplace_fused/t3m_swap.Tests:
tests/test_t3m.py(dense-oracle harness, cross-method agreement, the joint-quality guard, oversample and stacking cases).