1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! The random module provides methods of randomizing tensors.
//!
//! Here is an example:
//!
//! ```
//! use numeric::Tensor;
//! use numeric::random::RandomState;
//!
//! // Create a random state with seed 1234 (it has to be mutable)
//! let mut rs = RandomState::new(1234);
//!
//! let t = rs.uniform(0.0, 1.0, &[3, 3]);
//! println!("{}", t);
//! //  0.820987  0.93044 0.507159
//! //  0.603939  0.31157 0.383515
//! //  0.702227 0.346673 0.737954
//! // [Tensor<f64> of shape 3x3]
//! ```
use rand::{Rng, SeedableRng, StdRng};
use rand::distributions::range::SampleRange;
use num::traits::Float;
use std::f64;

use tensor::Tensor;
use traits::NumericTrait;
use math;

pub struct RandomState {
    rng: StdRng,
}

impl RandomState {
    /// Creates a new `RandomState` object with the given seed. The object needs to be captured
    /// as mutable in order to draw samples from it (since its internal state changes).
    pub fn new(seed: usize) -> RandomState {
        let ss: &[_] = &[seed];
        RandomState{rng: SeedableRng::from_seed(ss)}
    }

    /// Generates a tensor by independently drawing samples from a uniform distribution in the 
    /// range [`low`, `high`). This is appropriate for integer types as well.
    pub fn uniform<T>(&mut self, low: T, high: T, shape: &[usize]) -> Tensor<T>
            where T: NumericTrait + SampleRange {
        let mut t = Tensor::zeros(shape);
        {
            let n = t.size();
            let mut data = t.slice_mut();
            for i in 0..n {
                data[i] = self.rng.gen_range::<T>(low, high);
            }
        }
        t
    }

    /// Generates a tensor by independently drawing samples from a standard normal.
    pub fn normal<T>(&mut self, shape: &[usize]) -> Tensor<T>
            where T: NumericTrait + SampleRange + Float {
        let u1 = self.uniform(T::zero(), T::one(), shape);
        let u2 = self.uniform(T::zero(), T::one(), shape);

        let minustwo = Tensor::fscalar(-2.0);
        let twopi = Tensor::fscalar(2.0 * f64::consts::PI);

        math::sqrt(math::ln(u1) * &minustwo) * &math::cos(u2 * &twopi)
    }
}