conspire/math/optimize/globalization/line_search/wolfe/
mod.rs1use super::{LineSearchError, ObjectiveMerit, exhausted, start};
2use crate::{
3 math::{Quantity, Scalar},
4 units::UnitMul,
5};
6use std::fmt::{self, Display, Formatter};
7
8#[derive(Clone, Debug)]
10pub struct Wolfe {
11 pub control_1: Scalar,
12 pub control_2: Scalar,
13 pub cut_back: Scalar,
14 pub max_steps: usize,
15 pub strong: bool,
16}
17
18impl Display for Wolfe {
19 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
20 write!(f, "Wolfe")
21 }
22}
23
24impl ObjectiveMerit for Wolfe {
25 fn search<W, U, V>(
26 &self,
27 mut value: impl FnMut(Quantity<W>) -> Result<Quantity<V>, String>,
28 mut slope: impl FnMut(Quantity<W>) -> Result<Quantity<U>, String>,
29 step_size: Quantity<W>,
30 ) -> Result<Quantity<W>, LineSearchError<W>>
31 where
32 W: UnitMul<U, Output = V>,
33 {
34 let (initial, gradient) = start(self, &mut value, &mut slope, step_size)?;
35 let t_1 = gradient * self.control_1;
36 let t_2 = gradient * self.control_2;
37 let mut n = step_size;
38 for _ in 0..self.max_steps {
39 if let Ok(trial) = value(n)
40 && let Ok(curvature) = slope(n)
41 && initial - trial >= n * t_1
42 && if self.strong {
43 curvature.abs() < t_2.abs()
44 } else {
45 curvature < t_2
46 }
47 {
48 return Ok(n);
49 } else {
50 n *= self.cut_back
51 }
52 }
53 Err(exhausted(self, self.max_steps))
54 }
55 fn search_merit(
56 &self,
57 _merit: impl FnMut(Scalar) -> Result<Scalar, String>,
58 _value: Scalar,
59 _slope: Scalar,
60 _step_size: Scalar,
61 ) -> Result<Scalar, LineSearchError> {
62 panic!(
63 "The Wolfe conditions need the gradient of the merit function, which the exact penalty function does not have."
64 )
65 }
66}