| 1 //! Tolerance update schemes for subproblem solution quality |
1 //! Tolerance update schemes for subproblem solution quality |
| 2 use serde::{Serialize, Deserialize}; |
2 use crate::types::*; |
| 3 use numeric_literals::replace_float_literals; |
3 use numeric_literals::replace_float_literals; |
| 4 use crate::types::*; |
4 use serde::{Deserialize, Serialize}; |
| 5 |
5 |
| 6 /// Update style for optimality system solution tolerance |
6 /// Update style for optimality system solution tolerance |
| 7 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
7 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
| 8 #[allow(dead_code)] |
8 #[allow(dead_code)] |
| 9 pub enum Tolerance<F : Float> { |
9 pub enum Tolerance<F: Float> { |
| 10 /// $ε_k = εθ^k$ for the `factor` $θ$ and initial tolerance $ε$. |
10 /// $ε_k = εθ^k$ for the `factor` $θ$ and initial tolerance $ε$. |
| 11 Exponential{ factor : F, initial : F }, |
11 Exponential { factor: F, initial: F }, |
| 12 /// $ε_k = ε/(1+θk)^p$ for the `factor` $θ$, `exponent` $p$, and initial tolerance $ε$. |
12 /// $ε_k = ε/(1+θk)^p$ for the `factor` $θ$, `exponent` $p$, and initial tolerance $ε$. |
| 13 Power{ factor : F, exponent : F, initial : F}, |
13 Power { factor: F, exponent: F, initial: F }, |
| 14 /// $ε_k = εθ^{⌊k^p⌋}$ for the `factor` $θ$, initial tolerance $ε$, and exponent $p$. |
14 /// $ε_k = εθ^{⌊k^p⌋}$ for the `factor` $θ$, initial tolerance $ε$, and exponent $p$. |
| 15 SlowExp{ factor : F, exponent : F, initial : F } |
15 SlowExp { factor: F, exponent: F, initial: F }, |
| 16 } |
16 } |
| 17 |
17 |
| 18 #[replace_float_literals(F::cast_from(literal))] |
18 #[replace_float_literals(F::cast_from(literal))] |
| 19 impl<F : Float> Default for Tolerance<F> { |
19 impl<F: Float> Default for Tolerance<F> { |
| 20 fn default() -> Self { |
20 fn default() -> Self { |
| 21 Tolerance::Power { |
21 Tolerance::Power { |
| 22 initial : 0.5, |
22 initial: 0.5, |
| 23 factor : 0.2, |
23 factor: 0.2, |
| 24 exponent : 1.4 // 1.5 works but is already slower in practise on our examples. |
24 exponent: 1.4, // 1.5 works but is already slower in practise on our examples. |
| 25 } |
25 } |
| 26 } |
26 } |
| 27 } |
27 } |
| 28 |
28 |
| 29 #[replace_float_literals(F::cast_from(literal))] |
29 #[replace_float_literals(F::cast_from(literal))] |
| 30 impl<F : Float> Tolerance<F> { |
30 impl<F: Float> Tolerance<F> { |
| 31 /// Get the initial tolerance |
31 /// Get the initial tolerance |
| 32 pub fn initial(&self) -> F { |
32 pub fn initial(&self) -> F { |
| 33 match self { |
33 match self { |
| 34 &Tolerance::Exponential { initial, .. } => initial, |
34 &Tolerance::Exponential { initial, .. } => initial, |
| 35 &Tolerance::Power { initial, .. } => initial, |
35 &Tolerance::Power { initial, .. } => initial, |
| 45 Tolerance::SlowExp { ref mut initial, .. } => initial, |
45 Tolerance::SlowExp { ref mut initial, .. } => initial, |
| 46 } |
46 } |
| 47 } |
47 } |
| 48 |
48 |
| 49 /// Set the initial tolerance |
49 /// Set the initial tolerance |
| 50 pub fn set_initial(&mut self, set : F) { |
50 pub fn set_initial(&mut self, set: F) { |
| 51 *self.initial_mut() = set; |
51 *self.initial_mut() = set; |
| 52 } |
52 } |
| 53 |
53 |
| 54 /// Update `tolerance` for iteration `iter`. |
54 /// Update `tolerance` for iteration `iter`. |
| 55 /// `tolerance` may or may not be used depending on the specific |
55 /// `tolerance` may or may not be used depending on the specific |
| 56 /// update scheme. |
56 /// update scheme. |
| 57 pub fn update(&self, tolerance : F, iter : usize) -> F { |
57 pub fn update(&self, tolerance: F, iter: usize) -> F { |
| 58 match self { |
58 match self { |
| 59 &Tolerance::Exponential { factor, .. } => { |
59 &Tolerance::Exponential { factor, .. } => tolerance * factor, |
| 60 tolerance * factor |
|
| 61 }, |
|
| 62 &Tolerance::Power { factor, exponent, initial } => { |
60 &Tolerance::Power { factor, exponent, initial } => { |
| 63 initial /(1.0 + factor * F::cast_from(iter)).powf(exponent) |
61 initial / (1.0 + factor * F::cast_from(iter)).powf(exponent) |
| 64 }, |
62 } |
| 65 &Tolerance::SlowExp { factor, exponent, initial } => { |
63 &Tolerance::SlowExp { factor, exponent, initial } => { |
| 66 // let m = (speed |
64 // let m = (speed |
| 67 // * factor.powi(-(iter as i32)) |
65 // * factor.powi(-(iter as i32)) |
| 68 // * F::cast_from(iter).powf(-exponent) |
66 // * F::cast_from(iter).powf(-exponent) |
| 69 // ).floor().as_(); |
67 // ).floor().as_(); |
| 70 let m = F::cast_from(iter).powf(exponent).floor().as_(); |
68 let m = F::cast_from(iter).powf(exponent).floor().as_(); |
| 71 initial * factor.powi(m) |
69 initial * factor.powi(m) |
| 72 }, |
70 } |
| 73 } |
71 } |
| 74 } |
72 } |
| 75 } |
73 } |
| 76 |
74 |
| 77 impl<F: Float> std::ops::MulAssign<F> for Tolerance<F> { |
75 impl<F: Float> std::ops::MulAssign<F> for Tolerance<F> { |
| 78 fn mul_assign(&mut self, factor : F) { |
76 fn mul_assign(&mut self, factor: F) { |
| 79 *self.initial_mut() *= factor; |
77 *self.initial_mut() *= factor; |
| 80 } |
78 } |
| 81 } |
79 } |
| 82 |
80 |
| 83 impl<F: Float> std::ops::Mul<F> for Tolerance<F> { |
81 impl<F: Float> std::ops::Mul<F> for Tolerance<F> { |
| 84 type Output = Tolerance<F>; |
82 type Output = Tolerance<F>; |
| 85 fn mul(mut self, factor : F) -> Self::Output { |
83 fn mul(mut self, factor: F) -> Self::Output { |
| 86 *self.initial_mut() *= factor; |
84 *self.initial_mut() *= factor; |
| 87 self |
85 self |
| 88 } |
86 } |
| 89 } |
87 } |