tv_probe_transpose#
- t3toolbox.backend.probing.tv_probe_transpose(ztildes, ww, frame, sum_over_probes=False)#
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 residualsztildeslive in the forward probe space,elm_shape = W + C + (Ni,)(probe stack W outermost, T3 stack C innermost – base-inner), whilewwcarries only the probe stack W. Withsum_over_probes=Falsethe resulting variations keep both stacks (W + C + ..., the probe stack W becoming the tangent stack K); withsum_over_probes=Truethe 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
- Parameters:
ztildes (typ.Sequence[NDArray]) – Probe residuals to apply the transpose map to. len=d, elm_shape=(…,Ni)
ww (typ.Sequence[NDArray]) – input vectors that defined the (forward) probe map. len=d, elm_shape=(…,Ni)
frame ((up_tucker_cores, down_tt_cores, left_tt_cores, right_tt_cores)) – Orthogonal frame for the point where the tangent space attaches to the manifold. This is exactly
T3Frame.dataorder (U, O, P, Q) – passframe.datadirectly, no reorder.sum_over_probes (bool) – Sum results over all probe residuals, rather than returning results for each probe residual.
- Returns:
Tangent variations (a bvf.T3Variations.data tuple) resulting from applying the transpose map.
- Return type:
(dU_tildes, dG_tildes)
Examples
Adjoint identity
<z, J v> = <J^T z, v>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) # <z, J v> >>> rhs = cw.corewise_dot(JTz, v.variations.data) # <J^T z, v> >>> print(bool(np.allclose(lhs, rhs))) True
With
sum_over_probes=True(the Gauss-NewtonJ^T r), the adjoint identity still holds when a probe stackWis 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 <z_W, (J v)_W> >>> rhs = cw.corewise_dot(JTz, v.variations.data) # <sum_W J^T z_W, v> >>> print(bool(np.allclose(lhs, rhs))) True