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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
//! # Trellis
//!
//! Trellis is a generic execution engine for iterative numerical algorithms.
//!
//! Rather than implementing optimisation loops, integration loops or search loops
//! directly, a procedure describes a single iteration of an algorithm while
//! Trellis manages execution, convergence, termination, observation and
//! checkpointing.
//!
//! The library separates the concerns of:
//!
//! - **algorithm implementation** (`Procedure`)
//! - **problem definition** (the problem supplied to the procedure)
//! - **algorithm state** (`UserState`)
//! - **execution control** (policies)
//! - **instrumentation** (observers)
//!
//! This separation allows algorithms to focus solely on their numerical method,
//! while Trellis provides a reusable execution framework.
//!
//! ## Execution model
//!
//! Every Trellis calculation follows the same execution model:
//!
//! ```text
//! Problem
//! │
//! ▼
//! ┌───────────┐
//! │ Procedure │
//! └─────┬─────┘
//! │
//! updates state
//! │
//! ▼
//! ┌───────────┐
//! │ UserState │
//! └─────┬─────┘
//! │
//! emits Progress events
//! │
//! ┌──────────┴──────────┐
//! ▼ ▼
//! Engine Policies Observers
//! │
//! ▼
//! Engine Actions
//! ```
//!
//! The principal abstractions are:
//!
//! - **Problem** — the specific problem instance being solved.
//! - **Procedure** — performs a single iteration of the algorithm.
//! - **UserState** — stores the evolving state of the computation and reports
//! progress.
//! - **Policies** — inspect progress and control execution.
//! - **Observers** — inspect progress without affecting execution.
//!
//! ## A simple example
//!
//! A calculation is configured using the builder returned by
//! [`GenerateBuilder::build_for`]:
//!
//! ```
//! use trellis_runner::{
//! GenerateBuilder, MaxIterationPolicy, RelativeTolerancePolicy,
//! CancellationGuard, Procedure, Progress, UserState,
//! };
//!
//! struct Problem;
//!
//! #[derive(Default)]
//! struct State {
//! value: f64,
//! }
//!
//! impl UserState for State {
//! type Float = f64;
//!
//! fn progress(&self) -> Progress<Self::Float> {
//! Progress::Measure(self.value)
//! }
//! }
//!
//! struct Solver;
//!
//! impl Procedure<Problem> for Solver {
//! const NAME: &'static str = "Example";
//!
//! type State = State;
//! type Output = ();
//!
//! fn step(
//! &self,
//! _: &mut Problem,
//! _: &mut State,
//! _: CancellationGuard<'_>,
//! ) {}
//!
//! fn finalise(
//! &self,
//! _: &mut Problem,
//! _: &State,
//! ) {}
//! }
//! let engine = Solver
//! .build_for(Problem)
//! .with_initial_state(State::default())
//! .and_policy(RelativeTolerancePolicy::new(1e-8, 10))
//! .and_policy(MaxIterationPolicy::new(10_000))
//! .finalise();
//!
//! let result = engine.run();
//! ```
//!
//! The builder configures the execution environment rather than the numerical
//! algorithm itself.
//!
//! ## Procedures
//!
//! A [`Procedure`] implements the numerical algorithm.
//!
//! Each call to `step()` performs a single iteration of the algorithm, while
//! `finalise()` converts the final algorithm state into the value returned to the
//! caller.
//!
//! Both infallible and fallible procedures are supported.
//!
//! ## User state
//!
//! [`UserState`] stores the evolving state of the computation.
//!
//! In addition to algorithm-specific data, it reports progress to the engine via
//! [`Progress`], allowing policies and observers to monitor execution.
//!
//! States implementing [`Snapshotable`] can additionally participate in
//! checkpointing, allowing long-running computations to be resumed.
//!
//! ## Policies
//!
//! Policies control solver execution.
//!
//! During a run, the engine collects progress emitted by the procedure and
//! passes it to one or more policies. Policies inspect this information and
//! decide whether the solver should:
//!
//! - continue running,
//! - terminate successfully,
//! - terminate early,
//! - request a checkpoint,
//! - or perform another engine action.
//!
//! Policies influence execution.
//!
//! Observers do not.
//!
//! ```text
//! Progress ──► Policy ──► Engine Action
//! │
//! └────► Observer
//! ```
//!
//! Multiple policies may be attached simultaneously.
//!
//! The engine stops as soon as any policy requests termination.
//!
//! Custom policies can be created implementing the [`EnginePolicy`] trait.
//!
//! ### Built-in policies
//!
//! | Policy | Description |
//! |---------|-------------|
//! | `MaxIterationPolicy` | Stops after a fixed number of iterations. |
//! | `TimeoutPolicy` | Stops after a maximum wall-clock duration. |
//! | `AbsoluteTolerancePolicy` | Stops when the mean absolute error over a rolling window falls below a tolerance. |
//! | `RelativeTolerancePolicy` | Stops when the mean relative error over a rolling window falls below a tolerance. |
//! | `TargetValuePolicy` | Stops when the mean distance to a target value remains below a tolerance. |
//! | `NoProgressPolicy` | Stops when no meaningful improvement has been observed for a specified number of iterations. |
//! | `StagnationPolicy` | Stops when improvement over a rolling window falls below a relative threshold. |
//! | `CheckpointPolicy` | Requests periodic checkpoint generation. |
//!
//! ## Observers
//!
//! Observers receive every event emitted by the engine but never influence
//! execution.
//!
//! Typical applications include:
//!
//! - structured logging,
//! - tracing,
//! - CSV export,
//! - plotting,
//! - metrics collection,
//! - progress reporting,
//! - custom visualisation.
//!
//! ## Checkpointing
//!
//! User states implementing [`Snapshotable`] may be checkpointed during
//! execution.
//!
//! Checkpoints may be requested by policies or generated manually, allowing
//! interrupted computations to be resumed.
//!
//! ## Extending Trellis
//!
//! Trellis is designed to be extended through traits.
//!
//! Most applications only need to implement:
//!
//! - [`Procedure`] to define the numerical algorithm,
//! - [`UserState`] to store algorithm state,
//! - [`EnginePolicy`] for custom stopping criteria,
//! - [`Observe`] for custom instrumentation.
//!
//! These components compose naturally, allowing new algorithms, policies and
//! observers to be combined without modifying the execution engine itself.
pub use Infallible;
pub use ;
pub use CancellationToken;
pub use ;
pub use JsonCheckpointStore;
pub use ;
pub use ;
pub use ;
pub use ;
pub use CsvProgressWriter;
pub use PlotObserver;