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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
//! # ceres-solver-rs
//! ## Safe Rust bindings for [Ceres Solver](http://ceres-solver.org)
//!
//! Solve large and small non-linear optimization problems in Rust.
//! See [nlls_problem::NllsProblem] for general non-linear least squares problem and
//! [curve_fit::CurveFitProblem1D] for a multiparametric 1-D curve fitting.
//!
//! # Examples
//!
//! Let's solve min[(x - 2)^2] problem
//!
//! ```rust
//! use ceres_solver::{CostFunction, CostFunctionType, NllsProblem, ResidualBlock};
//!
//! // parameters vector consists of vector parameters, here we have a single 1-D parameter.
//! let true_parameters = vec![vec![2.0]];
//! let initial_parameters = vec![vec![0.0]];
//! // This must be equal to initial_parameters.iter().map(|v| v.len()).collect();
//! let parameter_sizes = [1];
//!
//! // You can skip type annotations in the closure definition, we use them for verbosity only.
//! let cost: CostFunctionType = Box::new(
//! move |parameters: &[&[f64]],
//! residuals: &mut [f64],
//! mut jacobians: Option<&mut [Option<&mut [&mut [f64]]>]>| {
//! // residuals have the size of your data set, in our case it is just 1
//! residuals[0] = parameters[0][0] - 2.0;
//! // jacobians can be None, then you don't need to provide them
//! if let Some(jacobians) = jacobians {
//! // The size of the jacobians array is equal to the number of parameters,
//! // each element is Option<&mut [&mut [f64]]>
//! if let Some(d_dx) = &mut jacobians[0] {
//! // Each element in the jacobians array is slice of slices:
//! // the first index is for different residuals components,
//! // the second index is for different components of the parameter vector
//! d_dx[0][0] = 1.0;
//! }
//! }
//! true
//! },
//! );
//! // 1 is the number of residuals.
//! let cost_function = CostFunction::new(cost, parameter_sizes, 1);
//!
//! let mut problem = NllsProblem::new();
//!
//! // There could be many residual blocks, each has its own parameters.
//! problem
//! .add_residual_block(ResidualBlock::new(initial_parameters, cost_function))
//! .unwrap();
//! // solution is a vector of parameters, one per residual block. Type annotation is not needed.
//! let solution: Vec<Vec<Vec<f64>>> = problem.solve().unwrap();
//!
//! assert!(f64::abs(solution[0][0][0] - true_parameters[0][0]) < 1e-8);
//! ```
//!
//! We also provide a lighter interface for 1-D multiparameter curve fit problems via
//! [CurveFitProblem1D]. Let's generate data points and fit them for a quadratic function.
//!
//! ```rust
//! use ceres_solver::{CurveFitProblem1D, CurveFunctionType};
//!
//! // A model to use for the cost function.
//! fn model(
//! x: f64,
//! parameters: &[f64],
//! y: &mut f64,
//! jacobians: Option<&mut [Option<f64>]>,
//! ) -> bool {
//! let &[a, b, c]: &[f64; 3] = parameters.try_into().unwrap();
//! *y = a * x.powi(2) + b * x + c;
//! if let Some(jacobians) = jacobians {
//! let [d_da, d_db, d_dc]: &mut [Option<f64>; 3] = jacobians.try_into().unwrap();
//! if let Some(d_da) = d_da {
//! *d_da = x.powi(2);
//! }
//! if let Some(d_db) = d_db {
//! *d_db = x;
//! }
//! if let Some(d_dc) = d_dc {
//! *d_dc = 1.0;
//! }
//! }
//! true
//! }
//!
//! let true_parameters = [1.0, 2.0, 3.0];
//!
//! // Generate data points.
//! let x: Vec<_> = (0..100).map(|i| i as f64 * 0.01).collect();
//! let y: Vec<_> = x
//! .iter()
//! .map(|&x| {
//! let mut y = 0.0;
//! model(x, &true_parameters, &mut y, None);
//! // True value + "noise"
//! y + 0.001 + f64::sin(1e6 * x)
//! })
//! .collect();
//!
//! // Wrap the model to be a cost function.
//! let cost: CurveFunctionType = Box::new(model);
//!
//! // Solve it!
//! let initial_guess = [0.0, 0.0, 0.0];
//! let solution = CurveFitProblem1D::new(cost, &x, &y, &initial_guess, None).to_solution();
//!
//! // Check the results.
//! for (true_value, actual_value) in true_parameters.into_iter().zip(solution.into_iter()) {
//! assert!(f64::abs(true_value - actual_value) < 0.1);
//! }
//! ```
pub use cost::{CostFunction, CostFunctionType};
pub use curve_fit::{CurveFitProblem1D, CurveFunctionType};
pub use loss::{LossFunction, LossFunctionType};
pub use nlls_problem::NllsProblem;
pub use parameters::Parameters;
pub use residual_block::ResidualBlock;
pub mod cost;
pub mod curve_fit;
pub mod error;
pub mod loss;
pub mod nlls_problem;
pub mod parameters;
pub mod residual_block;
pub mod types;