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
use crate::{
traits::{ProgressStatus, Status, StatusMessage},
DMatrix, DVector, Float,
};
use serde::{Deserialize, Serialize};
/// A status message struct containing all information about a minimization result.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GradientFreeStatus {
/// A [`String`] message 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 [`GradientFreeStatus::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 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 GradientFreeStatus {
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.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
}
}
impl GradientFreeStatus {
/// Updates the [`GradientFreeStatus::x`] and [`GradientFreeStatus::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 [`GradientFreeStatus::x`] and [`GradientFreeStatus::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 [`GradientFreeStatus::x`] and [`GradientFreeStatus::fx`] fields without
/// touching the status message.
pub fn set_position_silent(&mut self, pos: (DVector<Float>, Float)) {
self.x = pos.0;
self.fx = pos.1;
}
/// Increments [`GradientFreeStatus::n_f_evals`] by `1`.
pub fn inc_n_f_evals(&mut self) {
self.n_f_evals += 1;
}
/// Updates the [`GradientFreeStatus::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 [`GradientFreeStatus::hess`] field and computes [`GradientFreeStatus::cov`] and [`GradientFreeStatus::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 GradientFreeStatus {
fn write_progress(&self, out: &mut String) -> std::fmt::Result {
use std::fmt::Write;
write!(out, "status={} fx={}", self.message, self.fx)
}
}