Skip to main content

conspire/math/optimize/globalization/line_search/error/
mod.rs

1use super::{LineSearchError, ObjectiveMerit, ResidualMerit, backtrack, exhausted};
2use crate::math::{Erase, Jacobian, Quantity, Scalar, Solution, Tensor};
3use std::{
4    fmt::{self, Display, Formatter},
5    ops::Mul,
6};
7
8/// Backtrack for errors.
9#[derive(Clone, Debug)]
10pub struct Error {
11    pub cut_back: Scalar,
12    pub max_steps: usize,
13}
14
15impl Display for Error {
16    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
17        write!(f, "Error")
18    }
19}
20
21impl Error {
22    fn reachable(
23        &self,
24        mut merit: impl FnMut(Scalar) -> Result<Scalar, String>,
25        step_size: Scalar,
26    ) -> Result<Scalar, LineSearchError> {
27        let mut n = step_size;
28        for _ in 0..self.max_steps {
29            if merit(n).is_ok() {
30                return Ok(n);
31            } else {
32                n *= self.cut_back
33            }
34        }
35        Err(exhausted(self, self.max_steps))
36    }
37}
38
39impl ObjectiveMerit for Error {
40    const MERIT: bool = false;
41    fn search<X, J, D, W, E>(
42        &self,
43        function: impl FnMut(&X, Scalar) -> Result<Scalar, String>,
44        _jacobian: impl FnMut(&X) -> Result<J, String>,
45        argument: &X,
46        jacobian0: &J,
47        decrement: &D,
48        step_size: Scalar,
49    ) -> Result<Scalar, LineSearchError>
50    where
51        J: Erase<Erased = E> + Jacobian,
52        D: Erase<Erased = E>,
53        E: Tensor,
54        X: Solution,
55        for<'a> &'a D: Mul<Quantity<W>, Output = X>,
56    {
57        backtrack(
58            self,
59            self.cut_back,
60            self.max_steps,
61            function,
62            argument,
63            jacobian0,
64            decrement,
65            step_size,
66            |_, _, _| true,
67        )
68    }
69    fn search_merit(
70        &self,
71        merit: impl FnMut(Scalar) -> Result<Scalar, String>,
72        _value: Scalar,
73        _slope: Scalar,
74        step_size: Scalar,
75    ) -> Result<Scalar, LineSearchError> {
76        self.reachable(merit, step_size)
77    }
78}
79
80impl ResidualMerit for Error {
81    const MERIT: bool = false;
82    fn search_residual(
83        &self,
84        merit: impl FnMut(Scalar) -> Result<Scalar, String>,
85        _value: Scalar,
86        _fraction: Scalar,
87    ) -> Result<Scalar, LineSearchError> {
88        self.reachable(merit, 1.0)
89    }
90}