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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//! The [`Solver`] trait every concrete solver implements. See the trait
//! contract for the lifecycle (`init` once, then repeated `next_iter`,
//! with an optional `terminate` hook) and the
//! [`executor`](crate::core::executor) module for the canonical iteration
//! ordering.
use crateProblem;
use crateState;
use crateTerminationReason;
/// A concrete optimization algorithm. Implementations carry the
/// solver's configuration and any internal scratch state; the iterate
/// itself lives in `S: State`.
///
/// # Contract
///
/// - **Caller must:** drive the solver through
/// [`Executor`](crate::core::executor::Executor) (or
/// [`run_loop`](crate::core::executor::run_loop) for composed
/// solvers). The executor calls [`init`](Self::init) exactly once
/// before any [`next_iter`](Self::next_iter) call, and runs
/// termination checks before each iteration including iter 0. See the
/// [`executor`](crate::core::executor) module docs for the canonical
/// loop ordering.
/// - **Implementor must:** populate every state field termination
/// criteria might read before returning from
/// [`init`](Self::init) — at minimum [`State::cost`] for any state
/// whose `cost()` panics on missing data, and
/// [`GradientState::gradient`](crate::core::state::GradientState::gradient)
/// for first-order solvers. After every successful
/// [`next_iter`](Self::next_iter), the same fields must again
/// correspond to the *current* [`State::param`].
/// - **Implementor must:** report mid-iteration failures
/// (line-search bailout, non-descent direction, etc.) via
/// [`next_iter`](Self::next_iter)'s `Option<TerminationReason>`
/// return rather than panicking; and use [`terminate`](Self::terminate)
/// only for clean convergence tests on the current state.
///
/// # Eval counting
///
/// Solvers do **not** maintain eval counters by hand. Every cost /
/// gradient / residual / Jacobian / Hessian call goes through the
/// [`Problem`] wrapper, which bumps
/// [`EvalCounts`](crate::core::problem::EvalCounts) on the wrapper
/// before delegating to the user's problem. The
/// [`Executor`](crate::core::executor::Executor) mirrors those counts
/// onto the state's [`State::cost_evals`] /
/// [`GradientState::gradient_evals`](crate::core::state::GradientState::gradient_evals)
/// after every successful [`init`](Self::init) /
/// [`next_iter`](Self::next_iter); see
/// [`CountsMirror`](crate::core::state::CountsMirror) for the per-state
/// mapping.
///
/// # Error type
///
/// The associated [`Error`](Self::Error) is the **hard-abort** error
/// type the solver propagates out of [`init`](Self::init) and
/// [`next_iter`](Self::next_iter). Concrete impls set
/// `type Error = P::Error;` (or `<P as Residual>::Error` for NLLS
/// solvers) so the user's typed problem error flows untouched out of
/// [`Executor::run`](crate::core::executor::Executor::run). Soft per-point
/// rejection still travels through `Ok(f64::INFINITY)` — see the
/// [`problem`](crate::core::problem) module docs.