T3Tangent.apply_transpose ========================= .. py:method:: t3toolbox.manifold.T3Tangent.apply_transpose(c, ww, frame, sum_over_probes = False) :staticmethod: .. code-block:: python 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 :py:meth:`apply`: back-project a residual ``c`` into a tangent. The adjoint of the (linear-in-the-variation) all-modes :py:meth:`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 :py:meth:`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. .. rubric:: Examples Adjoint identity `` == 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