TuckerTensorTrain.rank_adjustment_sweep#

t3toolbox.tucker_tensor_train.TuckerTensorTrain.rank_adjustment_sweep(direction='right_to_left')#
def rank_adjustment_sweep(self, direction: str = 'right_to_left') -> 'TuckerTensorTrain':

A single lossless directional sweep that drops structurally-redundant ranks (the separate rank-minimization step; t3svd() itself does not minimize). Returns the adjusted T3.

'right_to_left' returns a right-orthogonal T3; 'left_to_right' a left-orthogonal one. A single sweep reaches minimal ranks only if the input is already orthogonal in the opposite direction – e.g. a t3svd() result is left-orthogonal, so result.rank_adjustment_sweep('right_to_left') minimizes it (check with has_minimal_ranks). That precondition is not enforced: sweeping the wrong direction for the input’s gauge just under-minimizes (it stays lossless here – but the uniform rank_adjustment_sweep() is lossy in that case). Verify the gauge with is_left_orthogonal() / is_right_orthogonal() first, or compose both directions for guaranteed minimal ranks. The represented tensor is unchanged (when used correctly).

Examples

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> np.random.seed(0)
>>> x = t3.TuckerTensorTrain.randn((5, 6, 7), (4, 5, 6), (1, 3, 2, 1))
>>> x2, _, _ = x.t3svd(max_tt_ranks=2)        # basic T3-SVD: left-orthogonal, NOT minimal
>>> print(x2.has_minimal_ranks, x2.tucker_ranks)
False (3, 4, 2)
>>> x3 = x2.rank_adjustment_sweep('right_to_left')   # x2 is left-orthogonal -> R->L minimizes
>>> print(x3.has_minimal_ranks, x3.tucker_ranks)
True (2, 4, 2)
>>> print(np.allclose(x3.to_dense(), x2.to_dense()))  # same tensor, redundant rank removed
True

Wrong direction for the input’s gauge – the left-orthogonal x2 needs 'right_to_left'; 'left_to_right' here just under-minimizes (lossless, but still non-minimal). Use a bond orphan to show it clearly:

>>> np.random.seed(0)
>>> y = t3.TuckerTensorTrain.randn((10, 10, 10), (9, 9, 9), (1, 9, 9, 1))
>>> y2, _, _ = y.t3svd(max_tucker_ranks=[9, 1, 9], max_tt_ranks=[1, 9, 2, 1])  # left-orth, non-minimal
>>> print(y2.has_minimal_ranks)
False
>>> wrong = y2.rank_adjustment_sweep('left_to_right')    # WRONG direction for a left-orth input
>>> print(wrong.has_minimal_ranks, np.allclose(wrong.to_dense(), y2.to_dense()))  # non-minimal, but lossless
False True
>>> print(y2.rank_adjustment_sweep('right_to_left').has_minimal_ranks)   # correct direction
True
Parameters:

direction (str)

Return type:

TuckerTensorTrain