rust_monster/ga/
ga_random.rs

1// Copyright 2016 Revolution Solid & Contributors.
2// author(s): sysnett
3// rust-monster is licensed under an MIT License.
4
5//! GA Random Numbers Util
6//!
7//! Wrapper around the rand crate that provides a Seeded
8//! and Stateful Random Number Generator.
9//!
10//! Internally uses rand::XorShiftRng for speed purposes.
11//!
12//! # Examples
13//!
14//! GARandomCtx - Basic Use case
15//! 
16//! ```rust
17//! extern crate rust_monster;
18//! use rust_monster::ga; 
19//! use rust_monster::ga::ga_random; 
20//! 
21//! fn main ()
22//! {
23//!     let seed : ga_random::GASeed = [1,2,3,4];
24//!
25//!     let mut ga_ctx = ga_random::GARandomCtx::from_seed(seed, String::from("MyRandomCtx")); 
26//!
27//!     println!("{:?}", ga_ctx.gen::<f32>());
28//!
29//!     println!("{:?}", ga_ctx);
30//! }
31//! ```
32//!
33use rand::{Rng, Rand, SeedableRng, XorShiftRng};
34use rand::distributions::range::SampleRange;
35
36use std::fmt;
37
38pub type GASeed = [u32; 4];
39pub struct GARandomCtx
40{
41    seed: GASeed,
42    rng:  XorShiftRng,
43    name: String,
44    seeded: bool,
45    values_generated: u32
46}
47
48impl GARandomCtx
49{
50// Constructors 
51    pub fn new_unseeded(name: String) -> GARandomCtx
52    {
53        let std_rng = XorShiftRng::new_unseeded();
54        GARandomCtx
55        {
56            seed: [0; 4],
57            rng: std_rng,
58            name: name,
59            seeded: false,
60            values_generated: 0
61        }
62    }
63
64    pub fn from_seed(seed: GASeed, name: String) -> GARandomCtx
65    {
66        let std_rng = SeedableRng::from_seed(seed); 
67        GARandomCtx
68        {
69            seed: seed,
70            rng:  std_rng,
71            name: name,
72            seeded: true,
73            values_generated: 0
74        }
75    }
76
77// Random Values - Subset of the RNG Trait
78    pub fn gen<T: Rand>(&mut self) -> T where Self: Sized
79    {
80        self.values_generated += 1;
81        self.rng.gen()
82    }
83
84    pub fn gen_range<T: PartialOrd + SampleRange>(&mut self, low: T, high: T) -> T
85    {
86        self.values_generated += 1;
87        self.rng.gen_range(low, high)
88    }
89
90    pub fn next_u32(&mut self) -> u32 { self.gen::<u32>() }
91    pub fn next_u64(&mut self) -> u64 { self.gen::<u64>() }
92    pub fn next_f32(&mut self) -> f32 { self.gen::<f32>() }
93    pub fn next_f64(&mut self) -> f64 { self.gen::<f64>() }
94
95// Random Values - GARandomCtx functions
96    pub fn test_value<T: PartialOrd + Rand>(&mut self, value: T) -> bool 
97    {
98        self.gen::<T>() < value
99    }
100
101
102// Reset State
103    pub fn reseed(&mut self, seed: GASeed)
104    {
105        self.seed = seed;
106        self.seeded = true;
107        self.reset();
108    }
109
110    pub fn reset(&mut self)
111    {
112        self.values_generated = 0;
113        if self.seeded
114        {
115            self.rng.reseed(self.seed);
116        }
117        else
118        {
119            self.rng = XorShiftRng::new_unseeded(); 
120        }
121    }
122}
123
124impl fmt::Debug for GARandomCtx
125{
126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
127    {
128        let seeded_str = if self.seeded
129            {
130                "Seeded"
131            }
132            else
133            {
134                "Not Seeded"
135            };
136
137        write!(f, "GARandomCtx {} - {} {{ seed: {:?}, values_generated: {:?} }}",
138               self.name,
139               seeded_str,
140               self.seed,
141               self.values_generated)
142    }
143}
144
145#[cfg(test)]
146mod test
147{
148    extern crate env_logger;
149    use super::{GASeed, GARandomCtx};
150
151    #[test]
152    fn same_seed()
153    {
154        let _ = env_logger::init();
155        let seed : GASeed = [1,2,3,4];
156        let mut ga_ctx = GARandomCtx::from_seed(seed, String::from("TestRandomCtx")); 
157        let mut ga_ctx_2 = GARandomCtx::from_seed(seed, String::from("TestRandomCtx2")); 
158        debug!("{:?}", ga_ctx);
159        debug!("{:?}", ga_ctx_2);
160
161        for _ in 0..100
162        {
163            assert_eq!(ga_ctx.gen::<f64>(), ga_ctx_2.gen::<f64>());
164        }
165        debug!("{:?}", ga_ctx);
166        debug!("{:?}", ga_ctx_2);
167
168        for _ in 0..100
169        {
170            assert_eq!(ga_ctx.gen::<u32>(), ga_ctx_2.gen::<u32>());
171        }
172        debug!("{:?}", ga_ctx);
173        debug!("{:?}", ga_ctx_2);
174    }
175
176    #[test]
177    fn diff_seed()
178    {
179        let _ = env_logger::init();
180        let seed_1 : GASeed = [1,2,3,4];
181        let seed_2 : GASeed = [4,3,2,1];
182        let mut ga_ctx = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx")); 
183        let mut ga_ctx_2 = GARandomCtx::from_seed(seed_2, String::from("TestRandomCtx2")); 
184        debug!("{:?}", ga_ctx);
185        debug!("{:?}", ga_ctx_2);
186
187        for _ in 0..100
188        {
189            assert!(ga_ctx.gen::<f32>() != ga_ctx_2.gen::<f32>());
190        }
191        debug!("{:?}", ga_ctx);
192        debug!("{:?}", ga_ctx_2);
193
194        for _ in 0..100
195        {
196            assert!(ga_ctx.gen::<u64>() != ga_ctx_2.gen::<u64>());
197        }
198        debug!("{:?}", ga_ctx);
199        debug!("{:?}", ga_ctx_2);
200    }
201
202    #[test]
203    fn same_seed_different_types()
204    {
205        let _ = env_logger::init();
206        let seed_1 = [1; 4];
207        let mut ga_ctx = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx")); 
208        let mut ga_ctx_2 = GARandomCtx::from_seed(seed_1, String::from("TestRandomCtx")); 
209        debug!("{:?}", ga_ctx.gen::<f32>()); 
210        debug!("{:?}", ga_ctx_2.gen::<i8>()); 
211        assert_eq!(ga_ctx.gen::<f32>(), ga_ctx_2.gen::<f32>());
212    }
213}