gradient_descent#

t3toolbox.backend.optimizers.gradient_descent(problem, x0, n_iter=100, gtol_rel=1e-08, c_armijo=0.0001, on_line_search_failure='stop')#
def gradient_descent(
        problem:  Problem,    # the fixed-rank least-squares problem
        x0:       Tangent,    # initial cores (U, G)
        n_iter:   int   = 100,
        gtol_rel: float = 1e-8,   # stop when ‖g‖ <= gtol_rel * ‖g_0‖
        c_armijo: float = 1e-4,   # Armijo sufficient-decrease constant
        on_line_search_failure: str = 'stop',  # Armijo exhausted (50 halvings): 'stop' = reject + terminate; 'accept' = take the last trial and continue
) -> typ.Tuple[Tangent, dict]:    # (x_cores, stats)

Steepest descent with a Cauchy initial step and an Armijo backtracking line search. The step length starts at the Cauchy value α = ‖g‖² / ‖𝒥g‖² (the 1D minimizer of the local GN quadratic along −g) and backtracks (α ← α/2) until f(retract(−α g)) ≤ f − c·α‖g‖² – so it descends on any geometry, including the additive corewise chart where a bare Cauchy step overshoots the high-degree objective. Exercises the whole backend-first stack (gradient / gn_quadratic / objective / retract). Eager only, deliberately – the reference implementation of the backend-first stack; use_jit lives on mc_sgd / adam / newton_cg.

on_line_search_failure: as in newton_cg() – exhausting all 50 halvings means the objective’s floor; 'stop' (default) rejects the step and terminates, 'accept' takes the last trial and keeps going (the deliberate escape mode). stats['line_search_failed'] reports whether an exhaustion occurred.

Parameters:
  • problem (Problem)

  • x0 (Tangent)

  • n_iter (int)

  • gtol_rel (float)

  • c_armijo (float)

  • on_line_search_failure (str)

Return type:

t3toolbox.backend.common.typ.Tuple[Tangent, dict]