pub mod lbfgs;
pub use lbfgs::LbfgsState;
use crate::core::math::{MatrixIdentity, 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;
}
pub trait GradientState: State {
fn gradient(&self) -> Option<&Self::Param>;
fn 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> {
pub(crate) param: P,
pub(crate) cost: Option<f64>,
pub(crate) gradient: Option<P>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
pub(crate) gradient_evals: u64,
}
impl<P> BasicState<P> {
pub fn new(param: P) -> Self {
Self {
param,
cost: None,
gradient: None,
iter: 0,
cost_evals: 0,
gradient_evals: 0,
}
}
}
impl<P> State for BasicState<P> {
type Param = P;
type Float = f64;
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) -> f64 {
self.cost
.expect("BasicState::cost read before Solver::init populated it")
}
}
impl<P> GradientState for BasicState<P> {
fn gradient(&self) -> Option<&P> {
self.gradient.as_ref()
}
fn gradient_evals(&self) -> u64 {
self.gradient_evals
}
}
impl<P> CountsMirror for BasicState<P> {
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> {
pub(crate) vertices: Vec<V>,
pub(crate) costs: Vec<f64>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
}
impl<V> BasicSimplexState<V> {
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![f64::INFINITY; n],
iter: 0,
cost_evals: 0,
}
}
}
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> BasicSimplexState<V> {
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> State for BasicSimplexState<V> {
type Param = V;
type Float = f64;
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) -> f64 {
self.costs[0]
}
}
impl<V> CountsMirror for BasicSimplexState<V> {
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.total_work();
}
}
impl<V> SimplexState for BasicSimplexState<V> {
fn vertices(&self) -> &[V] {
&self.vertices
}
fn costs(&self) -> &[f64] {
&self.costs
}
}
pub struct QuasiNewtonState<V, M> {
pub(crate) param: V,
pub(crate) cost: Option<f64>,
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,
}
impl<V: VectorLen, M: MatrixIdentity> QuasiNewtonState<V, M> {
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,
}
}
}
impl<V, M> State for QuasiNewtonState<V, M> {
type Param = V;
type Float = f64;
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) -> f64 {
self.cost
.expect("QuasiNewtonState::cost read before Solver::init populated it")
}
}
impl<V, M> GradientState for QuasiNewtonState<V, M> {
fn gradient(&self) -> Option<&V> {
self.gradient.as_ref()
}
fn gradient_evals(&self) -> u64 {
self.gradient_evals
}
}
impl<V, M> CountsMirror for QuasiNewtonState<V, M> {
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> {
pub(crate) candidates: Vec<V>,
pub(crate) costs: Vec<f64>,
pub(crate) iter: u64,
pub(crate) cost_evals: u64,
}
impl<V> BasicPopulationState<V> {
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![f64::INFINITY; n],
iter: 0,
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,
}
}
}
impl<V> State for BasicPopulationState<V> {
type Param = V;
type Float = f64;
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) -> f64 {
self.costs[0]
}
}
impl<V> CountsMirror for BasicPopulationState<V> {
fn mirror(&mut self, delta: &EvalCounts) {
self.cost_evals = delta.total_work();
}
}
impl<V> PopulationState for BasicPopulationState<V> {
fn candidates(&self) -> &[V] {
&self.candidates
}
fn costs(&self) -> &[f64] {
&self.costs
}
}