UT3Weights#

class t3toolbox.uniform_tucker_tensor_train.UT3Weights#

Diagonal weights on the internal edges of a UniformTuckerTensorTrain – the uniform twin of T3Weights.

One vector per internal edge, packed into two supercores + a UT3Masks holder:

  • tucker_weight_supercore: (d,) + stack_shape + (n,) – the Tucker-rank edges

  • tt_weight_supercore: (d+1,) + stack_shape + (r,) – the TT-bond edges

  • masks: the same two edge masks as the train it weights (a weight’s edges are the tensor’s edges, so it declares the same ranks). This is a genuine precondition, not bookkeeping – see is_consistent_with().

There is deliberately no ``shape`` field (unlike UniformTuckerTensorTrain): weights live only on the internal edges, so a weight has no physical mode legs at all.

Examples

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.uniform_tucker_tensor_train as ut3
>>> np.random.seed(0)
>>> x  = t3.TuckerTensorTrain.randn((6, 7, 8), (2, 2, 2), (1, 2, 2, 1))
>>> ux = ut3.UniformTuckerTensorTrain.from_t3(x, n=4, r=3)   # padded ABOVE the real ranks
>>> W  = ut3.UT3Weights.from_t3weights(t3.T3Weights.from_t3svd(x), n=ux.n, r=ux.r)
>>> print(W.is_consistent_with(ux))     # same edges -> same masks
True
>>> print(W.tucker_weight_supercore.shape, np.asarray(W.tucker_ranks).tolist())  # padded to 4, real 2
(3, 4) [2, 2, 2]
>>> xw = ut3.ut3_absorb_weights(ux, W)      # shape-preserving; masks unchanged
>>> print(xw.tucker_supercore.shape == ux.tucker_supercore.shape, xw.masks == ux.masks)
True True

The padding is a canonical zero, so reciprocal cannot naively divide (1/0 = inf would poison every masked reduction downstream: masking multiplies, and 0 * inf = nan). It guards the padding instead – which matters because the Grasedyck-Kramer metric is a reciprocal of singular values:

>>> with np.errstate(divide='ignore'):                             # the naive divide DOES blow up
...     naive = 1.0 / W.tucker_weight_supercore
>>> print(bool(np.isinf(naive).any()))
True
>>> Wr = W.reciprocal()                                            # ...the guarded one does not
>>> print(bool(np.isfinite(Wr.tucker_weight_supercore).all()))
True
>>> print(bool(np.isfinite(ut3.ut3_weighted_norm(ux, Wr))))            # so the GK norm stays finite
True
tucker_weight_supercore: NDArray#
tt_weight_supercore: NDArray#
masks: UT3Masks#
property supercores: Tuple[NDArray, NDArray]#

(tucker_weight_supercore, tt_weight_supercore).

Return type:

Tuple[NDArray, NDArray]

property data: Tuple[NDArray, NDArray, Tuple[NDArray, NDArray]]#

(tucker_weight_supercore, tt_weight_supercore, (2 rank masks)). Backend ut3_*_weights functions take this layout. Note it is a 3-tuple, one shorter than UniformTuckerTensorTrain.data – there is no shape slot.

Type:

Raw-array view, mirroring the fields

Return type:

Tuple[NDArray, NDArray, Tuple[NDArray, NDArray]]

property d: int#

Number of modes.

Return type:

int

property n: int#

Padded Tucker rank.

Return type:

int

property r: int#

Padded TT rank.

Return type:

int

property stack_shape: Tuple[int, Ellipsis]#

Stack shape (() if unstacked). Lives at axes 1 .. len(stack_shape) (d is axis 0).

Return type:

Tuple[int, Ellipsis]

property tucker_ranks: NDArray#

Real Tucker ranks (from tucker_edge_mask; may vary across the stack).

Return type:

NDArray

property tt_ranks: NDArray#

Real TT ranks (from tt_edge_mask; may vary across the stack).

Return type:

NDArray

Methods#

validate()

Check the structural invariants (supercore shapes agree with the masks; masks boolean).

__post_init__()

__repr__()

is_consistent_with(x)

True iff these weights can be absorbed into x (non-raising).

reciprocal()

Elementwise 1/w on the real slots (e.g. to form inverse-singular-value weights); the

sqrt()

Elementwise sqrt on the real slots; the padding stays a canonical, finite zero (masks

concatenate(other)

Per-edge concatenation with other -- the + / direct-sum combine (ranks add, padded

kronecker(other)

Per-edge Kronecker product with other -- the Hadamard (elementwise-product) combine (ranks

from_ut3svd(x, **kwargs)

The singular values of x as a weight object -- the canonical (unmodified) sigmas, so

from_t3weights(weights[, n, r])

Pack a ragged T3Weights into a uniform one.

to_t3weights()

Convert back to ragged form.