src/tolerance.rs

changeset 0
eb3c7813b67a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tolerance.rs	Thu Dec 01 23:07:35 2022 +0200
@@ -0,0 +1,89 @@
+//! Tolerance update schemes for subproblem solution quality
+use serde::{Serialize, Deserialize};
+use numeric_literals::replace_float_literals;
+use crate::types::*;
+
+/// 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
+    }
+}

mercurial