tv_probe_transpose ================== .. py:function:: t3toolbox.backend.probing.tv_probe_transpose(ztildes, ww, frame, sum_over_probes = False) .. code-block:: python def tv_probe_transpose( ztildes: typ.Union[typ.Sequence[NDArray], NDArray], # len=d, elm_shape=(...,Ni) ww: typ.Union[typ.Sequence[NDArray], NDArray], # input vectors, len=d, elm_shape=(...,Ni) frame: typ.Union[ typ.Tuple[ typ.Sequence[NDArray], # up_tucker_cores. len=d. U_xo U_yo = I_xy, U.shape = (nU, N) typ.Sequence[NDArray], # down_tt_cores. len=d. O_ixj O_iyj = I_xy O.shape = (rL, nO, rR) typ.Sequence[NDArray], # left_tt_cores. len=d. P_iax P_iay = I_xy, P.shape = (rL, nU, rR) typ.Sequence[NDArray], # right_tt_cores. len=d. Q_xaj Q_yaj = I_xy Q.shape = (rL, nU, rR) ], typ.Tuple[ NDArray, # up_tucker_supercore. shape=(d, nU, N), up orthogonal elements NDArray, # down_tt_supercore. shape=(d, rL, nO, rR), down orthogonal elements NDArray, # left_tt_supercore. shape=(d, rL, nU, rR), left orthogonal elements NDArray, # right_tt_supercore. shape=(d, rL, nU, rR), right orthogonal elements ], ], # frame order = T3Frame.data = (up, down, left, right) = (U, O, P, Q) sum_over_probes: bool = False, ) -> typ.Union[ typ.Tuple[ typ.Tuple[NDArray,...], # dU_tildes. len=d, elm_shape=(...,nOi,Ni) typ.Tuple[NDArray,...], # dG_tildes. len=d, elm_shape=(...,rLi,nUi,rRi) ], typ.Tuple[ NDArray, # dU_tildes. shape=(d, ..., nOi, Ni) NDArray, # dG_tildes. shape=(d, ..., rLi, nUi, rRi) ], ]: Apply the transpose of the map from a tangent vector to its probes (apply (J^(s))^T to ztildes). Stacking (handled by the W/C custom contractions in ``contractions.py``): the residuals ``ztildes`` live in the forward probe space, ``elm_shape = W + C + (Ni,)`` (probe stack W outermost, T3 stack C innermost -- base-inner), while ``ww`` carries only the probe stack W. With ``sum_over_probes=False`` the resulting variations keep both stacks (``W + C + ...``, the probe stack W becoming the tangent stack K); with ``sum_over_probes=True`` the probe stack W is summed and the T3 stack C is kept (``C + ...``). See Section 6.2.3, particularly Algorithm 8, in: Alger, N., Christierson, B., Chen, P., & Ghattas, O. (2026). "Tucker Tensor Train Taylor Series." arXiv preprint arXiv:2603.21141. `https://arxiv.org/abs/2603.21141 `_ :param ztildes: Probe residuals to apply the transpose map to. len=d, elm_shape=(...,Ni) :type ztildes: typ.Sequence[NDArray] :param ww: input vectors that defined the (forward) probe map. len=d, elm_shape=(...,Ni) :type ww: typ.Sequence[NDArray] :param frame: Orthogonal frame for the point where the tangent space attaches to the manifold. This is exactly ``T3Frame.data`` order (U, O, P, Q) -- pass ``frame.data`` directly, no reorder. :type frame: (up_tucker_cores, down_tt_cores, left_tt_cores, right_tt_cores) :param sum_over_probes: Sum results over all probe residuals, rather than returning results for each probe residual. :type sum_over_probes: bool :returns: Tangent variations (a bvf.T3Variations.data tuple) resulting from applying the transpose map. :rtype: (dU_tildes, dG_tildes) .. seealso:: :py:obj:`t3_probe`, :py:obj:`tv_probe` .. rubric:: Examples Adjoint identity `` = `` with one set of probing vectors: >>> import numpy as np >>> import t3toolbox.corewise as cw >>> import t3toolbox.tucker_tensor_train as t3 >>> import t3toolbox.frame_variations_format as bvf >>> import t3toolbox.manifold as t3m >>> import t3toolbox.backend.probing as t3p >>> np.random.seed(0) >>> x = t3.TuckerTensorTrain.randn((10, 11, 12), (5, 6, 4), (1, 2, 3, 1)) >>> frame, _ = bvf.t3_orthogonal_representations(x) >>> probe_frame = frame.data # probing's frame order == T3Frame.data, no reorder >>> ww = (np.random.randn(10), np.random.randn(11), np.random.randn(12)) >>> v = t3m.MANIFOLD.randn(frame) >>> z = (np.random.randn(10), np.random.randn(11), np.random.randn(12)) >>> Jv = t3p.tv_probe(ww, v.variations.data, probe_frame) >>> JTz = t3p.tv_probe_transpose(z, ww, probe_frame) # (dU_tildes, dG_tildes) >>> lhs = cw.corewise_dot(z, Jv) # >>> rhs = cw.corewise_dot(JTz, v.variations.data) # >>> print(bool(np.allclose(lhs, rhs))) True With ``sum_over_probes=True`` (the Gauss-Newton ``J^T r``), the adjoint identity still holds when a probe stack ``W`` is summed on both sides: >>> import numpy as np >>> import t3toolbox.corewise as cw >>> import t3toolbox.tucker_tensor_train as t3 >>> import t3toolbox.frame_variations_format as bvf >>> import t3toolbox.manifold as t3m >>> import t3toolbox.backend.probing as t3p >>> np.random.seed(0) >>> x = t3.TuckerTensorTrain.randn((10, 11, 12), (5, 6, 4), (1, 2, 3, 1)) >>> frame, _ = bvf.t3_orthogonal_representations(x) >>> ww = (np.random.randn(2, 10), np.random.randn(2, 11), np.random.randn(2, 12)) # W=(2,) >>> v = t3m.MANIFOLD.randn(frame) >>> z = (np.random.randn(2, 10), np.random.randn(2, 11), np.random.randn(2, 12)) >>> Jv = t3p.tv_probe(ww, v.variations.data, frame.data) # W-stacked probes >>> JTz = t3p.tv_probe_transpose(z, ww, frame.data, sum_over_probes=True) >>> lhs = cw.corewise_dot(z, Jv) # sum_W >>> rhs = cw.corewise_dot(JTz, v.variations.data) # >>> print(bool(np.allclose(lhs, rhs))) True