Current section
Files
Jump to
Current section
Files
src/gleastsq.gleam
import gleam/option.{type Option}
import gleastsq/internal/methods/gauss_newton as gn
import gleastsq/internal/methods/levenberg_marquardt as lm
import gleastsq/internal/methods/trust_region_reflective as trr
import gleastsq/internal/params.{decode_params}
import gleastsq/options.{type LeastSquareOptions}
/// The `least_squares` function is an alias for the `levenberg_marquardt` function.
/// Check the documentation of the `levenberg_marquardt` function for more information.
pub fn least_squares(
x: List(Float),
y: List(Float),
func: fn(Float, List(Float)) -> Float,
initial_params: List(Float),
opts opts: List(LeastSquareOptions),
) {
lm.levenberg_marquardt(x, y, func, initial_params, decode_params(opts))
}
/// The `levenberg_marquardt` function performs the Levenberg-Marquardt optimization algorithm.
/// It is used to solve non-linear least squares problems. This function takes as input the data points,
/// the model function, and several optional parameters to control the optimization process.
///
/// # Parameters
/// - `x` (List(Float))
/// A list of x-values of the data points.
/// - `y` (List(Float))
/// A list of y-values of the data points.
/// - `func` (fn(Float, List(Float)) -> Float)
/// The model function that takes an x-value and a list of parameters, and returns the corresponding y-value.
/// - `initial_params` (List(Float))
/// A list of initial guesses for the parameters of the model function.
/// This list must not be empty.
/// - `opts` (List(LeastSquareOptions))
/// A list of optional parameters to control the optimization process.
/// The available options are:
/// - `Iterations(Int)`: The maximum number of iterations to perform. Default is 100.
/// - `Epsilon(Float)`: A small value to change x when calculating the derivatives for the function. Default is 0.0001.
/// - `Tolerance(Float)`: The convergence tolerance. Default is 0.0001.
/// - `Damping(Float)`: The initial value of the damping parameter. Default is 0.0001.
/// - `DampingIncrease(Float)`: The factor by which the damping parameter is increased when a step fails. Default is 10.0.
/// - `DampingDecrease(Float)`: The factor by which the damping parameter is decreased when a step succeeds. Default is 0.1.
///
/// # Errors
/// Returns `Error(WrongParameters(_))` if `x` and `y` have different lengths or
/// if `initial_params` is empty.
///
/// # Example
/// ```gleam
/// import gleam/io
/// import gleastsq
/// import gleastsq/options.{Iterations, Tolerance}
///
/// fn parabola(x: Float, params: List(Float)) -> Float {
/// let assert [a, b, c] = params
/// a *. x *. x +. b *. x +. c
/// }
///
/// pub fn main() {
/// let x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
/// let y = [0.0, 1.0, 4.0, 9.0, 16.0, 25.0]
/// let initial_guess = [1.0, 1.0, 1.0]
///
/// let assert Ok(result) =
/// gleastsq.levenberg_marquardt(
/// x,
/// y,
/// parabola,
/// initial_guess,
/// opts: [Iterations(1000), Tolerance(0.001)]
/// )
///
/// io.debug(result) // [1.0, 0.0, 0.0] (within numerical error)
/// }
/// ```
pub fn levenberg_marquardt(
x: List(Float),
y: List(Float),
func: fn(Float, List(Float)) -> Float,
initial_params: List(Float),
opts opts: List(LeastSquareOptions),
) {
lm.levenberg_marquardt(x, y, func, initial_params, decode_params(opts))
}
/// The `gauss_newton` function performs a basic least squares optimization algorithm.
/// It is used to find the best-fit parameters for a given model function to a set of data points.
/// This function takes as input the data points, the model function, and several optional parameters to control the optimization process.
///
/// # Parameters
/// - `x` (List(Float))
/// A list of x-values of the data points.
/// - `y` (List(Float))
/// A list of y-values of the data points.
/// - `func` (fn(Float, List(Float)) -> Float)
/// The model function that takes an x-value and a list of parameters, and returns the corresponding y-value.
/// - `initial_params` (List(Float))
/// A list of initial guesses for the parameters of the model function.
/// This list must not be empty.
/// - `opts` (List(LeastSquareOptions))
/// A list of optional parameters to control the optimization process.
/// The available options are:
/// - `Iterations(Int)`: The maximum number of iterations to perform. Default is 100.
/// - `Epsilon(Float)`: A small value to change x when calculating the derivatives for the function. Default is 0.0001.
/// - `Tolerance(Float)`: The convergence tolerance. Default is 0.0001.
/// - `Damping(Float)`: The value of the damping parameter. Default is 0.001.
///
/// # Errors
/// Returns `Error(WrongParameters(_))` if `x` and `y` have different lengths or
/// if `initial_params` is empty.
///
/// # Example
/// ```gleam
/// import gleam/io
/// import gleastsq
/// import gleastsq/options.{Iterations, Tolerance}
///
/// fn parabola(x: Float, params: List(Float)) -> Float {
/// let assert [a, b, c] = params
/// a *. x *. x +. b *. x +. c
/// }
///
/// pub fn main() {
/// let x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
/// let y = [0.0, 1.0, 4.0, 9.0, 16.0, 25.0]
/// let initial_guess = [1.0, 1.0, 1.0]
///
/// let assert Ok(result) =
/// gleastsq.gauss_newton(
/// x,
/// y,
/// parabola,
/// initial_guess,
/// opts: [Iterations(1000), Tolerance(0.001)]
/// )
///
/// io.debug(result) // [1.0, 0.0, 0.0] (within numerical error)
/// }
/// ```
pub fn gauss_newton(
x: List(Float),
y: List(Float),
func: fn(Float, List(Float)) -> Float,
initial_params: List(Float),
opts opts: List(LeastSquareOptions),
) {
gn.gauss_newton(x, y, func, initial_params, decode_params(opts))
}
/// The `trust_region_reflective` function performs a bounded trust-region least
/// squares optimization.
/// It is used to find the best-fit parameters for a given model function to a
/// set of data points while respecting optional upper and lower bounds.
/// This function takes as input the data points, the model function, and
/// several optional parameters to control the optimization process.
///
/// # Parameters
/// - `x` (List(Float))
/// A list of x-values of the data points.
/// - `y` (List(Float))
/// A list of y-values of the data points.
/// - `func` (fn(Float, List(Float)) -> Float)
/// The model function that takes an x-value and a list of parameters, and returns the corresponding y-value.
/// - `initial_params` (List(Float))
/// A list of initial guesses for the parameters of the model function.
/// This list must not be empty. Values outside the provided bounds are
/// clipped to the bounds before optimization begins.
/// - `lower_bounds` (Option(List(Float)))
/// A list of lower bounds for the parameters of the model function. If the lower bound is `None`, then the parameter is unbounded from below.
/// - `upper_bounds` (Option(List(Float)))
/// A list of upper bounds for the parameters of the model function. If the upper bound is `None`, then the parameter is unbounded from above.
/// - `opts` (List(LeastSquareOptions))
/// A list of optional parameters to control the optimization process.
/// The available options are:
/// - `Iterations(Int)`: The maximum number of iterations to perform. Default is 100.
/// - `Epsilon(Float)`: A small value to change x when calculating the derivatives for the function. Default is 0.0001.
/// - `Tolerance(Float)`: The convergence tolerance. Default is 0.00001.
/// - `Damping(Float)`: The value of the damping parameter. Default is 0.001.
///
/// # Errors
/// Returns `Error(WrongParameters(_))` if `x` and `y` have different lengths,
/// if `initial_params` is empty, or if the bound lists have different lengths
/// from `initial_params`.
///
/// # Example
/// ```gleam
/// import gleam/io
/// import gleam/option.{Some}
/// import gleastsq
/// import gleastsq/options.{Iterations, Tolerance}
///
/// fn parabola(x: Float, params: List(Float)) -> Float {
/// let assert [a, b, c] = params
/// a *. x *. x +. b *. x +. c
/// }
///
/// pub fn main() {
/// let x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
/// let y = [0.0, 1.0, 4.0, 9.0, 16.0, 25.0]
/// let initial_guess = [1.0, 1.0, 1.0]
///
/// let assert Ok(result) =
/// gleastsq.trust_region_reflective(
/// x,
/// y,
/// parabola,
/// initial_guess,
/// lower_bounds: Some([0.0, 0.0, 0.0]),
/// upper_bounds: Some([2.0, 2.0, 2.0]),
/// opts: [Iterations(1000), Tolerance(0.001)]
/// )
///
/// io.debug(result) // [1.0, 0.0, 0.0] (within numerical error)
/// }
/// ```
pub fn trust_region_reflective(
x: List(Float),
y: List(Float),
func: fn(Float, List(Float)) -> Float,
initial_params: List(Float),
lower_bounds lower_bounds: Option(List(Float)),
upper_bounds upper_bounds: Option(List(Float)),
opts opts: List(LeastSquareOptions),
) {
trr.trust_region_reflective(
x,
y,
func,
initial_params,
lower_bounds,
upper_bounds,
decode_params(opts),
)
}