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
//! A `serde`-gated observer that snapshots the state to disk.
//!
//! Available only with the `serde` feature and off `wasm32` (it does file
//! I/O). The companion [`read_checkpoint`] reloads a state snapshot to warm
//! start a later run. Exact continuation instead uses the solver-aware
//! [`ExactCheckpointWriter`](crate::ExactCheckpointWriter).
use fs;
use io;
use ;
use Serialize;
use DeserializeOwned;
use crateObserve;
use crateState;
use crateTerminationReason;
/// Write the current state to a file with [`bincode`], overwriting the
/// previous snapshot, so the file always holds the latest checkpoint.
///
/// State-only checkpointing is an observer's job in Basin. It records an
/// iterate for a later warm start without promising an identical trajectory.
/// Register it with an [`ObserverMode`](super::ObserverMode) to pick the
/// cadence ([`Every(n)`](super::ObserverMode::Every) for every `n`th iteration,
/// [`NewBest`](super::ObserverMode::NewBest) to snapshot only on improvement).
/// The writer always snapshots on `observe_final` as well.
///
/// The state type must be [`Serialize`]; the shipped checkpointable states are
/// [`BasicState`](crate::core::state::BasicState),
/// [`QuasiNewtonState`](crate::core::state::QuasiNewtonState) (with `Vec<f64>`
/// or nalgebra backends—faer has no serde support), and
/// [`SimulatedAnnealingState`](crate::SimulatedAnnealingState) when its
/// parameter, neighbor, and RNG are serializable. Handing a non-serializable
/// state is a compile error.
///
/// # Resume
///
/// Read the file with [`read_checkpoint`], deserialize into the concrete state,
/// and hand it to [`Executor::new`](crate::Executor::new). The solver runs its
/// normal `init` path and begins a new run from the restored iterate.
///
/// ```no_run
/// # use basin::{BasicState, CostFunction, Executor, Gradient, GradientDescent};
/// use basin::{CheckpointWriter, ObserverMode, read_checkpoint};
/// # struct Quadratic;
/// # impl CostFunction for Quadratic {
/// # type Param = Vec<f64>;
/// # type Output = f64;
/// # type Error = std::convert::Infallible;
/// # fn cost(&self, x: &Vec<f64>) -> Result<f64, Self::Error> {
/// # Ok(0.5 * x.iter().map(|v| v * v).sum::<f64>())
/// # }
/// # }
/// # impl Gradient for Quadratic {
/// # type Gradient = Vec<f64>;
/// # fn gradient(&self, x: &Vec<f64>) -> Result<Vec<f64>, Self::Error> { Ok(x.clone()) }
/// # }
/// // First run: checkpoint every 10 iterations.
/// Executor::new(Quadratic, GradientDescent::new(0.1), BasicState::new(vec![5.0, 5.0]))
/// .max_iter(50)
/// .observe_with(CheckpointWriter::new("run.ckpt"), ObserverMode::Every(10))
/// .run()
/// .unwrap();
///
/// // Later: reload and continue from where it stopped.
/// let state: BasicState<Vec<f64>> = read_checkpoint("run.ckpt").unwrap();
/// Executor::new(Quadratic, GradientDescent::new(0.1), state)
/// .max_iter(50)
/// .run()
/// .unwrap();
/// ```
/// Load a checkpoint previously written by [`CheckpointWriter`] into a concrete
/// state, ready for [`Executor::new`](crate::Executor::new) as a warm start.