ut3_tie_tucker_factors#

t3toolbox.backend.sharing.ut3_tie_tucker_factors(data, sharing)#
def ut3_tie_tucker_factors(
        data:       typ.Tuple[
            NDArray,             # tucker_supercore, shape=(d,)+stack+(n,N)
            NDArray,             # tt_supercore,     shape=(d,)+stack+(r,n,r)
            typ.Sequence[int],   # shape, static int tuple
            typ.Tuple[NDArray, NDArray],  # (tucker_edge_mask, tt_edge_mask), HOST bool, static
        ],
        sharing:    typ.Sequence,   # len=d, static; one hashable group label per mode
) -> typ.Tuple[
    NDArray,                        # tucker_supercore with each group's slices set to the group mean
    NDArray,                        # tt_supercore, untouched
    typ.Sequence[int],              # shape, untouched
    typ.Tuple[NDArray, NDArray],    # masks, untouched (the tie changes values, never ranks)
]:

The uniform twin of t3_tie_tucker_factors(): tie the Tucker factors exactly, by per-group arithmetic averaging of the supercore slices.

Use this to repair numerical drift away from equal factors without round-tripping through the ragged layer – e.g. after many low-precision first-order steps, where an exactly-tied start can creep apart. TT cores, shape and masks are untouched: averaging changes factor values, never ranks, and a group’s Tucker rank masks are required equal anyway (structural, raises otherwise).

Garbage-transparent, so no masking is needed. A group’s rank masks are equal, so every real slot is real at every mode of the group and the mean of the real content uses only real values; the padding averages to other padding, which is don’t-care either way (docs/uniform_equivalence_contract.md).

As in the ragged twin the mean is computed as B_ref + mean(B_i - B_ref), so an exactly-tied group is a bitwise fixed point for any group size. Unlike the ragged twin there is no array identity to preserve – a supercore holds one slice per mode – so ties are exact by value, which is what the uniform checkers compare.

Examples

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.uniform_tucker_tensor_train as ut3
>>> import t3toolbox.backend.sharing as sharing
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((6, 6, 5), (3, 3, 2), (1, 2, 2, 1))
>>> u = ut3.UniformTuckerTensorTrain.from_t3(x)                      # untied
>>> print(bool(sharing.ut3_sharing_residual(u.data, (0, 0, 1)) > 0.1))
True
>>> tied = sharing.ut3_tie_tucker_factors(u.data, (0, 0, 1))
>>> print(float(sharing.ut3_sharing_residual(tied, (0, 0, 1))))
0.0

Masks and TT cores come back untouched, and re-tying is a bitwise fixed point:

>>> print(bool(np.array_equal(tied[1], u.data[1])), tied[2] == u.data[2])
True True
>>> again = sharing.ut3_tie_tucker_factors(tied, (0, 0, 1))
>>> print(bool(np.array_equal(np.asarray(again[0]), np.asarray(tied[0]))))
True
Parameters:
  • data (t3toolbox.backend.common.typ.Tuple[NDArray, NDArray, t3toolbox.backend.common.typ.Sequence[int], t3toolbox.backend.common.typ.Tuple[NDArray, NDArray]])

  • sharing (t3toolbox.backend.common.typ.Sequence)

Return type:

t3toolbox.backend.common.typ.Tuple[NDArray, NDArray, t3toolbox.backend.common.typ.Sequence[int], t3toolbox.backend.common.typ.Tuple[NDArray, NDArray]]