conspire/math/optimize/globalization/line_search/error/
mod.rs1use 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#[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}