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
use crate::create_state;
use crate::standard_distributions::standard_normal;

/// Lévy Distribution
/// # Example
/// ```
/// // Create a new Lévy distribution with a location parameter (μ) of 0 and a scale parameter (θ) of 1
/// let mut levy = rand_simple::Levy::new([1192_u32, 765_u32]);
/// assert_eq!(format!("{levy}"), "Lévy(Location parameter, Scale parameter) = Lévy(0, 1)");
/// println!("Returns a random number following a standard Levy distribution -> {}", levy.sample());
///
/// // Modify the distribution's parameters
/// let location: f64 = -2_f64;
/// let scale: f64 = 1.5_f64;
/// // Update the parameters and generate a random number following the modified Levy distribution
/// let result: Result<(f64, f64), &str> = levy.try_set_params(location, scale);
/// assert_eq!(format!("{levy}"), "Lévy(Location parameter, Scale parameter) = Lévy(-2, 1.5)");
/// println!("Returns a random number following a Levy distribution with location μ = {} and scale θ = {} -> {}", location, scale, levy.sample());
/// ```
pub struct Levy {
    xyzuv0: [u32; 5], // 状態変数
    xyzuv1: [u32; 5], // 状態変数
    location: f64,    // 位置母数
    scale: f64,       // 尺度母数
}

impl Levy {
    /// Constructor
    /// * `seeds` - Random number seeds. Adjusted internally to ensure uniqueness.
    pub fn new(seeds: [u32; 2_usize]) -> Self {
        let adjusted_seeds = crate::adjust_seeds!(seeds);
        Self {
            xyzuv0: create_state(adjusted_seeds[0]),
            xyzuv1: create_state(adjusted_seeds[1]),
            location: 0_f64,
            scale: 1_f64,
        }
    }

    /// Generate a random number.
    pub fn sample(&mut self) -> f64 {
        loop {
            let z = standard_normal(&mut self.xyzuv0, &mut self.xyzuv1).abs();
            if z > 0_f64 {
                return z.powi(-2_i32) * self.scale + self.location;
            }
        }
    }

    /// Modify the parameters of the probability variable.
    /// * `location` - Location parameter
    /// * `scale` - Scale parameter
    pub fn try_set_params(
        &mut self,
        location: f64,
        scale: f64,
    ) -> Result<(f64, f64), &'static str> {
        if scale <= 0_f64 {
            Err("The scale parameter is less than or equal to 0. The parameters of the probability variable remain unchanged.")
        } else {
            self.location = location;
            self.scale = scale;
            Ok((location, scale))
        }
    }
}

impl core::fmt::Display for Levy {
    /// Formatter for use with macros like `println!`
    /// * Location parameter
    /// * Scale parameter
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(
            f,
            "Lévy(Location parameter, Scale parameter) = Lévy({}, {})",
            self.location, self.scale
        )?;
        Ok(())
    }
}