Illustrated summary
One iteration, step by step
Every iteration of QQN runs the same loop. Four of the steps are strategy slots — pluggable components with a fixed interface. Everything else is glue that never changes.
- Phase 1 · Orient
-
1
Evaluate
Compute f(x) and ∇f(x) at the current iterate.
-
2
slot · Gradient
Steepest-descent direction
g̃ = ‖q‖·(−∇f)/‖∇f‖ — the gradient direction, rescaled to the length of the oracle step. It sets the path’s tangent at t = 0 (the anchor that guarantees a descent direction always exists) while cancelling ‖∇f‖, so the path never stretches with the gradient’s magnitude.
-
3
slot · Oracle
Quasi-Newton endpoint
q = −H∇f from the oracle (L-BFGS two-loop recursion by default). It may be aggressive — it does not need to be a descent direction on its own.
-
4
Build the quadratic path
d(t) = t(1−t)·g̃ + t²·q. A single 1-D search space of states x + d(t), from “barely moved along −∇f” to “full oracle step”. Because the gradient leg carries the oracle’s length, t means the same thing from iteration to iteration.
- Phase 2 · Step
-
5
slot · Search
Walk the path
The line search probes t ∈ [0, 1] directly (Armijo backtracking by default, optionally refined by a cubic Hermite spline fit to every probe) and selects t*.
-
6
slot · Region
Project every probe
Each candidate is remapped, projectR(x, x + d(t)) — box clip, orthant, trust-region sphere… — so the search navigates the feasible path. Identity when unused.
-
7
Accept
x ← x + d(t*), only if sufficient decrease holds: f(x_new) ≤ f(x) + c₁⟨∇f, d(t*)⟩.
-
8
Learn
Oracle ingests the curvature pair (s, y) = (x_new − x, ∇f_new − ∇f) (admitted only if ⟨y, s⟩ > ε); region adapts its state (e.g. trust radius via ρ = ared / pred).
-
↺
Repeat until ‖∇f‖ ≤ tol or iter ≥ maxiter.
Interactive illustration
Drag the directions. Slide along the path.
Drag the orange handle to set the gradient direction −∇f and the blue handle to set the oracle direction −H∇f. The background is a toy quadratic landscape consistent with that gradient; the lower plot is what the line search actually sees: φ(t) = f(x + d(t)) − f(x). Note that only the direction of the orange handle moves the curve: the gradient leg is rescaled to the oracle step’s length (the faint dashed orange arrow g̃), so stretching −∇f leaves d(t) exactly where it is.
- t
- —
- t(1−t) · gradient weight
- —
- t² · oracle weight
- —
- ‖d(t)‖
- —
- φ(t) = f(x+d(t)) − f(x)
- —
- Armijo test at t
- —
- t* = argmin φ
- —
- φ(t*)
- —
Strategy selector
Four slots. Many providers.
Gradient, Oracle, Search and Region are conceptually orthogonal and independently swappable. Each is a pure interface; providers plug in without touching the solver loop. Pick a slot to see what it does and who can fill it — then build a configuration below and see which classical optimizer you just reproduced.
Build your optimizer
QQN as a configuration space
Classical methods are the points where one or two slots are fixed to a canonical choice.
What’s different
Five things QQN does that most optimizers don’t
None of these are exotic on their own. Together they turn “an L-BFGS variant” into an optimizer with a provable descent guarantee and a genuinely modular architecture.
Non-decreasing search
Every accepted step must satisfy f(x + d(t)) ≤ f(x) + c₁⟨∇f, d(t)⟩. The sequence of objective values is monotone — there are no “escape” steps, no learning-rate warm-ups, no hoping a bad step averages out later. If no acceptable state is found, the iteration fails loudly rather than moving uphill.
Valid tiny steps ⇒ convergence proven
Because d′(0) = g̃ = ‖q‖·(−∇f)/‖∇f‖ is a positive multiple of −∇f, we have ⟨∇f, d′(0)⟩ = −‖q‖·‖∇f‖ < 0: for any ∇f ≠ 0 there is a t > 0 that decreases f. The search always has a valid fallback on the same curve, so global convergence holds regardless of how bad the oracle direction is — the oracle only has to be useful, never safe.
Deterministic objective function
A line search compares f at different probes; those comparisons are only meaningful if f(x) is a function of x. QQN treats the objective as deterministic — full-batch, or a minibatch held fixed for the whole iteration — instead of a noisy estimate that must be averaged over many small steps.
2-phase optimization loop
Orientation and stepping are separated. First the path is constructed; then it is searched and the result is
fed back. The original MindsEye implementation lives in the opt/orient package for exactly this
reason — QQN was born as an orienting strategy.
Strategy-provider pattern
Gradient, Oracle, Search and Region are interfaces (init / direction or
project / update). Providers are pure functions; combinators such as
Fallback, Blend and Sequential compose them. State is threaded through
one immutable QQNState, so the whole thing stays jit/vmap/grad
friendly — and many classical optimizers fall out as particular slot choices.
Bonus: information-reusing search
Every probe along d(t) yields both a value and a directional derivative. The optional spline refinement fits a cubic Hermite spline through all probes and jumps to its stationary points — reusing gradient information a naive line search throws away.
History
From a Java hobby project to a paper and three ports
QQN has been quietly training neural networks for the better part of a decade.
-
< 2020
Original implementation — MindsEye (Java)
QQN first appeared as an orienting strategy in MindsEye, a Java deep-learning framework. It was used to train style-transfer and texture-synthesis models whose outputs are collected in the DeepArtist gallery — the “deterministic objective, non-decreasing search” philosophy dates from here.
-
2025
Formal paper and Rust implementation
The algorithm was written up formally — the quadratic path, its descent guarantee, and a benchmark suite — alongside a from-scratch Rust implementation,
qqn-optimizer, used to produce the paper’s results. -
2026
Python variants and MNIST benchmarking
Pure-functional ports for the major Python frameworks, generalising the design into the four strategy slots (oracles, regions, spline search) and benchmarking the whole configuration space on MNIST.
Read more
The academic paper
Quadratic-Quasi-Newton Optimization: Combining Gradient and Quasi-Newton Directions Through Quadratic Interpolation. Full derivation, convergence analysis and benchmarks.
QQN(
fun,
oracle="lbfgs", # t = 1 endpoint
line_search="armijo", # walks t ∈ [0, 1]
spline=False, # Hermite refinement
region=None, # feasibility projection
history_size=10, tol=1e-5, maxiter=100,
)