t3toolbox.backend.probing.probe_tangent#

t3toolbox.backend.probing.probe_tangent(ww: t3toolbox.backend.common.typ.Union[t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.NDArray], variation: t3toolbox.backend.common.typ.Union[t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray]], t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray]], base: t3toolbox.backend.common.typ.Union[t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray]], t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray]], edge_weights: t3toolbox.backend.common.typ.Union[t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray]], t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray, t3toolbox.backend.common.NDArray]] = (None, None, None, None, None), use_jax: bool = False) t3toolbox.backend.common.typ.Union[t3toolbox.backend.common.typ.Sequence[t3toolbox.backend.common.NDArray], t3toolbox.backend.common.NDArray]#

Probe a tangent vector.

See Section 5.2.3 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:
  • x (t3m.T3Tangent) – Tangent vector to probe. shape=(N1,…,Nd)

  • ww (typ.Sequence[NDArray]) – input vectors to probe with. len=d, elm_shape=(…,Ni)

  • xnp – Linear algebra backend. Default: np (numpy)

Returns:

Probes, zz. len=d, elm_shape=(Ni,) or (num_probes,Ni)

Return type:

typ.Tuple[NDArray,…]

Examples

Probe tangent with one set of vectors:

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.manifold as t3m
>>> import t3toolbox.backend.probing as t3p
>>> import t3toolbox.orthogonalization as orth
>>> p = t3.t3_corewise_randn((10,11,12),(5,6,4),(2,3,4,2))
>>> base, _ = orth.orthogonal_representations(p)
>>> variation = t3m.tangent_randn(base)
>>> ww = (np.random.randn(10), np.random.randn(11), np.random.randn(12))
>>> zz = t3p.probe_tangent(ww, variation, base)
>>> zz2 = t3p.probe_dense(ww, t3m.tangent_to_dense(variation, base))
>>> print([np.linalg.norm(z - z2) for z, z2 in zip(zz, zz2)])
[4.6257812371663175e-15, 3.628238740198284e-15, 5.6097341748343224e-15]

Probe tangent with two sets of vectors:

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.manifold as t3m
>>> import t3toolbox.backend.probing as t3p
>>> import t3toolbox.orthogonalization as orth
>>> p = t3.t3_corewise_randn((10,11,12),(5,6,4),(2,3,4,2))
>>> base, _ = orth.orthogonal_representations(p)
>>> variation = t3m.tangent_randn(base)
>>> www = (np.random.randn(2,10), np.random.randn(2,11), np.random.randn(2,12))
>>> zzz = t3p.probe_tangent(www, variation, base) # Compute probes!
>>> zzz2 = t3p.probe_dense(www,t3m.tangent_to_dense(variation, base))
>>> print([np.linalg.norm(zz - zz2) for zz, zz2 in zip(zzz, zzz2)])
[3.863711710898517e-15, 5.474255194514171e-15, 5.930347504865667e-15]

Example with weights

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.manifold as t3m
>>> import t3toolbox.backend.probing as t3p
>>> import t3toolbox.orthogonalization as orth
>>> randn = np.random.randn
>>> p = t3.t3_corewise_randn((10,11,12),(5,6,4),(2,3,5,4))
>>> base, _ = orth.orthogonal_representations(p)
>>> variation = t3m.tangent_randn(base)
>>> NN = [U.shape[1] for U in base[0]]
>>> nnU = [U.shape[0] for U in base[0]]
>>> rrL = [L.shape[0] for L in base[1]]
>>> rrR = [R.shape[2] for R in base[2]]
>>> nnO = [O.shape[1] for O in base[3]]
>>> shape_weights = [randn(N) for N in NN]
>>> up_tucker_weights = [randn(nU) for nU in nnU]
>>> outer_tucker_weights = [randn(nO) for nO in nnO]
>>> left_tt_weights = [randn(rL) for rL in rrL]
>>> right_tt_weights = [randn(rR) for rR in rrR]
>>> edge_weights = (shape_weights, up_tucker_weights, outer_tucker_weights, left_tt_weights, right_tt_weights)
>>> www = (np.random.randn(2,10), np.random.randn(2,11), np.random.randn(2,12))
>>> zzz = t3p.probe_tangent(www, variation, base, edge_weights=edge_weights)
>>> weighted_variation, weighted_base = t3m.absorb_weights_into_tangent_cores(variation, base, edge_weights)
>>> zzz2 = t3p.probe_tangent(www, weighted_variation, weighted_base)
>>> print([np.linalg.norm(zz - zz2) for zz, zz2 in zip(zzz, zzz2)])
[1.5683512051190777e-15, 4.368484248906507e-15, 1.855735793037041e-15]

Uniform tangent

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.uniform as ut3
>>> import t3toolbox.manifold as t3m
>>> import t3toolbox.backend.probing as t3p
>>> import t3toolbox.orthogonalization as orth
>>> p = t3.t3_corewise_randn((10,11,12),(5,6,4),(2,3,4,2))
>>> base, _ = orth.orthogonal_representations(p)
>>> variation = t3m.tangent_randn(base)
>>> www = (np.random.randn(2,10), np.random.randn(2,11), np.random.randn(2,12))
>>> uniform_variation, uniform_base, masks = ut3.bv_to_ubv(variation, base)
>>> inv_masks = cw.corewise_logical_not(masks)
>>> junk = ut3.uniform_randn(ut3.get_uniform_structure(uniform_x), masks=inv_masks)
>>> uniform_x = cw.corewise_add(uniform_x, junk) # Add random junk outside the masks
>>> uniform_www = ut3.pack_tensors(www)
>>> uniform_zzz = t3p.probe_tangent(uniform_www, uniform_variation, uniform_base, edge_weights=masks)
>>> zzz2 = t3p.probe_tangent(www, variation, base)
>>> uniform_zzz2 = ut3.pack_tensors(zzz2)
>>> print(np.linalg.norm(uniform_zzz - uniform_zzz2))
5.3316719684500096e-15