Mon, 13 Apr 2026 22:29:26 -0500
Automatic transport disabling after sufficient failures, for efficiency
//! Tolerance update schemes for subproblem solution quality use crate::types::*; use numeric_literals::replace_float_literals; use serde::{Deserialize, Serialize}; /// Update style for optimality system solution tolerance #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] #[allow(dead_code)] pub enum Tolerance<F: Float> { /// $ε_k = εθ^k$ for the `factor` $θ$ and initial tolerance $ε$. Exponential { factor: F, initial: F }, /// $ε_k = ε/(1+θk)^p$ for the `factor` $θ$, `exponent` $p$, and initial tolerance $ε$. Power { factor: F, exponent: F, initial: F }, /// $ε_k = εθ^{⌊k^p⌋}$ for the `factor` $θ$, initial tolerance $ε$, and exponent $p$. SlowExp { factor: F, exponent: F, initial: F }, } #[replace_float_literals(F::cast_from(literal))] impl<F: Float> Default for Tolerance<F> { fn default() -> Self { Tolerance::Power { initial: 0.5, factor: 0.2, exponent: 1.4, // 1.5 works but is already slower in practise on our examples. } } } #[replace_float_literals(F::cast_from(literal))] impl<F: Float> Tolerance<F> { /// Get the initial tolerance pub fn initial(&self) -> F { match self { &Tolerance::Exponential { initial, .. } => initial, &Tolerance::Power { initial, .. } => initial, &Tolerance::SlowExp { initial, .. } => initial, } } /// Get mutable reference to the initial tolerance fn initial_mut(&mut self) -> &mut F { match self { Tolerance::Exponential { ref mut initial, .. } => initial, Tolerance::Power { ref mut initial, .. } => initial, Tolerance::SlowExp { ref mut initial, .. } => initial, } } /// Set the initial tolerance pub fn set_initial(&mut self, set: F) { *self.initial_mut() = set; } /// Update `tolerance` for iteration `iter`. /// `tolerance` may or may not be used depending on the specific /// update scheme. pub fn update(&self, tolerance: F, iter: usize) -> F { match self { &Tolerance::Exponential { factor, .. } => tolerance * factor, &Tolerance::Power { factor, exponent, initial } => { initial / (1.0 + factor * F::cast_from(iter)).powf(exponent) } &Tolerance::SlowExp { factor, exponent, initial } => { // let m = (speed // * factor.powi(-(iter as i32)) // * F::cast_from(iter).powf(-exponent) // ).floor().as_(); let m = F::cast_from(iter).powf(exponent).floor().as_(); initial * factor.powi(m) } } } } impl<F: Float> std::ops::MulAssign<F> for Tolerance<F> { fn mul_assign(&mut self, factor: F) { *self.initial_mut() *= factor; } } impl<F: Float> std::ops::Mul<F> for Tolerance<F> { type Output = Tolerance<F>; fn mul(mut self, factor: F) -> Self::Output { *self.initial_mut() *= factor; self } }