visual_odometry_rs/math/
optimizer.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5//! Guiding traits to implement iterative optimization algorithms.
6
7/// Enum used to indicate if iterations should continue or stop.
8/// Must be returned by the `stop_criterion` function.
9pub enum Continue {
10    /// Stop iterations.
11    Stop,
12    /// Continue iterations.
13    Forward,
14}
15
16/// An `State<Observations, EvalState, Model, Error>`
17/// is capable of iteratively minimizing an energy function,
18/// if provided few functions that are evaluated during iterations.
19///
20/// It merely is a skeleton for any iterative optimizer,
21/// that I have found to be flexible enough for all my past needs.
22/// Here is a simple description of its generic types.
23///
24/// * `Self`: State of the iterative optimizer.
25/// * `Observations`: Data used as reference during energy evaluations.
26/// * `EvalState`: Data computed while evaluating a model just computed.
27///   Will typically be result successfully containing all the data
28///   needed to update the optimizer state,
29///   or an error meaning that we stopped the evaluation because the energy increased.
30/// * `Model`: The model of what you are trying to optimize.
31/// * `Error`: Custom error type for potential failures in step computation.
32pub trait State<Observations, EvalState, Model, Error>
33where
34    Self: std::marker::Sized,
35{
36    /// Initialize the optimizer state.
37    fn init(obs: &Observations, model: Model) -> Self;
38
39    /// Compute an iteration step from the current optimizer state.
40    /// May fail, in such cases, iterations are stopped.
41    fn step(&self) -> Result<Model, Error>;
42
43    /// Evaluate the model.
44    /// You might want to short-circuit evaluation of a full new state depending on your usage
45    /// (e.g. if the energy increases).
46    /// This is why it returns an `EvalState` and not `Self`.
47    fn eval(&self, obs: &Observations, new_model: Model) -> EvalState;
48
49    /// Function deciding if iterations should continue.
50    /// Also return the state that will be used for next iteration.
51    fn stop_criterion(self, nb_iter: usize, eval_state: EvalState) -> (Self, Continue);
52
53    /// Iteratively solve your optimization problem,
54    /// with the provided functions by the trait implementation.
55    /// Return the final state and the number of iterations.
56    /// May return an error if a step computation failed.
57    fn iterative_solve(obs: &Observations, initial_model: Model) -> Result<(Self, usize), Error> {
58        let mut state = Self::init(obs, initial_model);
59        let mut nb_iter = 0;
60        loop {
61            nb_iter += 1;
62            let new_model = state.step()?;
63            let eval_state = state.eval(obs, new_model);
64            let (kept_state, continuation) = state.stop_criterion(nb_iter, eval_state);
65            state = kept_state;
66            if let Continue::Stop = continuation {
67                return Ok((state, nb_iter));
68            }
69        }
70    }
71}