t3weights_to_ut3weights ======================= .. py:function:: t3toolbox.backend.ut3_conversions.t3weights_to_ut3weights(weights, n = None, r = None) .. code-block:: python def t3weights_to_ut3weights( 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,) ], n: int = None, # padded Tucker rank (default max(tucker rank)); pass to force a larger pad r: int = None, # padded TT rank (default max(tt rank)) ) -> typ.Tuple[ NDArray, # tucker_weight_supercore, shape=(d,) +stack_shape+(n,) NDArray, # tt_weight_supercore, shape=(d+1,)+stack_shape+(r,) typ.Tuple[NDArray, NDArray], # (tucker_edge_mask, tt_edge_mask), HOST bool, static ]: Pack a ragged ``T3Weights`` core pair into uniform weight supercores + masks (the ``.data`` layout). The weight twin of :py:func:`t3_to_ut3`, and much simpler: a weight is one vector per edge, so there is nothing to pad but the last axis and no physical ``shape`` at all (weights live only on internal edges). Each vector is zero-padded to the common width and the real extent recorded as a prefix mask. The **zero** pad matters and is not a free choice: masking downstream works by multiplication, so the fill must stay finite (``docs/uniform_equivalence_contract.md``), and zero is the layer's canonical clean padding. It is emphatically *not* an identity for weighting -- absorbing a zero-padded weight zeroes the padding of the object it weights, which is exactly right (that padding is don't-care), but it is why ``ut3_reciprocal_weights`` cannot naively divide (``1/0 = inf``). Pass ``n``/``r`` to match the padding of the object these weights will pair with; the defaults pad tightly to the weights' own max rank. ``use_jax`` is inferred for the SUPERCORES; the masks are always numpy (host) structure.