Skip to content

Commit

Permalink
feat!: introduce own RealField trait
Browse files Browse the repository at this point in the history
  • Loading branch information
pnevyk committed Nov 12, 2023
1 parent 5d8c8e1 commit abe0f65
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 26 deletions.
6 changes: 3 additions & 3 deletions src/analysis/initial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use nalgebra::{
};

use crate::{
core::{Domain, Problem, System},
derivatives::{Jacobian, EPSILON_SQRT},
core::{Domain, Problem, RealField, System},
derivatives::Jacobian,
};

/// Initial guesses analyzer. See [module](self) documentation for more details.
Expand Down Expand Up @@ -75,7 +75,7 @@ impl<F: System> InitialGuessAnalysis<F> {
.filter(|(_, (c1, c2))| {
c1.iter()
.zip(c2.iter())
.any(|(a, b)| (*a - *b).abs() > convert(EPSILON_SQRT))
.any(|(a, b)| (*a - *b).abs() > F::Field::EPSILON_SQRT)
})
.map(|(col, _)| col)
.collect();
Expand Down
25 changes: 23 additions & 2 deletions src/core/base.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
use nalgebra::RealField;

use super::domain::Domain;

/// Trait implemented by real numbers.
pub trait RealField: nalgebra::RealField {
/// Square root of double precision machine epsilon. This value is a
/// standard constant for epsilons in approximating first-order
/// derivate-based concepts.
const EPSILON_SQRT: Self;

/// Cubic root of double precision machine epsilon. This value is a standard
/// constant for epsilons in approximating second-order derivate-based
/// concepts.
const EPSILON_CBRT: Self;
}

/// The base trait for [`System`](super::system::System) and
/// [`Function`](super::function::Function).
pub trait Problem {
Expand All @@ -12,3 +23,13 @@ pub trait Problem {
/// system is unconstrained.
fn domain(&self) -> Domain<Self::Field>;
}

impl RealField for f32 {
const EPSILON_SQRT: Self = 0.00034526698;
const EPSILON_CBRT: Self = 0.0049215667;
}

impl RealField for f64 {
const EPSILON_SQRT: Self = 0.000000014901161193847656;
const EPSILON_CBRT: Self = 0.0000060554544523933395;
}
17 changes: 4 additions & 13 deletions src/derivatives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,12 @@
use std::ops::Deref;

use nalgebra::{
convert,
storage::{Storage, StorageMut},
ComplexField, DimName, Dynamic, IsContiguous, OMatrix, OVector, RealField, Vector, U1,
};
use num_traits::{One, Zero};

use crate::core::{Function, Problem, System};

/// Square root of double precision machine epsilon. This value is a standard
/// constant for epsilons in approximating first-order derivate-based concepts.
pub const EPSILON_SQRT: f64 = 0.000000014901161193847656;

/// Cubic root of double precision machine epsilon. This value is a standard
/// constant for epsilons in approximating second-order derivate-based concepts.
pub const EPSILON_CBRT: f64 = 0.0000060554544523933395;
use crate::core::{Function, Problem, RealField as _, System};

/// Jacobian matrix of a system.
#[derive(Debug)]
Expand Down Expand Up @@ -76,7 +67,7 @@ impl<F: System> Jacobian<F> {
Sscale: Storage<F::Field, Dynamic>,
Sfx: Storage<F::Field, Dynamic>,
{
let eps: F::Field = convert(EPSILON_SQRT);
let eps = F::Field::EPSILON_SQRT;

for (j, mut col) in self.jac.column_iter_mut().enumerate() {
let xj = x[j];
Expand Down Expand Up @@ -173,7 +164,7 @@ impl<F: Function> Gradient<F> {
Sx: StorageMut<F::Field, Dynamic> + IsContiguous,
Sscale: Storage<F::Field, Dynamic>,
{
let eps: F::Field = convert(EPSILON_SQRT);
let eps = F::Field::EPSILON_SQRT;

for i in 0..x.nrows() {
let xi = x[i];
Expand Down Expand Up @@ -265,7 +256,7 @@ impl<F: Function> Hessian<F> {
Sx: StorageMut<F::Field, Dynamic> + IsContiguous,
Sscale: Storage<F::Field, Dynamic>,
{
let eps: F::Field = convert(EPSILON_CBRT);
let eps = F::Field::EPSILON_CBRT;

for i in 0..x.nrows() {
let xi = x[i];
Expand Down
7 changes: 2 additions & 5 deletions src/solver/nelder_mead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ use nalgebra::{
use num_traits::{One, Zero};
use thiserror::Error;

use crate::{
core::{Domain, Function, Optimizer, Problem, Solver, System},
derivatives::EPSILON_SQRT,
};
use crate::core::{Domain, Function, Optimizer, Problem, RealField as _, Solver, System};

/// Family of coefficients for reflection, expansion and contractions.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -435,7 +432,7 @@ impl<F: Function> NelderMead<F> {
// otherwise an error reduction was achieved. This criterion is
// taken from "Less is more: Simplified Nelder-Mead method for large
// unconstrained optimization".
let eps: F::Field = convert(EPSILON_SQRT);
let eps = F::Field::EPSILON_SQRT;

let worst = errors[sort_perm[n]];
let best = errors[sort_perm[0]];
Expand Down
6 changes: 3 additions & 3 deletions src/solver/trust_region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use num_traits::{One, Zero};
use thiserror::Error;

use crate::{
core::{Domain, Function, Optimizer, Problem, Solver, System},
derivatives::{Gradient, Hessian, Jacobian, EPSILON_SQRT},
core::{Domain, Function, Optimizer, Problem, RealField as _, Solver, System},
derivatives::{Gradient, Hessian, Jacobian},
};

/// Specification for initial value of trust region size.
Expand Down Expand Up @@ -102,7 +102,7 @@ impl<F: Problem> TrustRegionOptions<F> {
impl<F: Problem> Default for TrustRegionOptions<F> {
fn default() -> Self {
Self {
delta_min: convert(EPSILON_SQRT),
delta_min: F::Field::EPSILON_SQRT,
delta_max: convert(1e9),
delta_init: DeltaInit::Estimated,
mu_min: convert(1e-10),
Expand Down

0 comments on commit abe0f65

Please sign in to comment.