## Expand description

*gomez* is a framework and implementation for **mathematical optimization**
and solving **non-linear systems of equations**.

The library is written completely in Rust. Its focus is on being useful for
**practical problems** and having API that is simple for easy cases as well
as flexible for complicated ones. The name stands for * g*lobal

*ptimization &*

**o***on-linear*

**n***quations*

**e***olving, with a few typos.*

**s**### Practical problems

The main goal is to be useful for practical problems. This is manifested by the following features:

*Derivative-free*. No algorithm requires an analytical derivative (gradient, Hessian, Jacobian). Methods that use derivatives approximate it using finite difference method^{1}.*Constraints*support. It is possible to specify the problem domain with constraints^{2}, which is necessary for many engineering applications.- Non-naive implementations. The code is not a direct translation of a textbook pseudocode. It’s written with performance in mind and applies important techniques from numerical mathematics. It also tries to handle situations that hurt the methods but occur in practice.

^{1} There is a plan to provide ways to override this approximation
with a real derivative.

^{2} Currently, only unconstrained and box-bounded domains are
supported.

### Algorithms

- Trust region – Recommended method to be used as a default and it will just work in most cases.
- LIPO – Global optimization algorithm useful for searching good initial guesses in combination with a numerical algorithm.
- Steffensen – Fast and lightweight method for solving one-dimensional systems of equations.
- Nelder-Mead – Direct search optimization method that does not use any derivatives.

This list will be extended in the future. But at the same time, having as
many algorithms as possible is *not* the goal. Instead, the focus is on
providing quality implementations of battle-tested methods.

### Mathematical optimization

Given a function *f: D → R* from some domain *D* (in *R ^{n}*) to the
real numbers and an initial point

*x*, the goal is to find a point

_{0}*x’*such that

*f(x’)*is a minimum. Note that gomez does not guarantee that the minimum is global, although the focus is on global optimization techniques.

#### Example

```
use gomez::nalgebra as na;
use gomez::{Domain, Function, OptimizerDriver, Problem};
use na::{Dyn, IsContiguous};
// Objective function is represented by a struct.
struct Rosenbrock {
a: f64,
b: f64,
}
impl Problem for Rosenbrock {
// Field type, f32 or f64.
type Field = f64;
// Domain of the function.
fn domain(&self) -> Domain<Self::Field> {
Domain::unconstrained(2)
}
}
impl Function for Rosenbrock {
// Body of the function, taking x and returning f(x).
fn apply<Sx>(&self, x: &na::Vector<Self::Field, Dyn, Sx>) -> Self::Field
where
Sx: na::Storage<Self::Field, Dyn> + IsContiguous,
{
(self.a - x[0]).powi(2) + self.b * (x[1] - x[0].powi(2)).powi(2)
}
}
let f = Rosenbrock { a: 1.0, b: 1.0 };
let mut optimizer = OptimizerDriver::builder(&f)
.with_initial(vec![-10.0, -5.0])
.build();
let (x, fx) = optimizer
.find(|state| state.fx() <= 1e-6 || state.iter() >= 100)
.expect("optimizer error");
println!("f(x) = {fx}\tx = {x:?}");
```

See `OptimizerDriver`

and `OptimizerBuilder`

for additional options.

### Systems of equations

Given a vector function *r: D → R ^{n}*, with

*r*from some domain

_{i}: D → R*D*(in

*R*) to the real numbers for

^{n}*i = 1, 2, …, n*, and an initial point

*x*, the goal is to find a point

_{0}*x’*such that

*r(x) = 0*. Note that there is no constraint on the form of the equations

*r*(compare with specialized solvers for systems of linear equations).

_{i}#### Example

```
use gomez::nalgebra as na;
use gomez::{Domain, Problem, SolverDriver, System};
use na::{Dyn, IsContiguous};
// System of equations is represented by a struct.
struct Rosenbrock {
a: f64,
b: f64,
}
impl Problem for Rosenbrock {
// Field type, f32 or f64.
type Field = f64;
// Domain of the system.
fn domain(&self) -> Domain<Self::Field> {
Domain::unconstrained(2)
}
}
impl System for Rosenbrock {
// Evaluation of the system (computing the residuals).
fn eval<Sx, Srx>(
&self,
x: &na::Vector<Self::Field, Dyn, Sx>,
rx: &mut na::Vector<Self::Field, Dyn, Srx>,
) where
Sx: na::storage::Storage<Self::Field, Dyn> + IsContiguous,
Srx: na::storage::StorageMut<Self::Field, Dyn>,
{
rx[0] = (self.a - x[0]).powi(2);
rx[1] = self.b * (x[1] - x[0].powi(2)).powi(2);
}
}
let r = Rosenbrock { a: 1.0, b: 1.0 };
let mut solver = SolverDriver::builder(&r)
.with_initial(vec![-10.0, -5.0])
.build();
let (x, norm) = solver
.find(|state| state.norm() <= 1e-6 || state.iter() >= 100)
.expect("solver error");
println!("|| r(x) || = {norm}\tx = {x:?}");
```

See `SolverDriver`

and `SolverBuilder`

for
additional options.

### Custom algorithms

It is possible to create a custom algorithm by implementing the
`Optimizer`

and/or `Solver`

trait. Then it can be used by the driver as
any other algorithm provided by gomez. Go see the documentation of the
traits to get more details.

```
let f = Rosenbrock { a: 1.0, b: 1.0 };
let mut optimizer = OptimizerDriver::builder(&f)
.with_algo(|f, dom| MyAlgo::new(f, dom))
.build();
```

If you implement an algorithm, please reach out to discuss if we could include it in gomez.

### Roadmap

Listed *not* in priority order.

- Homotopy continuation method to compare the performance with the trust region method
- Conjugate gradient method
- Experimentation with various global optimization techniques for initial
guess search
- Evolutionary/nature-inspired algorithms
- Bayesian optimization

- Focus on initial guesses search and tools for analysis in general

### License

Licensed under MIT.

## Re-exports

`pub use driver::OptimizerDriver;`

`pub use driver::SolverDriver;`

`pub use nalgebra;`

## Modules

- The collection of implemented algorithms.
- Various supporting analyses.
- Tools for derivative-based methods.
- High-level API for optimization and solving.

## Structs

- Domain for a problem.

## Traits

- Definition of a function.
- Interface of an optimizer.
- Trait implemented by real numbers.
- Trait for types that can be sampled.
- Interface of a solver.
- Definition of a system of equations.