ferray_random/
parallel.rs1use ferray_core::{Array, FerrayError, Ix1};
7
8use crate::bitgen::BitGenerator;
9use crate::distributions::normal::standard_normal_pair;
10use crate::generator::Generator;
11
12impl<B: BitGenerator + Clone> Generator<B> {
13 pub fn standard_normal_parallel(
29 &mut self,
30 size: usize,
31 ) -> Result<Array<f64, Ix1>, FerrayError> {
32 if size == 0 {
33 return Err(FerrayError::invalid_value("size must be > 0"));
34 }
35
36 let mut data = Vec::with_capacity(size);
46 while data.len() < size {
47 let (a, b) = standard_normal_pair(&mut self.bg);
48 data.push(a);
49 if data.len() < size {
50 data.push(b);
51 }
52 }
53
54 let n = data.len();
55 Array::<f64, Ix1>::from_vec(Ix1::new([n]), data)
56 }
57
58 pub fn spawn(&mut self, n: usize) -> Result<Vec<Generator<B>>, FerrayError> {
68 crate::generator::spawn_generators(self, n)
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::default_rng_seeded;
75
76 #[test]
77 fn parallel_matches_sequential() {
78 let mut rng1 = default_rng_seeded(42);
80 let mut rng2 = default_rng_seeded(42);
81
82 let seq = rng1.standard_normal(10_000).unwrap();
83 let par = rng2.standard_normal_parallel(10_000).unwrap();
84
85 assert_eq!(
86 seq.as_slice().unwrap(),
87 par.as_slice().unwrap(),
88 "parallel and sequential outputs differ"
89 );
90 }
91
92 #[test]
93 fn parallel_deterministic() {
94 let mut rng1 = default_rng_seeded(42);
95 let mut rng2 = default_rng_seeded(42);
96
97 let a = rng1.standard_normal_parallel(50_000).unwrap();
98 let b = rng2.standard_normal_parallel(50_000).unwrap();
99
100 assert_eq!(a.as_slice().unwrap(), b.as_slice().unwrap());
101 }
102
103 #[test]
104 fn parallel_large() {
105 let mut rng = default_rng_seeded(42);
106 let arr = rng.standard_normal_parallel(1_000_000).unwrap();
107 assert_eq!(arr.shape(), &[1_000_000]);
108 let slice = arr.as_slice().unwrap();
110 let mean: f64 = slice.iter().sum::<f64>() / slice.len() as f64;
111 assert!(mean.abs() < 0.01, "parallel mean {mean} too far from 0");
112 }
113
114 #[test]
115 fn spawn_creates_independent_generators() {
116 let mut rng = default_rng_seeded(42);
117 let mut children = rng.spawn(4).unwrap();
118 assert_eq!(children.len(), 4);
119
120 let outputs: Vec<u64> = children.iter_mut().map(|c| c.next_u64()).collect();
122 for i in 0..outputs.len() {
123 for j in (i + 1)..outputs.len() {
124 assert_ne!(
125 outputs[i], outputs[j],
126 "children {i} and {j} produced same first value"
127 );
128 }
129 }
130 }
131
132 #[test]
133 fn spawn_deterministic() {
134 let mut rng1 = default_rng_seeded(42);
135 let mut rng2 = default_rng_seeded(42);
136
137 let mut children1 = rng1.spawn(4).unwrap();
138 let mut children2 = rng2.spawn(4).unwrap();
139
140 for (c1, c2) in children1.iter_mut().zip(children2.iter_mut()) {
141 for _ in 0..100 {
142 assert_eq!(c1.next_u64(), c2.next_u64());
143 }
144 }
145 }
146
147 #[test]
148 fn parallel_zero_size_error() {
149 let mut rng = default_rng_seeded(42);
150 assert!(rng.standard_normal_parallel(0).is_err());
151 }
152}