rand_simple/distributions/
chi.rs

1use crate::create_state;
2use crate::standard_distributions::{standard_gamma, xorshift160_0_or_greater_and_less_than_1};
3
4/// Chi Distribution
5///
6/// This struct represents the Chi distribution, which is a special case of the gamma distribution
7/// with a shape parameter equal to half the degrees of freedom. It is useful in various statistical
8/// applications, including hypothesis testing and confidence interval estimation.
9///
10/// # Example
11///
12/// ```
13/// let mut chi = rand_simple::Chi::new([1192_u32, 765_u32, 1543_u32, 2003_u32]);
14///
15/// // Verify the initial state
16/// assert_eq!(format!("{chi}"), "χ(Degree of Freedom parameter) = χ(1)");
17///
18/// // Generate a random number from the Chi distribution with 1 degree of freedom
19/// println!("Initial setting: Random number from Chi distribution with 1 degree of freedom -> {}", chi.sample());
20///
21/// // Change the degrees of freedom
22/// let degree_of_freedom: u64 = 2_u64;
23/// let result: Result<u64, &str> = chi.try_set_params(degree_of_freedom);
24///
25/// // Verify the new state
26/// assert_eq!(format!("{chi}"), "χ(Degree of Freedom parameter) = χ(2)");
27///
28/// // Generate a random number from the Chi distribution with the updated degrees of freedom
29/// println!("Updated setting: Random number from Chi distribution with {} degrees of freedom -> {}", degree_of_freedom, chi.sample());
30/// ```
31///
32/// # Fields
33///
34/// * `xyzuv_u_gamma` - State variable for gamma distribution random number generation
35/// * `xyzuv_n_0_gamma` - State variable for gamma distribution random number generation
36/// * `xyzuv_n_1_gamma` - State variable for gamma distribution random number generation
37/// * `xyzuv_uniform` - State variable for uniform distribution random number generation
38/// * `degree_of_freedom` - Degrees of freedom, must be a positive integer
39///
40pub struct Chi {
41    xyzuv_u_gamma: [u32; 5], // State variable for gamma distribution random number generation
42    xyzuv_n_0_gamma: [u32; 5], // State variable for gamma distribution random number generation
43    xyzuv_n_1_gamma: [u32; 5], // State variable for gamma distribution random number generation
44
45    xyzuv_uniform: [u32; 5], // State variable for uniform distribution random number generation
46
47    degree_of_freedom: u64, // Degrees of freedom, must be a positive integer
48}
49
50impl Chi {
51    /// Constructor for the `Chi` struct
52    /// # Arguments
53    ///
54    /// * `seeds` - An array of 4 unsigned 32-bit integers used as seeds for the random number generators.
55    ///             The seeds are adjusted to ensure they are unique and suitable for the random number generation.
56    pub fn new(seeds: [u32; 4_usize]) -> Self {
57        // Adjust the seeds to ensure they are suitable for the random number generation
58        let adjusted_seeds = crate::adjust_seeds!(seeds);
59
60        // Create a new instance of the Chi struct with the adjusted seeds
61        Self {
62            // Initialize the state variables for gamma distribution random number generation
63            xyzuv_u_gamma: create_state(adjusted_seeds[0]), // Seed for gamma distribution random number generator 1
64            xyzuv_n_0_gamma: create_state(adjusted_seeds[1]), // Seed for gamma distribution random number generator 2
65            xyzuv_n_1_gamma: create_state(adjusted_seeds[2]), // Seed for gamma distribution random number generator 3
66
67            // Initialize the state variable for uniform distribution random number generation
68            xyzuv_uniform: create_state(adjusted_seeds[3]), // Seed for uniform distribution random number generator
69
70            // Set the initial degrees of freedom
71            degree_of_freedom: 1_u64, // Default degrees of freedom
72        }
73    }
74
75    /// Generates a random number following the Chi distribution.
76    pub fn sample(&mut self) -> f64 {
77        // Step 1: Generate a random number Y following the Chi-squared distribution (χ^2(x))
78        let y = if self.degree_of_freedom > 1_u64 {
79            // If degrees of freedom > 1, generate a gamma distribution random number with the degrees of freedom as the shape parameter
80            standard_gamma(
81                &mut self.xyzuv_u_gamma,
82                &mut self.xyzuv_n_0_gamma,
83                &mut self.xyzuv_n_1_gamma,
84                &(self.degree_of_freedom as f64),
85            ) * 2_f64
86        } else {
87            // If degrees of freedom == 1, generate a random number using a specific method
88            let y = standard_gamma(
89                &mut self.xyzuv_u_gamma,
90                &mut self.xyzuv_n_0_gamma,
91                &mut self.xyzuv_n_1_gamma,
92                &(3_f64 / 2_f64),
93            ) * 2_f64;
94            let u = xorshift160_0_or_greater_and_less_than_1(&mut self.xyzuv_uniform); // Generate a uniform random number in the interval (0, 1)
95            u.powi(2) * y * 2_f64
96        };
97        // Step 2: Calculate X = √Y
98        y.sqrt() // Return the square root of Y as the final random number
99    }
100
101    /// Updates the parameters of the random variable.
102    /// # Parameters
103    ///
104    /// * `degree_of_freedom` - The degrees of freedom `r` (should be a natural number).
105    pub fn try_set_params(&mut self, degree_of_freedom: u64) -> Result<u64, &str> {
106        // Step 1: Validate the degrees of freedom
107        if degree_of_freedom < 1_u64 {
108            // If the degrees of freedom is less than 1, return an error message
109            Err("自由度は自然数である必要があります。確率変数のパラメータは前回の設定を維持します。")
110        } else {
111            // Step 2: Update the internal state with the new degrees of freedom
112            self.degree_of_freedom = degree_of_freedom;
113            // Return the updated degrees of freedom
114            Ok(degree_of_freedom)
115        }
116    }
117}
118
119impl core::fmt::Display for Chi {
120    /// Formatter for displaying in macros like println!
121    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
122        // Writes the formatted string to the formatter
123        write!(
124            f,
125            "χ(Degree of Freedom parameter) = χ({})",
126            self.degree_of_freedom
127        )?;
128        Ok(())
129    }
130}