t3_tie_tucker_factors ===================== .. py:function:: t3toolbox.backend.sharing.t3_tie_tucker_factors(x, sharing) .. code-block:: python def t3_tie_tucker_factors( x: typ.Tuple[ typ.Sequence[NDArray], # tucker_cores. len=d, elm_shape=stack_shape+(ni, Ni) typ.Sequence[NDArray], # tt_cores. len=d, elm_shape=stack_shape+(ri, ni, r(i+1)) ], sharing: typ.Sequence, # len=d, static; one hashable group label per mode ) -> typ.Tuple[ typ.Tuple[NDArray, ...], # new_tucker_cores. len=d; ONE shared array per group typ.Tuple[NDArray, ...], # tt_cores, untouched ]: Tie the Tucker factors exactly, by per-group arithmetic averaging. Each group's factor is replaced by the group mean, and the SAME array is assigned to every mode of the group -- the tie is exact by construction, never floating-point agreement. TT cores are untouched. The represented tensor changes unless the factors were already tied (drift repair for NEARLY-tied points, e.g. insurance after an operation that guarantees ties only to roundoff). 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 (the plain ``sum(B_i)/k`` would perturb the last ulp already at ``k = 3``). This is a repair of a POINT's representation, **not** the metric projection of a tangent onto the tied tangent space -- tangent tying is geometry-specific (the manifold geometry weights coordinates by the frame's ``S`` factors; the corewise geometry averages raw core perturbations) and lives with the shared geometry. .. rubric:: Examples The group factor becomes the mean, assigned as one array (identity, not just equality), and the result passes the tied-factors check exactly: >>> import numpy as np >>> import t3toolbox.tucker_tensor_train as t3 >>> import t3toolbox.backend.sharing as sharing >>> np.random.seed(0) >>> x = t3.TuckerTensorTrain.randn((6, 6, 5), (3, 3, 2), (1, 2, 2, 1)) >>> tk, tt = x.data >>> tk2, tt2 = sharing.t3_tie_tucker_factors(x.data, (0, 0, 1)) >>> print(tk2[0] is tk2[1], tt2 is tt) True True >>> print(bool(np.allclose(np.asarray(tk2[0]), (np.asarray(tk[0]) + np.asarray(tk[1])) / 2))) True >>> print(float(sharing.t3_sharing_residual((tk2, tt2), (0, 0, 1)))) 0.0 Already-tied input comes back with unchanged factor values: >>> tk3, _ = sharing.t3_tie_tucker_factors(((tk[0], tk[0], tk[2]), tt), (0, 0, 1)) >>> print(bool(np.array_equal(np.asarray(tk3[0]), np.asarray(tk[0])))) True