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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
//!
//! # Range creation tool
//!
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// # Creating a range by increment
///
/// Creating a range with the start, stop, and increment. If the range is invalid, an empty Vec is returned.
/// The points of this range are evenly spaced.
///
/// ```
/// # use scilib::range::by_increment;
/// let res = by_increment(2.0, -1.0, -0.5);
/// assert_eq!(res[0], 2.0);
/// assert_eq!(res.last().unwrap(), &-1.0);
/// assert_eq!(res.len(), 7);
/// ```
pub fn by_increment<T, U, V>(start: T, stop: U, step: V) -> Vec<f64>
where T: Into<f64>, U: Into<f64>, V: Into<f64> {
let mut res: Vec<f64> = Vec::new();
// Casting values
let mut computed: f64 = start.into();
let end: f64 = stop.into();
let inc: f64 = step.into();
// If the sign of this is pos, the increment doesn't make sense
if ((computed - end) / inc).is_sign_positive() {
return res;
}
'pushing: loop {
if ((computed - end) / inc).is_sign_positive() {
break 'pushing;
}
res.push(computed);
computed += inc;
}
res
}
/// # Creating a range from a number of points
///
/// Creating a range with the start, stop, and number of points. If the range is invalid, an empty Vec is returned.
/// The points of this range are evenly spaced.
///
/// ```
/// # use scilib::range::linear;
/// let r = linear(0.0, -10.0, 15);
/// assert_eq!(r[0], 0.0);
/// assert_eq!(r.last().unwrap(), &-10.0);
/// assert_eq!(r.len(), 15);
/// ```
pub fn linear<T, U>(start: T, stop: U, n_points: usize) -> Vec<f64>
where T: Into<f64>, U: Into<f64> {
let start_f: f64 = start.into();
let stop_f: f64 = stop.into();
let step: f64 = stop_f - start_f;
let mut res: Vec<f64> = Vec::with_capacity(n_points);
if n_points == 1 {
res.push(start_f);
return res;
}
for i in (0..n_points).map(|j| j as f64 / (n_points - 1) as f64) {
res.push(start_f + i * step);
}
res
}
/// # Creating a logarithmic range from a number of points
///
/// Creating a range with the start, stop, and number of points. If the range is invalid, an empty Vec is returned.
/// The points of this range are space based on the log given log base.
///
/// ```
/// # use scilib::range::logarithmic;
/// let r = logarithmic(0.1, 10.0, 15, 10.0);
/// assert!((r[0] - 0.1).abs() < 1.0e-15); // Start is correct
/// assert!((r[7] - 1.0).abs() < 1.0e-15); // Distribution is correct
/// assert_eq!(r.last().unwrap(), &10.0); // End is correct
/// assert_eq!(r.len(), 15); // Number of points is correct
/// ```
pub fn logarithmic<T, U, V>(start: T, stop: U, n_points: usize, base: V) -> Vec<f64>
where T: Into<f64>, U: Into<f64>, V: Into<f64> {
let start_f: f64 = start.into();
let stop_f: f64 = stop.into();
let base_f: f64 = base.into();
// If the scale includes 0.0, it doesn't work
if start_f == 0.0 || stop_f == 0.0 || start_f.signum() != stop_f.signum() {
return vec![];
}
if n_points == 1 {
return vec![start_f];
}
let sg: f64 = start_f.signum();
let start_l: f64 = start_f.abs().log(base_f);
let stop_l: f64 = stop_f.abs().log(base_f);
let mut res: Vec<f64> = linear(start_l, stop_l, n_points);
for elem in res.iter_mut() {
*elem = sg * base_f.powf(*elem);
}
res
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// # ∑ operation
///
/// Implementation of the mathematical summation.
/// * `type` - the type of the result
/// * `var` - name of the variable used in the loop (ex: i, n, j, etc)
/// * `range` - range used for the loop
/// * `form` - the formula summed
///
/// Which effectively computes:
/// $$
/// y = \sum_{i=r_\mathrm{min}}^{r_\mathrm{max}}f(i)
/// $$
/// With $r_\mathrm{min}$ and $r_\mathrm{max}$ the bounding values of the range, $i$ the variable used and
/// $f(i)$ the formula applied.
///
/// ```
/// # #[macro_use] extern crate scilib;
/// # use scilib::math::basic::*;
/// let res1 = summation!(u32, n, 0..=10, n);
/// assert_eq!(55, res1);
/// let res2 = summation!(f64, n, 0..=10, n as f64 * 0.5);
/// assert_eq!(27.5, res2);
/// ```
#[macro_export]
macro_rules! summation {
($type:ty, $var:pat, $range:expr, $form:expr) => {{
let mut result: $type = 0 as $type;
for $var in $range {
result += $form;
}
result
}};
}
/// # Π operation
///
/// Implementation of the mathematical product.
/// * `type` - the type of the result
/// * `var` - name of the variable used in the loop (ex: i, n, j, etc)
/// * `range` - range used for the loop
/// * `form` - the formula multiplied
///
/// Which effectively computes:
/// $$
/// y = \prod_{i=r_\mathrm{min}}^{r_\mathrm{max}}f(i)
/// $$
/// With $r_\mathrm{min}$ and $r_\mathrm{max}$ the bounding values of the range, $i$ the variable used and
/// $f(i)$ the formula applied.
///
/// ```
/// # #[macro_use] extern crate scilib;
/// # use scilib::math::basic::*;
/// let res = product!(usize, i, 1..=10, i); // = 10!
/// assert_eq!(3628800, res);
/// assert_eq!(res, factorial(10_usize));
/// ```
#[macro_export]
macro_rules! product {
($type:ty, $var:pat, $range:expr, $form:expr) => {{
let mut result: $type = 1 as $type;
for $var in $range {
result *= $form;
}
result
}};
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////