-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: Add Function and Optimizer traits for general optimization
Although the primary goal of Gomez - solving non-linear systems of equations - remains still the same, I believe that providing means for general numerical optimization may benefit someone for the features that Gomez has: first-class support for bounds, simple, low-level, iterative API and various utilities. Moreover, two out of three algorithms implemented so far are optimization algorithms, not solvers anyway. As solving equations is the primary goal, the information about general optimization is rather omitted from the documentation and that is on purpose.
- Loading branch information
Showing
16 changed files
with
644 additions
and
359 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,23 @@ | ||
//! Core abstractions and types for Gomez. | ||
//! | ||
//! *Users* are mainly interested in implementing the [`System`] trait, | ||
//! optionally specifying the [domain](Domain). | ||
//! *Users* are mainly interested in implementing the [`System`] and [`Problem`] | ||
//! traits, optionally specifying the [domain](Domain). | ||
//! | ||
//! Algorithms *developers* are interested in implementing the [`Solver`] trait | ||
//! and using extension traits [`SystemExt`] and [`VectorDomainExt`] as well as | ||
//! tools in [derivatives](crate::derivatives) or | ||
//! [population](crate::population) modules. | ||
//! (or possibly the [`Optimizer`] trait too) and using extension traits (e.g., | ||
//! [`VectorDomainExt`]) as well as tools in [derivatives](crate::derivatives) | ||
//! or [population](crate::population) modules. | ||
mod base; | ||
mod domain; | ||
mod function; | ||
mod optimizer; | ||
mod solver; | ||
mod system; | ||
|
||
pub use base::*; | ||
pub use domain::*; | ||
pub use function::*; | ||
pub use optimizer::*; | ||
pub use solver::*; | ||
pub use system::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use nalgebra::{Dim, RealField}; | ||
use thiserror::Error; | ||
|
||
use super::domain::Domain; | ||
|
||
/// The base trait for [`System`](super::system::System) and | ||
/// [`Function`](super::function::Function). | ||
pub trait Problem { | ||
/// Type of the scalar, usually f32 or f64. | ||
type Scalar: RealField; | ||
|
||
/// Dimension of the system. Can be fixed | ||
/// ([`Const`](nalgebra::base::dimension::Const)) or dynamic | ||
/// ([`Dynamic`](nalgebra::base::dimension::Dynamic)). | ||
type Dim: Dim; | ||
|
||
/// Return the actual dimension of the system. This is needed for dynamic | ||
/// systems. | ||
fn dim(&self) -> Self::Dim; | ||
|
||
/// Get the domain (bound constraints) of the system. If not overridden, the | ||
/// system is unconstrained. | ||
fn domain(&self) -> Domain<Self::Scalar> { | ||
Domain::with_dim(self.dim().value()) | ||
} | ||
} | ||
|
||
/// Error encountered while applying variables to the function. | ||
#[derive(Debug, Error)] | ||
pub enum Error { | ||
/// The number of variables does not match the dimensionality | ||
/// ([`Problem::dim`]) of the problem. | ||
#[error("invalid dimensionality")] | ||
InvalidDimensionality, | ||
/// An invalid value (NaN, positive or negative infinity) of a residual or | ||
/// the function value occurred. | ||
#[error("invalid value encountered")] | ||
InvalidValue, | ||
/// A custom error specific to the system or function. | ||
#[error("{0}")] | ||
Custom(Box<dyn std::error::Error>), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
use nalgebra::{ | ||
allocator::Allocator, storage::Storage, storage::StorageMut, DefaultAllocator, Vector, | ||
}; | ||
use num_traits::Zero; | ||
|
||
use super::{ | ||
base::{Error, Problem}, | ||
system::System, | ||
}; | ||
|
||
/// The trait for defining functions. | ||
/// | ||
/// ## Defining a function | ||
/// | ||
/// A function is any type that implements [`Function`] and [`Problem`] traits. | ||
/// There are two required associated types (scalar type and dimension type) and | ||
/// two required methods: [`apply`](Function::apply) and [`dim`](Problem::dim). | ||
/// | ||
/// ```rust | ||
/// use gomez::nalgebra as na; | ||
/// use gomez::prelude::*; | ||
/// use na::{Dim, DimName}; | ||
/// | ||
/// // A problem is represented by a type. | ||
/// struct Rosenbrock { | ||
/// a: f64, | ||
/// b: f64, | ||
/// } | ||
/// | ||
/// impl Problem for Rosenbrock { | ||
/// // The numeric type. Usually f64 or f32. | ||
/// type Scalar = f64; | ||
/// // The dimension of the problem. Can be either statically known or dynamic. | ||
/// type Dim = na::U2; | ||
/// | ||
/// // Return the actual dimension of the system. | ||
/// fn dim(&self) -> Self::Dim { | ||
/// na::U2::name() | ||
/// } | ||
/// } | ||
/// | ||
/// impl Function for Rosenbrock { | ||
/// // Apply trial values of variables to the function. | ||
/// fn apply<Sx>( | ||
/// &self, | ||
/// x: &na::Vector<Self::Scalar, Self::Dim, Sx>, | ||
/// ) -> Result<Self::Scalar, Error> | ||
/// where | ||
/// Sx: na::storage::Storage<Self::Scalar, Self::Dim>, | ||
/// { | ||
/// // Compute the function value. | ||
/// Ok((self.a - x[0]).powi(2) + self.b * (x[1] - x[0].powi(2)).powi(2)) | ||
/// } | ||
/// } | ||
/// ``` | ||
pub trait Function: Problem { | ||
/// Calculate the function value given values of the variables. | ||
fn apply<Sx>(&self, x: &Vector<Self::Scalar, Self::Dim, Sx>) -> Result<Self::Scalar, Error> | ||
where | ||
Sx: Storage<Self::Scalar, Self::Dim>; | ||
|
||
/// Calculate the norm of residuals of the system given values of the | ||
/// variable for cases when the function is actually a system of equations. | ||
/// | ||
/// The optimizers should prefer calling this function because the | ||
/// implementation for systems reuse `fx` for calculating the residuals and | ||
/// do not make an unnecessary allocation for it. | ||
fn apply_eval<Sx, Sfx>( | ||
&self, | ||
x: &Vector<Self::Scalar, Self::Dim, Sx>, | ||
fx: &mut Vector<Self::Scalar, Self::Dim, Sfx>, | ||
) -> Result<Self::Scalar, Error> | ||
where | ||
Sx: Storage<Self::Scalar, Self::Dim>, | ||
Sfx: StorageMut<Self::Scalar, Self::Dim>, | ||
{ | ||
let norm = self.apply(x)?; | ||
fx.fill(Self::Scalar::zero()); | ||
fx[0] = norm; | ||
Ok(norm) | ||
} | ||
} | ||
|
||
impl<F: System> Function for F | ||
where | ||
DefaultAllocator: Allocator<F::Scalar, F::Dim>, | ||
{ | ||
fn apply<Sx>(&self, x: &Vector<Self::Scalar, Self::Dim, Sx>) -> Result<Self::Scalar, Error> | ||
where | ||
Sx: Storage<Self::Scalar, Self::Dim>, | ||
{ | ||
let mut fx = x.clone_owned(); | ||
self.apply_eval(x, &mut fx) | ||
} | ||
|
||
fn apply_eval<Sx, Sfx>( | ||
&self, | ||
x: &Vector<Self::Scalar, Self::Dim, Sx>, | ||
fx: &mut Vector<Self::Scalar, Self::Dim, Sfx>, | ||
) -> Result<Self::Scalar, Error> | ||
where | ||
Sx: Storage<Self::Scalar, Self::Dim>, | ||
Sfx: StorageMut<Self::Scalar, Self::Dim>, | ||
{ | ||
self.eval(x, fx)?; | ||
let norm = fx.norm(); | ||
Ok(norm) | ||
} | ||
} |
Oops, something went wrong.