1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use super::Iterative;
use std::fmt;
/// The parameters of an iterative variable
///
/// This parameters are used by the `step_limitation()` method from the `Iterative` trait to reduce the size of a step
#[derive(Debug, Clone, PartialEq)]
pub struct IterativeParams {
max_step_abs: f64,
max_step_rel: f64,
min_value: f64,
max_value: f64,
}
impl IterativeParams {
/// The parameters are used by the `step_limitation()` method from the `Iterative` trait to reduce the size of a step
///
/// Both value `max_step_abs` and `max_step_rel` must be positive
///
/// The `min_value` must be lower than the `max_value`
pub fn new(max_step_abs: f64, max_step_rel: f64, min_value: f64, max_value: f64) -> Self {
if max_step_abs <= 0.0 {
panic!(
"max_step_abs must be strictly positive, provided value was {}",
max_step_abs
);
}
if max_step_rel <= 0.0 {
panic!(
"max_step_rel must be strictly positive, provided value was {}",
max_step_rel
);
}
if min_value >= max_value {
panic!(
"min_value must be strictly inferior to max_value, provided values are {} > {}",
min_value, max_value
);
}
IterativeParams {
max_step_abs,
max_step_rel,
min_value,
max_value,
}
}
pub fn get_min_value(&self) -> f64 {
self.min_value
}
pub fn get_max_value(&self) -> f64 {
self.max_value
}
pub fn get_max_step_abs(&self) -> f64 {
self.max_step_abs
}
pub fn get_max_step_rel(&self) -> f64 {
self.max_step_rel
}
}
impl Default for IterativeParams {
fn default() -> IterativeParams {
IterativeParams {
max_step_abs: f64::INFINITY,
max_step_rel: f64::INFINITY,
min_value: f64::NEG_INFINITY,
max_value: f64::INFINITY,
}
}
}
impl Iterative for IterativeParams {
/// Compute a limited update step
///
/// The step size is reduced according to the following criteria :
///```block
/// abs(step_size) < max_step_abs
/// abs(step_size) < max_step_rel*abs(iterative_value)
///```
/// Also, the step must not violated the constraints on the `min_value` and `max_value` of the iterative variable.
///
/// **Warning**:
/// setting the parameters max_step_rel to a value different from infinity
/// might lead to very reduced step size if the iterative value is near zero.
///
/// # Examples
/// ```
/// use newton_rootfinder as nrf;
/// use nrf::iteratives::*;
///
/// let (max_step_abs, max_step_rel, min_value, max_value) = (1.0, 1.0, f64::NEG_INFINITY, f64::INFINITY);
/// let mut iterative_var = IterativeParams::new(max_step_abs, max_step_rel, min_value, max_value);
/// assert_eq!(iterative_var.step_limitation(1.0, 1.0), 2.0);
/// assert_eq!(iterative_var.step_limitation(1.0, 3.0), 2.0);
///
/// let (max_step_abs, max_step_rel, min_value, max_value) = (0.1, 0.5, f64::NEG_INFINITY, f64::INFINITY);
/// let mut iterative_var = IterativeParams::new(max_step_abs, max_step_rel, min_value, max_value);
/// assert_eq!(iterative_var.step_limitation(1.5, 0.5), 1.6);
/// assert_eq!(iterative_var.step_limitation(0.1, 3.0), 0.15000000000000002);
/// ```
fn step_limitation(&self, value_current: f64, raw_step: f64) -> f64 {
let max_step = self
.max_step_abs
.min(self.max_step_rel * value_current.abs());
let abs_step = raw_step.abs();
let sign_step = raw_step.signum();
let step_lim = (max_step.min(abs_step)) * sign_step;
// limitation by max_step_abs and max_step_rel
let value_next_lim = value_current + step_lim;
// limitation by min_value and max_value
(value_next_lim.max(self.min_value)).min(self.max_value)
}
}
impl fmt::Display for IterativeParams {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut content = String::new();
content.push_str(&format!(
" {:width$}|",
&self.max_step_abs.to_string(),
width = 13
));
content.push_str(&format!(
" {:width$}|",
&self.max_step_rel.to_string(),
width = 13
));
content.push_str(&format!(
" {:width$}|",
&self.min_value.to_string(),
width = 13
));
content.push_str(&format!(
" {:width$}|",
&self.max_value.to_string(),
width = 13
));
write!(f, "{}", content)
}
}