ferray_random/
generator.rs1use ferray_core::{Array, FerrayError, IxDyn};
7
8use crate::bitgen::{BitGenerator, Xoshiro256StarStar};
9
10pub struct Generator<B: BitGenerator = Xoshiro256StarStar> {
25 pub(crate) bg: B,
27 pub(crate) seed: u64,
29}
30
31impl<B: BitGenerator> Generator<B> {
32 pub fn new(bg: B) -> Self {
34 Self { bg, seed: 0 }
35 }
36
37 pub(crate) fn new_with_seed(bg: B, seed: u64) -> Self {
39 Self { bg, seed }
40 }
41
42 #[inline]
44 pub fn bit_generator(&mut self) -> &mut B {
45 &mut self.bg
46 }
47
48 #[inline]
50 pub fn next_u64(&mut self) -> u64 {
51 self.bg.next_u64()
52 }
53
54 #[inline]
56 pub fn next_f64(&mut self) -> f64 {
57 self.bg.next_f64()
58 }
59
60 #[inline]
62 pub fn next_f32(&mut self) -> f32 {
63 self.bg.next_f32()
64 }
65
66 #[inline]
68 pub fn next_u64_bounded(&mut self, bound: u64) -> u64 {
69 self.bg.next_u64_bounded(bound)
70 }
71
72 pub fn bytes(&mut self, n: usize) -> Vec<u8> {
79 let mut out = Vec::with_capacity(n);
80 let full_words = n / 8;
81 for _ in 0..full_words {
82 out.extend_from_slice(&self.bg.next_u64().to_le_bytes());
83 }
84 let remainder = n % 8;
85 if remainder > 0 {
86 let bytes = self.bg.next_u64().to_le_bytes();
87 out.extend_from_slice(&bytes[..remainder]);
88 }
89 out
90 }
91}
92
93pub fn default_rng() -> Generator<Xoshiro256StarStar> {
104 let seed = {
107 let mut buf = [0u8; 8];
108 if getrandom::getrandom(&mut buf).is_ok() {
109 u64::from_ne_bytes(buf)
110 } else {
111 use std::time::SystemTime;
113 let dur = SystemTime::now()
114 .duration_since(SystemTime::UNIX_EPOCH)
115 .unwrap_or_default();
116 let nanos = dur.as_nanos();
117 let mut s = nanos as u64;
118 s ^= (nanos >> 64) as u64;
119 let stack_var: u8 = 0;
120 s ^= &stack_var as *const u8 as u64;
121 s
122 }
123 };
124 default_rng_seeded(seed)
125}
126
127pub fn default_rng_seeded(seed: u64) -> Generator<Xoshiro256StarStar> {
137 let bg = Xoshiro256StarStar::seed_from_u64(seed);
138 Generator::new_with_seed(bg, seed)
139}
140
141pub fn spawn_generators<B: BitGenerator + Clone>(
150 parent: &mut Generator<B>,
151 n: usize,
152) -> Result<Vec<Generator<B>>, FerrayError> {
153 if n == 0 {
154 return Err(FerrayError::invalid_value("spawn count must be > 0"));
155 }
156
157 let mut children = Vec::with_capacity(n);
158
159 let mut test_bg = parent.bg.clone();
161 if test_bg.jump().is_some() {
162 let mut current = parent.bg.clone();
164 for _ in 0..n {
165 children.push(Generator::new(current.clone()));
166 current.jump();
167 }
168 parent.bg = current;
170 return Ok(children);
171 }
172
173 if let Some(first) = B::stream(parent.seed, 0) {
175 drop(first);
176 for i in 0..n {
177 if let Some(bg) = B::stream(parent.seed, i as u64) {
178 children.push(Generator::new(bg));
179 }
180 }
181 if children.len() == n {
182 return Ok(children);
183 }
184 children.clear();
185 }
186
187 for _ in 0..n {
189 let child_seed = parent.bg.next_u64();
190 let bg = B::seed_from_u64(child_seed);
191 children.push(Generator::new(bg));
192 }
193 Ok(children)
194}
195
196pub(crate) fn generate_vec<B: BitGenerator>(
198 rng: &mut Generator<B>,
199 size: usize,
200 mut f: impl FnMut(&mut B) -> f64,
201) -> Vec<f64> {
202 let mut data = Vec::with_capacity(size);
203 for _ in 0..size {
204 data.push(f(&mut rng.bg));
205 }
206 data
207}
208
209pub(crate) fn generate_vec_f32<B: BitGenerator>(
211 rng: &mut Generator<B>,
212 size: usize,
213 mut f: impl FnMut(&mut B) -> f32,
214) -> Vec<f32> {
215 let mut data = Vec::with_capacity(size);
216 for _ in 0..size {
217 data.push(f(&mut rng.bg));
218 }
219 data
220}
221
222pub(crate) fn generate_vec_i64<B: BitGenerator>(
224 rng: &mut Generator<B>,
225 size: usize,
226 mut f: impl FnMut(&mut B) -> i64,
227) -> Vec<i64> {
228 let mut data = Vec::with_capacity(size);
229 for _ in 0..size {
230 data.push(f(&mut rng.bg));
231 }
232 data
233}
234
235#[inline]
237pub(crate) fn shape_size(shape: &[usize]) -> usize {
238 if shape.is_empty() {
239 0
240 } else {
241 shape.iter().product()
242 }
243}
244
245pub(crate) fn vec_to_array_f64(
247 data: Vec<f64>,
248 shape: &[usize],
249) -> Result<Array<f64, IxDyn>, FerrayError> {
250 Array::<f64, IxDyn>::from_vec(IxDyn::new(shape), data)
251}
252
253pub(crate) fn vec_to_array_f32(
255 data: Vec<f32>,
256 shape: &[usize],
257) -> Result<Array<f32, IxDyn>, FerrayError> {
258 Array::<f32, IxDyn>::from_vec(IxDyn::new(shape), data)
259}
260
261pub(crate) fn vec_to_array_i64(
263 data: Vec<i64>,
264 shape: &[usize],
265) -> Result<Array<i64, IxDyn>, FerrayError> {
266 Array::<i64, IxDyn>::from_vec(IxDyn::new(shape), data)
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn default_rng_seeded_deterministic() {
275 let mut rng1 = default_rng_seeded(42);
276 let mut rng2 = default_rng_seeded(42);
277 for _ in 0..100 {
278 assert_eq!(rng1.next_u64(), rng2.next_u64());
279 }
280 }
281
282 #[test]
283 fn default_rng_works() {
284 let mut rng = default_rng();
285 let v = rng.next_f64();
286 assert!((0.0..1.0).contains(&v));
287 }
288
289 #[test]
290 fn spawn_xoshiro() {
291 let mut parent = default_rng_seeded(42);
292 let children = spawn_generators(&mut parent, 4).unwrap();
293 assert_eq!(children.len(), 4);
294 }
295
296 #[test]
297 fn spawn_zero_is_error() {
298 let mut parent = default_rng_seeded(42);
299 assert!(spawn_generators(&mut parent, 0).is_err());
300 }
301
302 #[test]
305 fn bytes_length_zero() {
306 let mut rng = default_rng_seeded(42);
307 assert!(rng.bytes(0).is_empty());
308 }
309
310 #[test]
311 fn bytes_length_full_word() {
312 let mut rng = default_rng_seeded(42);
313 let b = rng.bytes(8);
314 assert_eq!(b.len(), 8);
315 }
316
317 #[test]
318 fn bytes_length_partial_word() {
319 let mut rng = default_rng_seeded(42);
320 let b = rng.bytes(13);
321 assert_eq!(b.len(), 13);
322 }
323
324 #[test]
325 fn bytes_deterministic_for_same_seed() {
326 let mut rng1 = default_rng_seeded(42);
327 let mut rng2 = default_rng_seeded(42);
328 assert_eq!(rng1.bytes(64), rng2.bytes(64));
329 }
330}