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