conspire/math/optimize/nonlinear/step_size/
mod.rs1#[cfg(test)]
2mod test;
3
4mod barzilai_borwein;
5
6pub use barzilai_borwein::{BarzilaiBorwein, Step as BarzilaiBorweinStep};
7
8use crate::math::{Erase, Scalar, Tensor};
9use std::fmt::{Debug, Display};
10
11pub trait StepEstimator: Clone + Debug + Display {
17 fn estimate(&self, ss: Scalar, sy: Scalar, yy: Scalar, iteration: usize) -> Scalar;
19}
20
21pub(crate) struct Secant<X, F> {
27 iteration: usize,
28 solution: X,
29 residual: Option<F>,
30}
31
32impl<X, F, E> Secant<X, F>
33where
34 X: Erase<Erased = E> + Tensor,
35 F: Erase<Erased = E> + Tensor,
36 E: Tensor,
37{
38 pub(crate) fn new(solution: &X) -> Self {
39 Self {
40 iteration: 0,
41 solution: solution.clone(),
42 residual: None,
43 }
44 }
45 pub(crate) fn solution(&self) -> &X {
46 &self.solution
47 }
48 pub(crate) fn step_size(
49 &mut self,
50 estimator: &impl StepEstimator,
51 solution: &X,
52 residual: &F,
53 step_size: Scalar,
54 ) -> Scalar {
55 self.solution -= solution;
56 let change = self.residual.get_or_insert_with(|| {
57 let mut zero = residual.clone();
58 zero *= 0.0;
59 zero
60 });
61 *change -= residual;
62 let trial = estimator.estimate(
63 self.solution
64 .erase()
65 .full_contraction(self.solution.erase()),
66 change.erase().full_contraction(self.solution.erase()),
67 change.erase().full_contraction(change.erase()),
68 self.iteration,
69 );
70 *change = residual.clone();
71 self.solution = solution.clone();
72 self.iteration += 1;
73 if trial.abs() > 0.0 && !trial.is_nan() {
74 trial.abs()
75 } else {
76 step_size
77 }
78 }
79}