t3_orthogonal_representations ============================= .. py:function:: t3toolbox.frame_variations_format.t3_orthogonal_representations(x, already_left_orthogonal = False, squash_tails = True) .. code-block:: python def t3_orthogonal_representations( x: t3.TuckerTensorTrain, already_left_orthogonal: bool = False, squash_tails: bool = True, ) -> typ.Tuple[ T3Frame, # orthogonal frame T3Variations, # variations ]: Construct frame-variation representations of TuckerTensorTrain with orthogonal frame. Input TuckerTensorTrain:: 1 -- G0 -- G1 -- G2 -- G3 -- 1 X = | | | | B0 B1 B2 B3 | | | | Frame-variation representation with non-orthogonal TT-core H1:: 1 -- L0 -- H1 -- R2 -- R3 -- 1 X = | | | | U0 U1 U2 U3 | | | | Frame-variation representation with non-orthogonal tucker core V2:: 1 -- L0 -- L1 -- D2 -- R3 -- 1 X = | | | | U0 U1 V2 U3 | | | | The input tensor train x is defined by: - x_tucker_cores = (B0, B1, B2, B3) - x_tt_cores = (G0, G1, G2, G3) The "frame cores" are: - tucker_cores = (U0,U1, U2, U3), up orthogonal - down_tt_cores = (O0, O1, O2, O3), down orthogonal - left_tt_cores = (L0, L1, L2), left orthogonal - right_tt_cores = (R1, R2, R3), right orthogonal The "variation cores" are: - tucker_variations = (V0, V1, V2, V3) - tt_variations = (H0, H1, H2, H3) Implements the sweeping orthogonalization (Algorithm 11), producing the representations (45)-(46), in Appendix A.3 of Alger et al. (2026), "Tucker Tensor Train Taylor Series" (arXiv:2603.21141). NOTE: the left/right orthogonalization sweep order here differs from Algorithm 11 (left-then-right vs the paper's right-then-left); the resulting orthogonal representations are equivalent. :param x: Input TuckerTensorTrain x = (x_tucker_cores, x_tt_cores) x_tucker_cores = (B0, ..., B(d-1)) x_tt_cores = (G0, ..., G(d-1)) :type x: TuckerTensorTrain :returns: * *T3Base* -- Orthogonal frame for frame-variation representations of x. * *T3Variation* -- Variation for frame-variation representaions of x. .. rubric:: Examples Orthogonalize a (stacked) T3. The frame reconstructs the *same* tensor x -- either by dropping the index-1 TT variation H1 into the chain, or the index-1 Tucker variation V1 (these are two of the single-core terms of :py:func:`fv_to_t3`): >>> import numpy as np >>> import t3toolbox.tucker_tensor_train as t3 >>> import t3toolbox.frame_variations_format as bvf >>> np.random.seed(0) >>> x = t3.TuckerTensorTrain.randn((14, 15, 16), (4, 5, 6), (3, 3, 2, 1), stack_shape=(2, 3)) >>> frame, variations = bvf.t3_orthogonal_representations(x) >>> x_tt = bvf.fv_to_t3((True, 1), frame, variations) # frame with TT-variation H1 in the chain >>> print(np.allclose(x.to_dense(), x_tt.to_dense())) # still represents the original tensor True >>> x_tk = bvf.fv_to_t3((False, 1), frame, variations) # frame with Tucker-variation V1 >>> print(np.allclose(x.to_dense(), x_tk.to_dense())) True The frame cores are orthogonal in their respective senses (the point of this routine). ``frame`` is ``(2, 3)``-stacked, so ``is_orthogonal()`` returns a per-element bool array; ``.all()`` summarizes it: >>> print(frame.is_orthogonal().shape, frame.is_orthogonal().all()) (2, 3) True >>> print(frame.shape, frame.stack_shape) # shape and stack are preserved (14, 15, 16) (2, 3)