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 const fn new(bg: B) -> Self {
34 Self { bg, seed: 0 }
35 }
36
37 pub(crate) const fn new_with_seed(bg: B, seed: u64) -> Self {
39 Self { bg, seed }
40 }
41
42 #[inline]
44 pub const 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
93#[must_use]
104pub fn default_rng() -> Generator<Xoshiro256StarStar> {
105 let seed = {
108 let mut buf = [0u8; 8];
109 if getrandom::fill(&mut buf).is_ok() {
110 u64::from_ne_bytes(buf)
111 } else {
112 use std::time::SystemTime;
114 let dur = SystemTime::now()
115 .duration_since(SystemTime::UNIX_EPOCH)
116 .unwrap_or_default();
117 let nanos = dur.as_nanos();
118 let mut s = nanos as u64;
119 s ^= (nanos >> 64) as u64;
120 let stack_var: u8 = 0;
121 s ^= &raw const stack_var as u64;
122 s
123 }
124 };
125 default_rng_seeded(seed)
126}
127
128#[must_use]
138pub fn default_rng_seeded(seed: u64) -> Generator<Xoshiro256StarStar> {
139 let bg = Xoshiro256StarStar::seed_from_u64(seed);
140 Generator::new_with_seed(bg, seed)
141}
142
143pub fn spawn_generators<B: BitGenerator + Clone>(
152 parent: &mut Generator<B>,
153 n: usize,
154) -> Result<Vec<Generator<B>>, FerrayError> {
155 if n == 0 {
156 return Err(FerrayError::invalid_value("spawn count must be > 0"));
157 }
158
159 let mut children = Vec::with_capacity(n);
160
161 let mut test_bg = parent.bg.clone();
163 if test_bg.jump().is_some() {
164 let mut current = parent.bg.clone();
166 for _ in 0..n {
167 children.push(Generator::new(current.clone()));
168 current.jump();
169 }
170 parent.bg = current;
172 return Ok(children);
173 }
174
175 if let Some(first) = B::stream(parent.seed, 0) {
177 drop(first);
178 for i in 0..n {
179 if let Some(bg) = B::stream(parent.seed, i as u64) {
180 children.push(Generator::new(bg));
181 }
182 }
183 if children.len() == n {
184 return Ok(children);
185 }
186 children.clear();
187 }
188
189 for _ in 0..n {
191 let child_seed = parent.bg.next_u64();
192 let bg = B::seed_from_u64(child_seed);
193 children.push(Generator::new(bg));
194 }
195 Ok(children)
196}
197
198pub(crate) fn generate_vec<B: BitGenerator>(
200 rng: &mut Generator<B>,
201 size: usize,
202 mut f: impl FnMut(&mut B) -> f64,
203) -> Vec<f64> {
204 let mut data = Vec::with_capacity(size);
205 for _ in 0..size {
206 data.push(f(&mut rng.bg));
207 }
208 data
209}
210
211pub(crate) fn generate_vec_f32<B: BitGenerator>(
213 rng: &mut Generator<B>,
214 size: usize,
215 mut f: impl FnMut(&mut B) -> f32,
216) -> Vec<f32> {
217 let mut data = Vec::with_capacity(size);
218 for _ in 0..size {
219 data.push(f(&mut rng.bg));
220 }
221 data
222}
223
224pub(crate) fn generate_vec_i64<B: BitGenerator>(
226 rng: &mut Generator<B>,
227 size: usize,
228 mut f: impl FnMut(&mut B) -> i64,
229) -> Vec<i64> {
230 let mut data = Vec::with_capacity(size);
231 for _ in 0..size {
232 data.push(f(&mut rng.bg));
233 }
234 data
235}
236
237#[inline]
239pub(crate) fn shape_size(shape: &[usize]) -> usize {
240 if shape.is_empty() {
241 0
242 } else {
243 shape.iter().product()
244 }
245}
246
247pub(crate) fn vec_to_array_f64(
249 data: Vec<f64>,
250 shape: &[usize],
251) -> Result<Array<f64, IxDyn>, FerrayError> {
252 Array::<f64, IxDyn>::from_vec(IxDyn::new(shape), data)
253}
254
255pub(crate) fn vec_to_array_f32(
257 data: Vec<f32>,
258 shape: &[usize],
259) -> Result<Array<f32, IxDyn>, FerrayError> {
260 Array::<f32, IxDyn>::from_vec(IxDyn::new(shape), data)
261}
262
263pub(crate) fn vec_to_array_i64(
265 data: Vec<i64>,
266 shape: &[usize],
267) -> Result<Array<i64, IxDyn>, FerrayError> {
268 Array::<i64, IxDyn>::from_vec(IxDyn::new(shape), data)
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn default_rng_seeded_deterministic() {
277 let mut rng1 = default_rng_seeded(42);
278 let mut rng2 = default_rng_seeded(42);
279 for _ in 0..100 {
280 assert_eq!(rng1.next_u64(), rng2.next_u64());
281 }
282 }
283
284 #[test]
285 fn default_rng_works() {
286 let mut rng = default_rng();
287 let v = rng.next_f64();
288 assert!((0.0..1.0).contains(&v));
289 }
290
291 #[test]
292 fn spawn_xoshiro() {
293 let mut parent = default_rng_seeded(42);
294 let children = spawn_generators(&mut parent, 4).unwrap();
295 assert_eq!(children.len(), 4);
296 }
297
298 #[test]
299 fn spawn_zero_is_error() {
300 let mut parent = default_rng_seeded(42);
301 assert!(spawn_generators(&mut parent, 0).is_err());
302 }
303
304 #[test]
307 fn bytes_length_zero() {
308 let mut rng = default_rng_seeded(42);
309 assert!(rng.bytes(0).is_empty());
310 }
311
312 #[test]
313 fn bytes_length_full_word() {
314 let mut rng = default_rng_seeded(42);
315 let b = rng.bytes(8);
316 assert_eq!(b.len(), 8);
317 }
318
319 #[test]
320 fn bytes_length_partial_word() {
321 let mut rng = default_rng_seeded(42);
322 let b = rng.bytes(13);
323 assert_eq!(b.len(), 13);
324 }
325
326 #[test]
327 fn bytes_deterministic_for_same_seed() {
328 let mut rng1 = default_rng_seeded(42);
329 let mut rng2 = default_rng_seeded(42);
330 assert_eq!(rng1.bytes(64), rng2.bytes(64));
331 }
332}