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
// Copyright 2018-2024 argmin developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! # Line search conditions
//!
//! For a step length to be accepted in a line search, it needs to satisfy one of several
//! conditions.
//!
//! A condition exposes an interface defined by the trait
//! [`LineSearchCondition`](`condition::LineSearchCondition`).
//!
//! # Available line search conditions
//!
//! * [`ArmijoCondition`](`condition::ArmijoCondition`)
//! * [`WolfeCondition`](`condition::WolfeCondition`)
//! * [`StrongWolfeCondition`](`condition::StrongWolfeCondition`)
//! * [`GoldsteinCondition`](`condition::GoldsteinCondition`)
//!
//! ## Reference
//!
//! Jorge Nocedal and Stephen J. Wright (2006). Numerical Optimization.
//! Springer. ISBN 0-387-30303-0.

mod armijo;
mod goldstein;
mod strongwolfe;
mod wolfe;

pub use armijo::ArmijoCondition;
pub use goldstein::GoldsteinCondition;
pub use strongwolfe::StrongWolfeCondition;
pub use wolfe::WolfeCondition;

/// Interface which a condition needs to implement.
///
/// # Example
///
/// ```
/// use argmin::solver::linesearch::condition::LineSearchCondition;
///
/// pub struct MyCondition {}
///
/// impl<T, G, F> LineSearchCondition<T, G, F> for MyCondition {
///     fn evaluate_condition(
///         &self,
///         current_cost: F,
///         current_gradient: Option<&G>,
///         initial_cost: F,
///         initial_gradient: &G,
///         search_direction: &T,
///         step_length: F,
///     ) -> bool {
///         // Use the current cost function value, the current gradient, the initial cost function
///         // value, the initial gradient, the search direction and the current step length to
///         // compute whether your condition is met (return `true`) or not (return `false`).
/// #       true
///     }
///
///     fn requires_current_gradient(&self) -> bool {
///         // Indicate to the calling method whether your condition requires the current gradient
///         // (at the position defined by the current step length).
///         true
///     }
/// }
/// ```
pub trait LineSearchCondition<T, G, F> {
    /// Evaluate the condition
    ///
    /// This method has access to the initial cost function value and the initial gradient (at the
    /// initial point from where to search from), the current cost function value at the initial
    /// point plus a step in search direction of length `step_length` as well as (optionally) the
    /// gradient at that point. It further has access to the search direction and the step length.
    ///
    /// It returns `true` if the condition was met and `false` if not.
    fn evaluate_condition(
        &self,
        current_cost: F,
        current_gradient: Option<&G>,
        initial_cost: F,
        initial_gradient: &G,
        search_direction: &T,
        step_length: F,
    ) -> bool;

    /// Indicates whether this condition requires the computation of the gradient at the new point
    ///
    /// This should return `false` if the evaluation of the condition does not require the gradient
    /// at the current point and `true` otherwise.
    fn requires_current_gradient(&self) -> bool;
}