statrs 0.11.0

Statistical computing library for Rust
Documentation
//! Provides utility functions for generating data sequences

use euclid::Modulus;
use std::f64::consts;
use std::iter::Take;

/// Generates a base 10 log spaced vector of the given length between the
/// specified decade exponents (inclusive). Equivalent to MATLAB logspace
///
/// # Examples
///
/// ```
/// use statrs::generate;
///
/// let x = generate::log_spaced(5, 0.0, 4.0);
/// assert_eq!(x, [1.0, 10.0, 100.0, 1000.0, 10000.0]);
/// ```
pub fn log_spaced(length: usize, start_exp: f64, stop_exp: f64) -> Vec<f64> {
    match length {
        0 => Vec::new(),
        1 => vec![10f64.powf(stop_exp)],
        _ => {
            let step = (stop_exp - start_exp) / (length - 1) as f64;
            let mut vec = (0..length)
                .map(|x| 10f64.powf(start_exp + (x as f64) * step))
                .collect::<Vec<f64>>();
            vec[length - 1] = 10f64.powf(stop_exp);
            vec
        }
    }
}

/// Infinite iterator returning floats that form a periodic wave
pub struct InfinitePeriodic {
    amplitude: f64,
    step: f64,
    phase: f64,
    k: f64,
}

impl InfinitePeriodic {
    /// Constructs a new infinite periodic wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfinitePeriodic;
    ///
    /// let x = InfinitePeriodic::new(8.0, 2.0, 10.0, 1.0,
    /// 2).take(10).collect::<Vec<f64>>();
    /// assert_eq!(x, [6.0, 8.5, 1.0, 3.5, 6.0, 8.5, 1.0, 3.5, 6.0, 8.5]);
    /// ```
    pub fn new(
        sampling_rate: f64,
        frequency: f64,
        amplitude: f64,
        phase: f64,
        delay: i64,
    ) -> InfinitePeriodic {
        let step = frequency / sampling_rate * amplitude;
        InfinitePeriodic {
            amplitude: amplitude,
            step: step,
            phase: (phase - delay as f64 * step).modulus(amplitude),
            k: 0.0,
        }
    }

    /// Constructs a default infinite periodic wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfinitePeriodic;
    ///
    /// let x = InfinitePeriodic::default(8.0,
    /// 2.0).take(10).collect::<Vec<f64>>();
    /// assert_eq!(x, [0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25]);
    /// ```
    pub fn default(sampling_rate: f64, frequency: f64) -> InfinitePeriodic {
        Self::new(sampling_rate, frequency, 1.0, 0.0, 0)
    }
}

impl Iterator for InfinitePeriodic {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        let mut x = self.phase + self.k * self.step;
        if x >= self.amplitude {
            x %= self.amplitude;
            self.phase = x;
            self.k = 0.0;
        }
        self.k += 1.0;
        Some(x)
    }
}

/// Finite iterator returning floats that form a periodic wave
pub struct Periodic {
    internal: Take<InfinitePeriodic>,
}

impl Periodic {
    /// Constructs a new periodic wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Periodic;
    ///
    /// let x = Periodic::new(10, 8.0, 2.0, 10.0, 1.0, 2).collect::<Vec<f64>>();
    /// assert_eq!(x, [6.0, 8.5, 1.0, 3.5, 6.0, 8.5, 1.0, 3.5, 6.0, 8.5]);
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfinitePeriodic::new` and `take` instead"
    )]
    pub fn new(
        length: usize,
        sampling_rate: f64,
        frequency: f64,
        amplitude: f64,
        phase: f64,
        delay: i64,
    ) -> Periodic {
        Periodic {
            internal: InfinitePeriodic::new(sampling_rate, frequency, amplitude, phase, delay)
                .take(length),
        }
    }

    /// Constructs a default periodic wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Periodic;
    ///
    /// let x = Periodic::default(10, 8.0, 2.0).collect::<Vec<f64>>();
    /// assert_eq!(x, [0.0, 0.25, 0.5, 0.75, 0.0, 0.25, 0.5, 0.75, 0.0, 0.25]);
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfinitePeriodic::default` and `take` instead"
    )]
    pub fn default(length: usize, sampling_rate: f64, frequency: f64) -> Periodic {
        Periodic {
            internal: InfinitePeriodic::default(sampling_rate, frequency).take(length),
        }
    }
}

impl Iterator for Periodic {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.internal.next()
    }
}

/// Infinite iterator returning floats that form a sinusoidal wave
pub struct InfiniteSinusoidal {
    amplitude: f64,
    mean: f64,
    step: f64,
    phase: f64,
    i: usize,
}

impl InfiniteSinusoidal {
    /// Constructs a new infinite sinusoidal wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfiniteSinusoidal;
    ///
    /// let x = InfiniteSinusoidal::new(8.0, 2.0, 1.0, 5.0, 2.0,
    /// 1).take(10).collect::<Vec<f64>>();
    /// assert_eq!(x,
    ///     [5.416146836547142, 5.909297426825682, 4.583853163452858,
    ///     4.090702573174318, 5.416146836547142, 5.909297426825682,
    ///     4.583853163452858, 4.090702573174318, 5.416146836547142,
    ///     5.909297426825682]);
    /// ```
    pub fn new(
        sampling_rate: f64,
        frequency: f64,
        amplitude: f64,
        mean: f64,
        phase: f64,
        delay: i64,
    ) -> InfiniteSinusoidal {
        let pi2 = consts::PI * 2.0;
        let step = frequency / sampling_rate * pi2;
        InfiniteSinusoidal {
            amplitude: amplitude,
            mean: mean,
            step: step,
            phase: (phase - delay as f64 * step) % pi2,
            i: 0,
        }
    }

    /// Constructs a default infinite sinusoidal wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfiniteSinusoidal;
    ///
    /// let x = InfiniteSinusoidal::default(8.0, 2.0,
    /// 1.0).take(10).collect::<Vec<f64>>();
    /// assert_eq!(x,
    ///     [0.0, 1.0, 0.00000000000000012246467991473532,
    ///     -1.0, -0.00000000000000024492935982947064, 1.0,
    ///     0.00000000000000036739403974420594, -1.0,
    ///     -0.0000000000000004898587196589413, 1.0]);
    /// ```
    pub fn default(sampling_rate: f64, frequency: f64, amplitude: f64) -> InfiniteSinusoidal {
        Self::new(sampling_rate, frequency, amplitude, 0.0, 0.0, 0)
    }
}

impl Iterator for InfiniteSinusoidal {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        let x = self.mean + self.amplitude * (self.phase + self.i as f64 * self.step).sin();
        self.i += 1;
        if self.i == 1000 {
            self.i = 0;
            self.phase = (self.phase + 1000.0 * self.step) % (consts::PI * 2.0);
        }
        Some(x)
    }
}

/// Finite iterator returning floats that form a sinusoidal wave
pub struct Sinusoidal {
    internal: Take<InfiniteSinusoidal>,
}

impl Sinusoidal {
    /// Constructs a new sinusoidal wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Sinusoidal;
    ///
    /// let x = Sinusoidal::new(10, 8.0, 2.0, 1.0, 5.0, 2.0,
    /// 1).collect::<Vec<f64>>();
    /// assert_eq!(x,
    ///     [5.416146836547142, 5.909297426825682, 4.583853163452858,
    ///     4.090702573174318, 5.416146836547142, 5.909297426825682,
    ///     4.583853163452858, 4.090702573174318, 5.416146836547142,
    ///     5.909297426825682]);
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfiniteSinusoidal::new` and `take` instead"
    )]
    pub fn new(
        length: usize,
        sampling_rate: f64,
        frequency: f64,
        amplitude: f64,
        mean: f64,
        phase: f64,
        delay: i64,
    ) -> Sinusoidal {
        Sinusoidal {
            internal: InfiniteSinusoidal::new(
                sampling_rate,
                frequency,
                amplitude,
                mean,
                phase,
                delay,
            )
            .take(length),
        }
    }

    /// Constructs a default sinusoidal wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Sinusoidal;
    ///
    /// let x = Sinusoidal::default(10, 8.0, 2.0, 1.0).collect::<Vec<f64>>();
    /// assert_eq!(x,
    ///     [0.0, 1.0, 0.00000000000000012246467991473532,
    ///     -1.0, -0.00000000000000024492935982947064, 1.0,
    ///     0.00000000000000036739403974420594, -1.0,
    ///     -0.0000000000000004898587196589413, 1.0]);
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfiniteSinusoidal::default` and `take` instead"
    )]
    pub fn default(
        length: usize,
        sampling_rate: f64,
        frequency: f64,
        amplitude: f64,
    ) -> Sinusoidal {
        Sinusoidal {
            internal: InfiniteSinusoidal::default(sampling_rate, frequency, amplitude).take(length),
        }
    }
}

impl Iterator for Sinusoidal {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.internal.next()
    }
}

/// Infinite iterator returning floats forming a square wave starting
/// with the high phase
pub struct InfiniteSquare {
    periodic: InfinitePeriodic,
    high_duration: f64,
    high_value: f64,
    low_value: f64,
}

impl InfiniteSquare {
    /// Constructs a new infinite square wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfiniteSquare;
    ///
    /// let x = InfiniteSquare::new(3, 7, 1.0, -1.0,
    /// 1).take(12).collect::<Vec<f64>>();
    /// assert_eq!(x, [-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
    /// -1.0, 1.0])
    /// ```
    pub fn new(
        high_duration: i64,
        low_duration: i64,
        high_value: f64,
        low_value: f64,
        delay: i64,
    ) -> InfiniteSquare {
        let duration = (high_duration + low_duration) as f64;
        InfiniteSquare {
            periodic: InfinitePeriodic::new(1.0, 1.0 / duration, duration, 0.0, delay),
            high_duration: high_duration as f64,
            high_value: high_value,
            low_value: low_value,
        }
    }
}

impl Iterator for InfiniteSquare {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.periodic.next().and_then(|x| {
            if x < self.high_duration {
                Some(self.high_value)
            } else {
                Some(self.low_value)
            }
        })
    }
}

/// Finite iterator returning floats forming a square wave starting
/// with the high phase
pub struct Square {
    internal: Take<InfiniteSquare>,
}

impl Square {
    /// Constructs a new square wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Square;
    ///
    /// let x = Square::new(12, 3, 7, 1.0, -1.0, 1).collect::<Vec<f64>>();
    /// assert_eq!(x, [-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0,
    /// -1.0, 1.0])
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfiniteSquare::new` and `take` instead"
    )]
    pub fn new(
        length: usize,
        high_duration: i64,
        low_duration: i64,
        high_value: f64,
        low_value: f64,
        delay: i64,
    ) -> Square {
        Square {
            internal: InfiniteSquare::new(
                high_duration,
                low_duration,
                high_value,
                low_value,
                delay,
            )
            .take(length),
        }
    }
}

impl Iterator for Square {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.internal.next()
    }
}

/// Infinite iterator returning floats forming a triangle wave starting with
/// the raise phase from the lowest sample
pub struct InfiniteTriangle {
    periodic: InfinitePeriodic,
    raise_duration: f64,
    raise: f64,
    fall: f64,
    high_value: f64,
    low_value: f64,
}

impl InfiniteTriangle {
    /// Constructs a new infinite triangle wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate statrs;
    ///
    /// use statrs::generate::InfiniteTriangle;
    ///
    /// # fn main() {
    /// let x = InfiniteTriangle::new(4, 7, 1.0, -1.0,
    /// 1).take(12).collect::<Vec<f64>>();
    /// let expected: [f64; 12] = [-0.714, -1.0, -0.5, 0.0, 0.5, 1.0, 0.714,
    /// 0.429, 0.143, -0.143, -0.429, -0.714];
    /// for (&left, &right) in x.iter().zip(expected.iter()) {
    ///     assert_almost_eq!(left, right, 1e-3);
    /// }
    /// # }
    /// ```
    pub fn new(
        raise_duration: i64,
        fall_duration: i64,
        high_value: f64,
        low_value: f64,
        delay: i64,
    ) -> InfiniteTriangle {
        let duration = (raise_duration + fall_duration) as f64;
        let height = high_value - low_value;
        InfiniteTriangle {
            periodic: InfinitePeriodic::new(1.0, 1.0 / duration, duration, 0.0, delay),
            raise_duration: raise_duration as f64,
            raise: height / raise_duration as f64,
            fall: height / fall_duration as f64,
            high_value: high_value,
            low_value: low_value,
        }
    }
}

impl Iterator for InfiniteTriangle {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.periodic.next().and_then(|x| {
            if x < self.raise_duration {
                Some(self.low_value + x * self.raise)
            } else {
                Some(self.high_value - (x - self.raise_duration) * self.fall)
            }
        })
    }
}

/// Finite iterator returning floats forming a triangle wave
/// starting with the raise phase from the lowest sample
pub struct Triangle {
    internal: Take<InfiniteTriangle>,
}

impl Triangle {
    /// Constructs a new triangle wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// #[macro_use]
    /// extern crate statrs;
    ///
    /// use statrs::generate::Triangle;
    ///
    /// # fn main() {
    /// let x = Triangle::new(12, 4, 7, 1.0, -1.0, 1).collect::<Vec<f64>>();
    /// let expected: [f64; 12] = [-0.714, -1.0, -0.5, 0.0, 0.5, 1.0, 0.714,
    /// 0.429, 0.143, -0.143, -0.429, -0.714];
    /// for (&left, &right) in x.iter().zip(expected.iter()) {
    ///     assert_almost_eq!(left, right, 1e-3);
    /// }
    /// # }
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfiniteTriangle::new` and `take` instead"
    )]
    pub fn new(
        length: usize,
        raise_duration: i64,
        fall_duration: i64,
        high_value: f64,
        low_value: f64,
        delay: i64,
    ) -> Triangle {
        Triangle {
            internal: InfiniteTriangle::new(
                raise_duration,
                fall_duration,
                high_value,
                low_value,
                delay,
            )
            .take(length),
        }
    }
}

impl Iterator for Triangle {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.internal.next()
    }
}

/// Infinite iterator returning floats forming a sawtooth wave
/// starting with the lowest sample
pub struct InfiniteSawtooth {
    periodic: InfinitePeriodic,
    low_value: f64,
}

impl InfiniteSawtooth {
    /// Constructs a new infinite sawtooth wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::InfiniteSawtooth;
    ///
    /// let x = InfiniteSawtooth::new(5, 1.0, -1.0,
    /// 1).take(12).collect::<Vec<f64>>();
    /// assert_eq!(x, [1.0, -1.0, -0.5, 0.0, 0.5, 1.0, -1.0, -0.5, 0.0, 0.5,
    /// 1.0, -1.0]);
    /// ```
    pub fn new(period: i64, high_value: f64, low_value: f64, delay: i64) -> InfiniteSawtooth {
        let height = high_value - low_value;
        let period = period as f64;
        InfiniteSawtooth {
            periodic: InfinitePeriodic::new(
                1.0,
                1.0 / period,
                height * period / (period - 1.0),
                0.0,
                delay,
            ),
            low_value: low_value as f64,
        }
    }
}

impl Iterator for InfiniteSawtooth {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.periodic.next().and_then(|x| Some(x + self.low_value))
    }
}

/// Finite iterator returning floats forming a sawtooth wave
/// starting with the lowest sample
pub struct Sawtooth {
    internal: Take<InfiniteSawtooth>,
}

impl Sawtooth {
    /// Constructs a new sawtooth wave generator
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::generate::Sawtooth;
    ///
    /// let x = Sawtooth::new(12, 5, 1.0, -1.0, 1).collect::<Vec<f64>>();
    /// assert_eq!(x, [1.0, -1.0, -0.5, 0.0, 0.5, 1.0, -1.0, -0.5, 0.0, 0.5,
    /// 1.0, -1.0]);
    /// ```
    #[deprecated(
        since = "0.9.0",
        note = "please use `InfiniteSawtooth::new` and `take` instead"
    )]
    pub fn new(
        length: usize,
        period: i64,
        high_value: f64,
        low_value: f64,
        delay: i64,
    ) -> Sawtooth {
        Sawtooth {
            internal: InfiniteSawtooth::new(period, high_value, low_value, delay).take(length),
        }
    }
}

impl Iterator for Sawtooth {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        self.internal.next()
    }
}