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
//! A minimal progress-logging observer.
use Display;
use crateObserve;
use crateState;
use crateTerminationReport;
/// Print a one-line progress report on every fire.
///
/// Each line carries the iteration counter, the current
/// [`cost`](State::cost), and the best cost so far
/// ([`best_cost`](State::best_cost)); the final line adds the
/// [`TerminationReport`]. Output goes to **stderr** (`eprintln!`) so it never
/// interleaves with data a caller might be writing to stdout.
///
/// Binds on the minimum shape [`State`] (with a [`Display`] scalar), so it
/// works with any solver. Pair it with an [`ObserverMode`](super::ObserverMode)
/// to control cadence: [`Every(n)`](super::ObserverMode::Every) for a heartbeat,
/// [`NewBest`](super::ObserverMode::NewBest) to log only on improvement.
///
/// # Example
///
/// ```
/// # use basin::{FirstOrderState, CostFunction, Executor, Gradient, GradientDescent};
/// use basin::{Report, ObserverMode};
/// # struct Quadratic;
/// # impl basin::ProblemConstraints for Quadratic {
/// type Constraints = basin::NoConstraints;
/// fn constraint_set(&self) -> basin::NoConstraints { basin::NoConstraints::EMPTY }
/// }
/// 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()) }
/// # }
/// let result = Executor::new(Quadratic, GradientDescent::new(0.1), FirstOrderState::new(vec![1.0, 1.0]))
/// .max_iter(10)
/// .observe_with(Report::with_prefix("gd"), ObserverMode::Every(2))
/// .run()
/// .unwrap();
/// ```