T3Frame#

class t3toolbox.frame_variations_format.T3Frame#

Frame for frame-variations representation of TuckerTensorTrains

Often, one works with TuckerTensorTrains of the following forms:

1--(H0)--R1---R2---1    1---L0--(H1)--R2---1    1---L0---L1--(H2)--1
    |    |    |             |    |    |             |    |    |
    U0   U1   U2            U0   U1   U2            U0   U1   U2
    |    |    |             |    |    |             |    |    |

1---D0---R1---R2---1    1---L0---D1---R2---1    1---L0---L1---D2---1
    |    |    |             |    |    |             |    |    |
   (V0)  U1   U2            U0  (V1)  U2            U0   U1  (V2)
    |    |    |             |    |    |             |    |    |

In each of these, there is a special “variation” core, indicated by parentheses (X), surrounded by “frame” cores.

The components of T3Frame are the “frame cores”:
  • up_tucker_cores = (U0, …, U(d-1)), elm_shape=(nUi, Ni)

  • down_tt_cores = (D0, …, D(d-1)), elm_shape=(rLi, nDi, rR(i+1))

  • left_tt_cores = (L0, …, L(d-1)), elm_shape=(rLi, ni, rL(i+1))

  • right_tt_cores = (R0, …, R(d-1)), elm_shape=(rRi, ni, rR(i+1))

The components of T3Variations are the “variation cores”:
  • tucker_variations = (V0, …, V(d-1)), elm_shape=(nDi, Ni)

  • tt_variations = (H0, …, H(d-1)), elm_shape=(rLi, nUi, rRi)

Note that Ld and R0 are not used in these diagrams. (Why keep them, then? They hold the base point as one extra variation term so the frame remembers where it is attached, and they give every family a uniform length d for code reuse / off-by-one safety. See docs/frame_variations.md for the full rationale, and for how the gauged variations act as coordinates – which is what the weighted-layer metric T3FrameWeights reweights.)

The edge ranks are shown in the following diagrams:

   rL0       rL1       rR2      rR(d-1)         rRd
1 ------ L0 ----- (H1) ----- ... ------ R(d-1) ------ 1
         |         |                    |
         | nU0     | nU1                | nU(d-1)
         |         |                    |
         U0        U1                   Ud
         |         |                    |
         | N0      | N1                 | N(d-1)
         |         |                    |

and:

   rL0       rL1       rR2      rR(d-1)         rRd
1 ------ L0 ------ D1 ------ ... ------ R(d-1) ------ 1
         |         |                    |
         | nU0     | nO1                | nU(d-1)
         |         |                    |
         U0       (V1)                   Ud
         |         |                    |
         | N0      | N1                 | N(d-1)
         |         |                    |

A tangent vector can be written as the sum of all the tensor diagrams above. In this case, the frame cores are representations of the point where the tangent space attaches to the manifold, and the variation cores define the tangent vector with respect to the frame.

Often, it is desirable for the frame cores to be orthogonal as follows:
  • up_tucker_cores = (U0,…,U(d-1)), orthogonal: U_ia U_ja = delta_ij

  • down_tt_cores = (O0,…,O(d-1)), outer-orthogonal O_aib O_ajb = delta_ij

  • left_tt_cores = (L0,…,L(d-1)), left-orthogonal: L_abi L_abj = delta_ij

  • right_tt_cores = (R0,…,R(d-1)), right-orthogonal R_ibc R_jbc = delta_ij

Often, it is desirable for the variations to satisfy the following Gauge conditions:
  • U_ia V_ja = 0 (all V)

  • L_abi H_abj = 0 (all but the last H)

If these conditions are satisfied, then one can do “dumb” corewise linear algebra (add, scale, dot product, etc) with the variations, and those core faithfully correspond to linear algebra with the N1 x … x Nd tangent vectors represented by the variations.

The orthogonal representations (45)-(46) and gauge conditions (48)-(49) are defined in Appendix A.3 of Alger, Christierson, Chen & Ghattas (2026), “Tucker Tensor Train Taylor Series” (arXiv:2603.21141).

See also

T3Variations, check_t3_frame, t3_orthogonal_representations, oblique_gauge_projection

Examples

>>> import numpy as np
>>> import t3toolbox.frame_variations_format as bvf
>>> ss = (2, 3)                                       # frame/core stack C, shared by every core
>>> up_tucker_cores = (np.ones(ss+(10, 14)), np.ones(ss+(11, 15)), np.ones(ss+(12, 16)))
>>> down_tt_cores = (np.ones(ss+(1, 9, 4)), np.ones(ss+(2, 8, 5)), np.ones(ss+(3, 7, 1)))
>>> left_tt_cores = (np.ones(ss+(1, 10, 2)), np.ones(ss+(2, 11, 3)), np.ones(ss+(3, 12, 5)))
>>> right_tt_cores = (np.ones(ss+(2, 10, 4)), np.ones(ss+(4, 11, 5)), np.ones(ss+(5, 12, 1)))
>>> frame = bvf.T3Frame(up_tucker_cores, down_tt_cores, left_tt_cores, right_tt_cores)
>>> print(frame.structure)   # (shape, up_ranks, down_ranks, left_ranks, right_ranks, stack_shape)
((14, 15, 16), (10, 11, 12), (9, 8, 7), (1, 2, 3, 5), (2, 4, 5, 1), (2, 3))
>>> print(frame.variation_shapes)   # the (tucker, tt) holes a fitting T3Variations must fill
(((9, 14), (8, 15), (7, 16)), ((1, 10, 4), (2, 11, 5), (3, 12, 1)))
up_tucker_cores: t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]#
down_tt_cores: t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]#
left_tt_cores: t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]#
right_tt_cores: t3toolbox.backend.common.typ.Tuple[NDArray, Ellipsis]#

Methods#

d()

shape()

up_ranks()

down_ranks()

left_ranks()

right_ranks()

stack_shape()

The frame/core stack C -- a batch of base points, shared by every core.

structure()

variation_shapes()

T3Variations shapes that fit with this T3Frame.

data()

to_jax()

Copy with all frame cores converted to jax arrays.

to_numpy()

Copy with all frame cores converted to numpy arrays.

copy()

Deep copy (copies every frame core).

contains_jax()

True if any frame core is a jax array.

size()

Number of elements of the represented (base-point) dense tensor (prod(shape)).

data_size()

Number of stored core entries (size on disk).

__repr__()

orthogonality_residual()

Max absolute deviation of the orthogonal cores from identity, per stack element (shape

is_orthogonal([atol])

True (per stack element) if the frame cores are orthogonal in their respective senses.

minimal_ranks()

Structural minimal ranks (min_tucker_ranks, min_tt_ranks) for this frame's shape/ranks.

has_minimal_ranks()

True if the frame has minimal ranks.

has_numerically_minimal_ranks([atol])

True (per stack element) if the frame is numerically minimal -- certified without an SVD.

validate()

Check rank and shape consistency of Tucker tensor train frame (T3Frame).

__post_init__()

unstack()

Unstack into an array-like tree.

stack(xx)

Stack array-like tree of T3Frame into a single T3Frame.

from_t3(x)

Orthogonal representation (frame) of a TuckerTensorTrain x -- the orthogonal frame at the

random_orthogonal(shape, tucker_ranks, tt_ranks[, ...])

Orthogonal representation of a random T3 -- a genuine random base point (orthogonal,

random_orthogonal_like(frame)

A random orthogonal frame with the same shape/ranks/stack as frame.

save(file)

Save the frame cores to a .npz file (load with load()).

load(file[, use_jax])

Load a frame saved by save().

reverse()

Reverse the mode order. Left/right cores swap roles (reversing a left-orthogonal chain

to_t3()

The base point this frame represents, as a TuckerTensorTrain (natural ranks).

to_dense()

Dense tensor of the base point this frame represents (= to_t3().to_dense()).

orthogonalize()

Orthogonal, minimal-rank representation of the base point this frame reconstructs to.

is_consistent([rtol])

True (per stack element) if the left- and right-canonical reconstructions of the base point agree.

allclose(other[, rtol, atol])

True (per stack element) if other represents the same base point as self (gauge-invariant).