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
use crate::{
traits::{ProgressStatus, Status, StatusMessage},
DMatrix, DVector, Float,
};
use serde::{Deserialize, Serialize};
use std::ops::ControlFlow;
/// A status message struct containing all information about a minimization result.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GradientStatus {
/// A [`StatusMessage`] that can be set by [`Algorithm`](crate::traits::Algorithm)s.
pub message: StatusMessage,
/// The current parameters of the minimization.
pub x: DVector<Float>,
/// The current value of the minimization problem function at [`GradientStatus::x`].
pub fx: Float,
/// The number of function evaluations (approximately, this is left up to individual
/// [`Algorithm`](crate::traits::Algorithm)s to correctly compute and may not be exact).
pub n_f_evals: usize,
/// The number of gradient evaluations (approximately, this is left up to individual
/// [`Algorithm`](crate::traits::Algorithm)s to correctly compute and may not be exact).
pub n_g_evals: usize,
/// The number of Hessian evaluations (approximately, this is left up to individual
/// [`Algorithm`](crate::traits::Algorithm)s to correctly compute and may not be exact).
pub n_h_evals: usize,
/// The Hessian matrix at the end of the fit ([`None`] if not computed yet)
pub hess: Option<DMatrix<Float>>,
/// Covariance matrix at the end of the fit ([`None`] if not computed yet)
pub cov: Option<DMatrix<Float>>,
/// Errors on parameters at the end of the fit ([`None`] if not computed yet)
pub err: Option<DVector<Float>>,
}
impl Status for GradientStatus {
fn reset(&mut self) {
self.message = Default::default();
self.x = DVector::zeros(self.x.len());
self.fx = Default::default();
self.n_f_evals = Default::default();
self.n_g_evals = Default::default();
self.n_h_evals = Default::default();
self.hess = Default::default();
self.cov = Default::default();
self.err = Default::default();
}
fn message(&self) -> &StatusMessage {
&self.message
}
fn set_message(&mut self) -> &mut StatusMessage {
&mut self.message
}
fn check_invariants(&mut self) -> ControlFlow<()> {
if !self.fx.is_finite() {
self.set_message().fail_with_message("f(x) is not finite");
return ControlFlow::Break(());
}
ControlFlow::Continue(())
}
}
impl GradientStatus {
/// Updates the [`GradientStatus::x`] and [`GradientStatus::fx`] fields and sets the status
/// message to an initialized state.
pub fn initialize(&mut self, pos: (DVector<Float>, Float)) {
self.set_message()
.succeed_with_message(&format!("f(x) = {}", pos.1));
self.x = pos.0;
self.fx = pos.1;
}
/// Updates the [`GradientStatus::x`] and [`GradientStatus::fx`] fields and sets the status
/// message to a step state.
pub fn set_position(&mut self, pos: (DVector<Float>, Float)) {
self.set_message()
.step_with_message(&format!("f(x) = {}", pos.1));
self.x = pos.0;
self.fx = pos.1;
}
/// Updates the [`GradientStatus::x`] and [`GradientStatus::fx`] fields and marks the status as
/// initialized without formatting a message payload.
pub fn initialize_silent(&mut self, pos: (DVector<Float>, Float)) {
self.set_message().initialize();
self.x = pos.0;
self.fx = pos.1;
}
/// Updates the [`GradientStatus::x`] and [`GradientStatus::fx`] fields and marks the status as
/// a step without formatting a message payload.
pub fn set_position_silent(&mut self, pos: (DVector<Float>, Float)) {
self.set_message().step();
self.x = pos.0;
self.fx = pos.1;
}
/// Increments [`GradientStatus::n_f_evals`] by `1`.
pub fn inc_n_f_evals(&mut self) {
self.n_f_evals += 1;
}
/// Increments [`GradientStatus::n_g_evals`] by `1`.
pub fn inc_n_g_evals(&mut self) {
self.n_g_evals += 1;
}
/// Increments [`GradientStatus::n_h_evals`] by `1`.
pub fn inc_n_h_evals(&mut self) {
self.n_h_evals += 1;
}
/// Updates the [`GradientStatus::err`] field.
pub fn set_cov(&mut self, covariance: Option<DMatrix<Float>>) {
if let Some(cov_mat) = &covariance {
self.err = Some(cov_mat.diagonal().map(Float::sqrt));
}
self.cov = covariance;
}
/// Updates the [`GradientStatus::hess`] field and computes [`GradientStatus::cov`] and [`GradientStatus::err`].
pub fn set_hess(&mut self, hessian: &DMatrix<Float>) {
use crate::core::utils::hessian_to_covariance;
self.hess = Some(hessian.clone());
let covariance = hessian_to_covariance(hessian);
if let Some(cov_mat) = &covariance {
self.err = Some(cov_mat.diagonal().map(Float::sqrt));
}
self.cov = covariance;
}
}
impl ProgressStatus for GradientStatus {
fn write_progress(&self, out: &mut String) -> std::fmt::Result {
use std::fmt::Write;
write!(out, "status={} fx={}", self.message, self.fx)
}
}