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}