t3_tucker_weights_sharing_residual ================================== .. py:function:: t3toolbox.backend.sharing.t3_tucker_weights_sharing_residual(weights, sharing) .. code-block:: python def t3_tucker_weights_sharing_residual( weights: typ.Tuple[ typ.Sequence[NDArray], # tucker_weights. len=d, elm_shape=stack_shape+(ni,) typ.Sequence[NDArray], # tt_weights. len=d+1, elm_shape=stack_shape+(ri,) ], sharing: typ.Sequence, # len=d, static; one hashable group label per mode ) -> NDArray: # shape = stack_shape; max relative Tucker-weight deviation per stack element Non-enforcing check that edge weights are COMPATIBLE with a sharing partition, per stack element: the max over groups and group modes of ``||w_i - w_ref|| / ||w_ref||`` on the TUCKER weight vectors. TT-bond weights are unconstrained (they are absorbed into the TT cores and never touch the factors -- only equal group Tucker weights keep ``absorb_weights`` on a tied T3 tied). Weights carry no mode sizes, so the size check of :py:func:`validate_sharing` does not apply; unequal weight LENGTHS within a group (unequal Tucker ranks) raise (structural). ``T3Weights.from_t3svd(x, sharing=...)`` produces group-equal weights by construction (the group spectrum at every group mode), and ``concatenate``/``kronecker``/``reciprocal``/``sqrt`` all preserve group-equality. .. rubric:: Examples >>> 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, 3, 2, 1)) >>> tk, tt = x.data >>> xs = t3.TuckerTensorTrain((tk[0], tk[0], tk[2]), tt) # a tied point >>> W = t3.T3Weights.from_t3svd(xs, sharing=(0, 0, 1)) # grouped svals: group-equal >>> print(float(sharing.t3_tucker_weights_sharing_residual(W.data, (0, 0, 1)))) 0.0 >>> W2 = t3.T3Weights.from_t3svd(xs) # per-mode svals: NOT group-equal >>> print(bool(sharing.t3_tucker_weights_sharing_residual(W2.data, (0, 0, 1)) > 1e-3)) True