UniformGaussNewtonModel#

class t3toolbox.fitting.UniformGaussNewtonModel#

The uniform-layer twin of GaussNewtonModel: the local Gauss-Newton model at frame, surfacing UT3Tangent gradients / Hessian actions so a frontend user can roll their own uniform optimizer (e.g. manifold L-BFGS) with the same ergonomics as the ragged model – UNIFORM_MANIFOLD.inner / .retract / .transport supply the rest. Built by the same factories (apply_model() &c.), which dispatch on x’s type; not directly.

Internally the sampling kind runs on the packed supercore pair (the speed path); the UT3Tangent boundary conversion (bare variation pair ⟷ gauged tangent) is the only frontend work.

Jit (compile-once). The packed kind is a per-problem closure over x’s rank masks, so – unlike the ragged model’s stateless singleton kind – it cannot go in the jax aux_data directly (a fresh closure each rebuild would recompile). Instead the aux is the value-hashed (kind_name, x0_masks, order, weight) and the kind is rebuilt lazily from it (the kind builders use only (shape, masks), not the supercores). So a model crossing a jit boundary keeps a stable, value-based aux and jit(lambda m, p: m.gn_hessian(p)) compiles once across rebuilt models of the same rank (frame / sweep / sample / residual flow as leaves). See docs/uniform_backend_jit_recipe.md.

Examples

>>> import numpy as np
>>> import t3toolbox.tucker_tensor_train as t3
>>> import t3toolbox.uniform_tucker_tensor_train as ut3
>>> import t3toolbox.uniform_manifold as ut3m
>>> import t3toolbox.fitting as fitting
>>> np.random.seed(0)
>>> x = ut3.UniformTuckerTensorTrain.from_t3(t3.TuckerTensorTrain.randn((6, 7, 8), (2, 3, 2), (1, 2, 2, 1)))
>>> ww = [np.random.randn(15, N) for N in (6, 7, 8)]
>>> r = np.random.randn(15)                            # residual r = apply(x) − y

The gradient is a gauged UT3Tangent and the Gauss-Newton quadratic form pᵀHp = ‖J p‖² agrees with the Hessian action:

>>> model = fitting.apply_model(ut3m.UNIFORM_MANIFOLD, x, ww, r)
>>> print(bool(model.gradient.is_gauged().all()))
True
>>> p = ut3m.UNIFORM_MANIFOLD.randn(model.frame)
>>> bool(np.allclose(float(model.gn_quadratic(p)), float(p.corewise_inner(model.gn_hessian(p)))))
True
geometry: t3toolbox.backend.common.typ.Any#
frame: UT3Frame#
kind_name: str#
x0_masks: UT3Masks#
order: t3toolbox.backend.common.typ.Optional[int]#
weight: t3toolbox.backend.common.typ.Optional[t3toolbox.backend.common.typ.Tuple[t3toolbox.backend.common.typ.Tuple[float, Ellipsis], Ellipsis]]#
sample: t3toolbox.backend.common.typ.Any#
residual: t3toolbox.backend.common.typ.Any#
sweep: t3toolbox.backend.common.typ.Any#
regularizer: t3toolbox.backend.common.typ.Any = None#

Methods#

kind()

objective_value()

The least-squares objective at the frame, c = ½‖r‖²; plus ρ(X) when a regularizer is set.

gradient()

The gradient g = geometry.project(𝒥ᵀ r) -- gauged on the manifold, raw on corewise -- plus the

jacobian(p)

The linearized forward J p = 𝒥(Π p) -- ONE forward sweep (the predicted residual r + J p).

gn_quadratic(p)

The Gauss-Newton quadratic form pᵀHp = ‖J p‖² -- ONE forward sweep (the Cauchy / line-search

gn_hessian(p)

The Gauss-Newton Hessian action H p = Π 𝒥ᵀ 𝒥 Π p (H = JᵀJ), a UT3Tangent at frame, plus

evaluate(p)

The quadratic-model value m(p) = c + gᵀp + ½ pᵀHp, reusing c / g and ONE forward apply.