T3Tangent.apply_transpose#

static t3toolbox.manifold.T3Tangent.apply_transpose(c, ww, frame, sum_over_probes=False)#
def apply_transpose(
        c:                  NDArray,                # residual, shape=W+C
        ww:                 typ.Sequence[NDArray],  # apply vectors, len=d, elm_shape=W+(Ni,)
        frame:              bvf.T3Frame,
        sum_over_probes:    bool = False,           # True: sum the apply stack W (Gauss-Newton apply^T c)
) -> 'T3Tangent':

Apply the transpose apply^T of apply(): back-project a residual c into a tangent.

The adjoint of the (linear-in-the-variation) all-modes apply(). With sum_over_probes=False (default) the apply-vector stack W becomes the result’s tangent stack (one tangent per apply-set); with sum_over_probes=True W is summed – the usual Gauss-Newton apply^T c back-projection (a single tangent when W = ()). Needs only the frame sweep + a single-term scatter assembly (cheaper than a general probe_transpose()).

False is the primary transpose; sum_over_probes=True == Σ_W sum_over_probes=False. See Batching & stacking §11 (docs/batching_and_stacking.md) for which mode to use and why.

Examples

Adjoint identity <apply^T c, v> == c * apply(v) (no stacks):

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.frame_variations_format as bvf
>>> import t3toolbox.manifold as t3m
>>> import t3toolbox.corewise as cw
>>> x = t3.TuckerTensorTrain.randn((10, 11, 12), (5, 6, 4), (1, 2, 3, 1))
>>> frame, _ = bvf.t3_orthogonal_representations(x)
>>> v = t3m.COREWISE.randn(frame)
>>> ww = (np.random.randn(10), np.random.randn(11), np.random.randn(12))
>>> ATc = t3m.T3Tangent.apply_transpose(np.asarray(1.7), ww, frame, sum_over_probes=True)
>>> lhs = float(cw.corewise_dot(ATc.variations.data, v.variations.data))
>>> print(bool(abs(lhs - 1.7 * float(v.apply(ww))) < 1e-9))
True
Parameters:
Return type:

T3Tangent