pub mod cma_es;
pub mod lbfgs;
pub mod nlls;
pub mod scalar;
pub use cma_es::CmaEsState;
pub use lbfgs::LbfgsState;
pub use nlls::NllsState;
pub use scalar::ScalarState;
use crate::core::math::{MatrixIdentity, Scalar, VectorLen};
use crate::core::problem::EvalCounts;
pub trait State {
type Param;
type Float;
fn iter(&self) -> u64;
fn increment_iter(&mut self);
fn cost_evals(&self) -> u64;
fn param(&self) -> &Self::Param;
fn cost(&self) -> Self::Float;
fn best_param(&self) -> &Self::Param;
fn best_cost(&self) -> Self::Float;
fn best_iter(&self) -> u64;
fn best_cost_evals(&self) -> u64;
fn update_best(&mut self);
fn reset_best(&mut self);
}
pub trait GradientState: State {
fn gradient(&self) -> Option<&Self::Param>;
fn gradient_evals(&self) -> u64;
fn best_gradient_evals(&self) -> u64;
}
pub trait CountsMirror: State {
fn mirror(&mut self, delta: &EvalCounts);
}
pub trait SimplexState: State {
fn vertices(&self) -> &[Self::Param];
fn costs(&self) -> &[Self::Float];
}
pub trait PopulationState: State {
fn candidates(&self) -> &[Self::Param];
fn costs(&self) -> &[Self::Float];
}
pub struct BasicState<P, F = f64> {
pub(crate) param: P,
pub(crate) cost: Option<F>,
pub(crate) gradient: Option<P>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
pub(crate) gradient_evals: u64,
pub(crate) best_param: Option<P>,
pub(crate) best_cost: F,
pub(crate) best_iter: u64,
pub(crate) best_cost_evals: u64,
pub(crate) best_gradient_evals: u64,
}
impl<P, F: Scalar> BasicState<P, F> {
pub fn new(param: P) -> Self {
Self {
param,
cost: None,
gradient: None,
iter: 0,
cost_evals: 0,
gradient_evals: 0,
best_param: None,
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
best_gradient_evals: 0,
}
}
}
impl<P: Clone, F: Scalar> State for BasicState<P, F> {
type Param = P;
type Float = F;
fn iter(&self) -> u64 {
self.iter
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn cost_evals(&self) -> u64 {
self.cost_evals
}
fn param(&self) -> &P {
&self.param
}
fn cost(&self) -> F {
self.cost
.expect("BasicState::cost read before Solver::init populated it")
}
fn best_param(&self) -> &P {
self.best_param
.as_ref()
.expect("BasicState::best_param read before Solver::init populated it")
}
fn best_cost(&self) -> F {
self.best_cost
}
fn best_iter(&self) -> u64 {
self.best_iter
}
fn best_cost_evals(&self) -> u64 {
self.best_cost_evals
}
fn update_best(&mut self) {
if let Some(curr) = self.cost {
if self.best_param.is_none() || curr < self.best_cost {
self.best_param = Some(self.param.clone());
self.best_cost = curr;
self.best_iter = self.iter;
self.best_cost_evals = self.cost_evals;
self.best_gradient_evals = self.gradient_evals;
}
}
}
fn reset_best(&mut self) {
self.best_param = None;
self.best_cost = F::infinity();
self.best_iter = 0;
self.best_cost_evals = 0;
self.best_gradient_evals = 0;
}
}
impl<P: Clone, F: Scalar> GradientState for BasicState<P, F> {
fn gradient(&self) -> Option<&P> {
self.gradient.as_ref()
}
fn gradient_evals(&self) -> u64 {
self.gradient_evals
}
fn best_gradient_evals(&self) -> u64 {
self.best_gradient_evals
}
}
impl<P, F> CountsMirror for BasicState<P, F>
where
BasicState<P, F>: State,
{
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.cost_evals + delta.residual_evals;
self.gradient_evals = delta.gradient_evals + delta.jacobian_evals + delta.hessian_evals;
}
}
pub struct BasicSimplexState<V, F = f64> {
pub(crate) vertices: Vec<V>,
pub(crate) costs: Vec<F>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
pub(crate) best_cost: F,
pub(crate) best_iter: u64,
pub(crate) best_cost_evals: u64,
pub(crate) scratch: Vec<V>,
}
impl<V, F: Scalar> BasicSimplexState<V, F> {
pub fn from_simplex(vertices: Vec<V>) -> Self {
assert!(
vertices.len() >= 2,
"BasicSimplexState requires at least 2 vertices (n+1 for an n-D problem)"
);
let n = vertices.len();
Self {
vertices,
costs: vec![F::infinity(); n],
iter: 0,
cost_evals: 0,
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
scratch: Vec::new(),
}
}
}
pub trait IntoInitialSimplex<V> {
fn into_initial_simplex(self, relative_step: f64) -> Vec<V>;
}
impl IntoInitialSimplex<Self> for Vec<f64> {
fn into_initial_simplex(self, relative_step: f64) -> Vec<Self> {
let n = self.len();
let mut simplex = Vec::with_capacity(n + 1);
simplex.push(self.clone());
for i in 0..n {
let mut v = self.clone();
v[i] = if self[i] != 0.0 {
(1.0 + relative_step) * self[i]
} else {
0.00025
};
simplex.push(v);
}
simplex
}
}
#[cfg(feature = "nalgebra")]
impl IntoInitialSimplex<Self> for nalgebra::DVector<f64> {
fn into_initial_simplex(self, relative_step: f64) -> Vec<Self> {
let n = self.len();
let mut simplex = Vec::with_capacity(n + 1);
simplex.push(self.clone());
for i in 0..n {
let mut v = self.clone();
v[i] = if self[i] != 0.0 {
(1.0 + relative_step) * self[i]
} else {
0.00025
};
simplex.push(v);
}
simplex
}
}
#[cfg(feature = "faer")]
impl IntoInitialSimplex<Self> for faer::Col<f64> {
fn into_initial_simplex(self, relative_step: f64) -> Vec<Self> {
let n = self.nrows();
let mut simplex = Vec::with_capacity(n + 1);
simplex.push(self.clone());
for i in 0..n {
let mut v = self.clone();
v[i] = if self[i] != 0.0 {
(1.0 + relative_step) * self[i]
} else {
0.00025
};
simplex.push(v);
}
simplex
}
}
#[cfg(feature = "ndarray")]
impl IntoInitialSimplex<ndarray::Array1<f64>> for ndarray::Array1<f64> {
fn into_initial_simplex(self, relative_step: f64) -> Vec<ndarray::Array1<f64>> {
let n = self.len();
let mut simplex = Vec::with_capacity(n + 1);
simplex.push(self.clone());
for i in 0..n {
let mut v = self.clone();
v[i] = if self[i] != 0.0 {
(1.0 + relative_step) * self[i]
} else {
0.00025
};
simplex.push(v);
}
simplex
}
}
impl<V, F: Scalar> BasicSimplexState<V, F> {
pub fn new<X: IntoInitialSimplex<V>>(x0: X) -> Self {
Self::from_simplex(x0.into_initial_simplex(0.05))
}
pub fn with_step<X: IntoInitialSimplex<V>>(x0: X, relative_step: f64) -> Self {
Self::from_simplex(x0.into_initial_simplex(relative_step))
}
}
impl<V, F: Scalar> State for BasicSimplexState<V, F> {
type Param = V;
type Float = F;
fn iter(&self) -> u64 {
self.iter
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn cost_evals(&self) -> u64 {
self.cost_evals
}
fn param(&self) -> &V {
&self.vertices[0]
}
fn cost(&self) -> F {
self.costs[0]
}
fn best_param(&self) -> &V {
&self.vertices[0]
}
fn best_cost(&self) -> F {
self.best_cost
}
fn best_iter(&self) -> u64 {
self.best_iter
}
fn best_cost_evals(&self) -> u64 {
self.best_cost_evals
}
fn update_best(&mut self) {
let curr = self.costs[0];
if curr < self.best_cost {
self.best_cost = curr;
self.best_iter = self.iter;
self.best_cost_evals = self.cost_evals;
}
}
fn reset_best(&mut self) {
self.best_cost = F::infinity();
self.best_iter = 0;
self.best_cost_evals = 0;
}
}
impl<V, F> CountsMirror for BasicSimplexState<V, F>
where
BasicSimplexState<V, F>: State,
{
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.total_work();
}
}
impl<V, F: Scalar> SimplexState for BasicSimplexState<V, F> {
fn vertices(&self) -> &[V] {
&self.vertices
}
fn costs(&self) -> &[F] {
&self.costs
}
}
pub struct QuasiNewtonState<V, M, F = f64> {
pub(crate) param: V,
pub(crate) cost: Option<F>,
pub(crate) gradient: Option<V>,
pub(crate) inverse_hessian: M,
pub(crate) initial_scaling_done: bool,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
pub(crate) gradient_evals: u64,
pub(crate) best_param: Option<V>,
pub(crate) best_cost: F,
pub(crate) best_iter: u64,
pub(crate) best_cost_evals: u64,
pub(crate) best_gradient_evals: u64,
}
impl<V: VectorLen, M: MatrixIdentity, F: Scalar> QuasiNewtonState<V, M, F> {
pub fn new(param: V) -> Self {
let n = param.vec_len();
Self {
param,
cost: None,
gradient: None,
inverse_hessian: M::identity(n),
initial_scaling_done: false,
iter: 0,
cost_evals: 0,
gradient_evals: 0,
best_param: None,
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
best_gradient_evals: 0,
}
}
}
pub type DenseQuasiNewtonState<F = f64> =
QuasiNewtonState<Vec<F>, crate::core::math::DenseMatrix<F>, F>;
#[cfg(feature = "nalgebra")]
pub type NalgebraQuasiNewtonState<F = f64> =
QuasiNewtonState<nalgebra::DVector<F>, nalgebra::DMatrix<F>, F>;
#[cfg(feature = "faer")]
pub type FaerQuasiNewtonState<F = f64> = QuasiNewtonState<faer::Col<F>, faer::Mat<F>, F>;
impl<V: Clone, M, F: Scalar> State for QuasiNewtonState<V, M, F> {
type Param = V;
type Float = F;
fn iter(&self) -> u64 {
self.iter
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn cost_evals(&self) -> u64 {
self.cost_evals
}
fn param(&self) -> &V {
&self.param
}
fn cost(&self) -> F {
self.cost
.expect("QuasiNewtonState::cost read before Solver::init populated it")
}
fn best_param(&self) -> &V {
self.best_param
.as_ref()
.expect("QuasiNewtonState::best_param read before Solver::init populated it")
}
fn best_cost(&self) -> F {
self.best_cost
}
fn best_iter(&self) -> u64 {
self.best_iter
}
fn best_cost_evals(&self) -> u64 {
self.best_cost_evals
}
fn update_best(&mut self) {
if let Some(curr) = self.cost {
if self.best_param.is_none() || curr < self.best_cost {
self.best_param = Some(self.param.clone());
self.best_cost = curr;
self.best_iter = self.iter;
self.best_cost_evals = self.cost_evals;
self.best_gradient_evals = self.gradient_evals;
}
}
}
fn reset_best(&mut self) {
self.best_param = None;
self.best_cost = F::infinity();
self.best_iter = 0;
self.best_cost_evals = 0;
self.best_gradient_evals = 0;
}
}
impl<V: Clone, M, F: Scalar> GradientState for QuasiNewtonState<V, M, F> {
fn gradient(&self) -> Option<&V> {
self.gradient.as_ref()
}
fn gradient_evals(&self) -> u64 {
self.gradient_evals
}
fn best_gradient_evals(&self) -> u64 {
self.best_gradient_evals
}
}
impl<V: Clone, M, F: Scalar> CountsMirror for QuasiNewtonState<V, M, F> {
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.cost_evals + delta.residual_evals;
self.gradient_evals = delta.gradient_evals + delta.jacobian_evals + delta.hessian_evals;
}
}
pub struct BasicPopulationState<V, F = f64> {
pub(crate) candidates: Vec<V>,
pub(crate) costs: Vec<F>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
pub(crate) best_cost: F,
pub(crate) best_iter: u64,
pub(crate) best_cost_evals: u64,
}
impl<V, F: Scalar> BasicPopulationState<V, F> {
pub fn from_population(candidates: Vec<V>) -> Self {
assert!(
!candidates.is_empty(),
"BasicPopulationState requires a non-empty population"
);
let n = candidates.len();
Self {
candidates,
costs: vec![F::infinity(); n],
iter: 0,
cost_evals: 0,
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
}
}
pub fn with_size(lambda: usize) -> Self {
assert!(lambda >= 1, "BasicPopulationState requires lambda >= 1");
Self {
candidates: Vec::with_capacity(lambda),
costs: Vec::with_capacity(lambda),
iter: 0,
cost_evals: 0,
best_cost: F::infinity(),
best_iter: 0,
best_cost_evals: 0,
}
}
}
impl<V, F: Scalar> State for BasicPopulationState<V, F> {
type Param = V;
type Float = F;
fn iter(&self) -> u64 {
self.iter
}
fn increment_iter(&mut self) {
self.iter += 1;
}
fn cost_evals(&self) -> u64 {
self.cost_evals
}
fn param(&self) -> &V {
&self.candidates[0]
}
fn cost(&self) -> F {
self.costs[0]
}
fn best_param(&self) -> &V {
&self.candidates[0]
}
fn best_cost(&self) -> F {
self.best_cost
}
fn best_iter(&self) -> u64 {
self.best_iter
}
fn best_cost_evals(&self) -> u64 {
self.best_cost_evals
}
fn update_best(&mut self) {
let curr = self.costs[0];
if curr < self.best_cost {
self.best_cost = curr;
self.best_iter = self.iter;
self.best_cost_evals = self.cost_evals;
}
}
fn reset_best(&mut self) {
self.best_cost = F::infinity();
self.best_iter = 0;
self.best_cost_evals = 0;
}
}
impl<V, F> CountsMirror for BasicPopulationState<V, F>
where
BasicPopulationState<V, F>: State,
{
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.total_work();
}
}
impl<V, F: Scalar> PopulationState for BasicPopulationState<V, F> {
fn candidates(&self) -> &[V] {
&self.candidates
}
fn costs(&self) -> &[F] {
&self.costs
}
}