1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Framework: traits, state shapes, the iteration driver, and the
//! termination layer. The slot taxonomy is:
//!
//! - [`problem`] — what the *user* implements about their objective:
//! [`CostFunction`](problem::CostFunction),
//! [`Gradient`](problem::Gradient),
//! [`Residual`](problem::Residual) / [`Jacobian`](problem::Jacobian)
//! (least squares), and [`Hessian`](problem::Hessian) (second order).
//! Future: operators (matrix-free).
//! - [`numdiff`] — finite-difference derivative synthesis: the
//! [`FiniteDiff`](numdiff::FiniteDiff) wrapper adds
//! [`Gradient`](problem::Gradient) / [`Jacobian`](problem::Jacobian) /
//! [`Hessian`](problem::Hessian) to a problem that only exposes
//! function values.
//! - [`constraint`] — constraint markers carried on the problem (tenet 4
//! in `AGENTS.md`): [`BoxConstraints`](constraint::BoxConstraints) and
//! [`LinearInequalityConstraints`](constraint::LinearInequalityConstraints).
//! - [`barrier`] — the [`LogBarrier`](barrier::LogBarrier) adapter that
//! rewrites a linearly-constrained problem as the unconstrained
//! log-barrier objective consumed by the
//! [`BarrierMethod`](crate::solver::BarrierMethod).
//! - [`state`] — what a solver carries between iterations:
//! [`State`](state::State) for the minimum,
//! [`GradientState`](state::GradientState) /
//! [`SimplexState`](state::SimplexState) when a solver carries
//! richer info that termination criteria can read.
//! - [`solver`] — the [`Solver`](solver::Solver) trait every concrete
//! solver implements. Lifecycle is `init` once, then repeated
//! `next_iter`, with an optional `terminate` hook.
//! - [`termination`] — the framework-level
//! [`TerminationCriterion`](termination::TerminationCriterion)
//! trait plus shipped criteria. Each criterion bounds on the minimum
//! state shape it needs (tenet 3), so mismatches are compile errors
//! rather than runtime no-ops.
//! - [`executor`] — the driver: [`Executor`](executor::Executor) /
//! [`Stepper`](executor::Stepper) / [`run_loop`](executor::run_loop).
//! The canonical iteration ordering is documented on the
//! [`executor`] module.
//! - [`inner`] — the composition adapter:
//! [`InnerExecutor`](inner::InnerExecutor) wraps `run_loop` for outer
//! solvers that drive an inner solver per outer iteration. See
//! `AGENTS.md` "Solver composition" for the contracts.
//! - [`math`] — the small shared math layer
//! ([`ScaledAdd`](math::ScaledAdd), [`NormSquared`](math::NormSquared),
//! …) that backend-generic solvers depend on. Per tenet 5, this stays
//! honest: only ops every backend can implement well live here. LA-heavy
//! ops will live in a separate tier when the first solver wants them.