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
//! # Trellis
//!
//! Trellis is a generic, event-driven numerical engine for iterative procedures.
//!
//! It provides a structured execution environment for algorithms that evolve a state over time,
//! producing progress signals, convergence diagnostics, and termination conditions.
//!
//! # Policies
//!
//! Policies control solver execution.
//!
//! During a run, the engine collects progress information from 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,
//! - or request some other engine action.
//!
//! Policies are the primary mechanism used to implement convergence criteria,
//! iteration limits, stagnation detection and timeout handling.
//!
//! ## Policies vs Observers
//!
//! Policies influence solver behaviour.
//!
//! Observers only observe solver behaviour.
//!
//! A policy may terminate a calculation. An observer may not.
//!
//! ```text
//! Progress ──► Policy ──► Engine Action
//! │
//! └────► Observer
//! ```
//!
//! ## Attaching Policies
//!
//! Policies are attached through the builder.
//!
//! ```rust
//! use trellis_runner::{CancellationGuard, MaxIterationPolicy, StagnationPolicy, GenerateBuilder};
//!
//! struct MyProcedure;
//! struct MyProblem;
//! struct MyState;
//!
//! impl trellis_runner::Procedure<MyProblem> for MyProcedure {
//! const NAME: &'static str = "My Procedure";
//! type State = MyState;
//! type Output = ();
//!
//! fn step(
//! &self,
//! _: &mut MyProblem,
//! _: &mut Self::State,
//! _guard: CancellationGuard<'_>,
//! ) {
//! ()
//! }
//!
//! fn finalise(&self, _: &mut MyProblem, _: &Self::State) {}
//! }
//!
//!
//! impl trellis_runner::UserState for MyState {
//! type Float = f64;
//!
//! fn progress(&self) -> trellis_runner::Progress<f64> {
//! trellis_runner::Progress::Complete
//! }
//! }
//!
//! let engine = MyProcedure
//! .build_for(MyProblem)
//! .with_initial_state(MyState)
//! .and_policy(MaxIterationPolicy::new(10_000))
//! .and_policy(StagnationPolicy::new(10))
//! .finalise();
//! ```
//!
//! Multiple policies may be attached.
//!
//! The engine stops as soon as any policy requests termination.
//!
//! ## Built-in Policies
//!
//! Trellis provides several commonly useful policies.
//!
//! | Policy | Purpose |
//! |---------|----------|
//! | `MaxIterationPolicy` | Stop the engine after a fixed number of iterations |
//! | `TimeoutPolicy` | Stops the engine after a maximum wall-clock duration |
//! | `AbsoluteTolerancePolicy` | Stops the engine when the mean absolute error over a rolling window falls below a user-defined tolerance|
//! | `RelativeTolerancePolicy` | Stops the engine when the mean relative error over a rolling window falls below a user-defined tolerance|
//! | `StagnationPolicy` | Stops the engine when the improvement of the best observed value over a rolling window falls below a relative tolerance threshold |
//! | `NoProgressPolicy` | Stops the engine when the best observed objective value fails to improve by a relative tolerance for a specified number of consecutive iterations |
//! | `TargetValuePolicy` | Stops the engine when the mean absolute distance to a target value remains below a specified tolerance over a rolling window |
//! | `CheckpointPolicy` | Define frequency of checkpoint generation |
pub use Infallible;
pub use ;
pub use ;
pub use JsonCheckpointStore;
pub use ;
pub use ;
pub use ;
pub use ;
pub use CsvProgressWriter;
pub use PlotObserver;