dvcompute 2.0.0

Discrete event simulation library (sequential simulation)
Documentation
// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::rc::Rc;
use std::cell::UnsafeCell;

use dvcompute_rand::simulation::generator::primitives::*;

/// The random number generator.
#[repr(C)]
pub struct Generator {

    /// The uniform random number generator.
    genu: UnsafeCell<GeneratorRepr>,

    /// The normal random number generator.
    genn: UnsafeCell<GeneratorRepr>,

    /// The unique sequence number.
    sequence_no: UnsafeCell<u64>
}

/// Specifies the generator type.
#[derive(Clone)]
pub enum GeneratorType {

    /// A simple random number generator.
    Simple,

    /// A simple random number generator with the specified seed.
    SimpleWithSeed([u8; 32])
}

impl Generator {

    /// Create a new generator.
    pub fn new(t: &GeneratorType) -> Generator {
        match t {
            &GeneratorType::Simple => {
                let gen1 = uniform_generator();
                let genu = UnsafeCell::new(gen1);
                let gen2 = uniform_generator();
                let genn = UnsafeCell::new(normal_generator(gen2));
                let sequence_no = UnsafeCell::new(0);
                Generator {
                    genu: genu,
                    genn: genn,
                    sequence_no: sequence_no
                }
            },
            &GeneratorType::SimpleWithSeed(seed) => {
                let gen0 = Rc::new(UnsafeCell::new(uniform_generator_with_seed(seed)));
                let genu = {
                    let gen0 = gen0.clone();
                    let gen2 = Box::new(move || {
                        let gen0 = gen0.get();
                        unsafe { (*gen0).call() }
                    });
                    let gen2 = GeneratorRepr::into_repr(gen2);
                    UnsafeCell::new(gen2)
                };
                let genn = {
                    let gen0 = gen0.clone();
                    let gen2 = Box::new(move || {
                        let gen0 = gen0.get();
                        unsafe { (*gen0).call() }
                    });
                    let gen2 = GeneratorRepr::into_repr(gen2);
                    UnsafeCell::new(normal_generator(gen2))
                };
                let sequence_no = UnsafeCell::new(0);
                Generator {
                    genu: genu,
                    genn: genn,
                    sequence_no: sequence_no
                }
            }
        }
    }

    /// Generate an uniform random number with the specified minimum and maximum.
    #[inline]
    pub fn random_uniform(&self, min: f64, max: f64) -> f64 {
        let gen = self.genu.get();
        unsafe {
            generate_uniform(&mut *gen, min, max)
        }
    }

    /// Generate an integer uniform random number with the specified minimum and maximum.
    #[inline]
    pub fn random_int_uniform(&self, min: isize, max: isize) -> isize {
        let gen = self.genu.get();
        unsafe {
            generate_int_uniform(&mut *gen, min, max)
        }
    }

    /// Generate the triangular random number by the specified minimum, median and maximum.
    #[inline]
    pub fn random_triangular(&self, min: f64, median: f64, max: f64) -> f64 {
        let gen = self.genu.get();
        unsafe {
            generate_triangular(&mut *gen, min, median, max)
        }
    }

    /// Generate a normal random number by the specified generator, mean and deviation.
    #[inline]
    pub fn random_normal(&self, mu: f64, nu: f64) -> f64 {
        let gen = self.genn.get();
        unsafe {
            generate_normal(&mut *gen, mu, nu)
        }
    }

    /// Generate the lognormal random number derived from a normal distribution with
    /// the specified generator, mean and deviation.
    #[inline]
    pub fn random_log_normal(&self, mu: f64, nu: f64) -> f64 {
        let gen = self.genn.get();
        unsafe {
            generate_log_normal(&mut *gen, mu, nu)
        }
    }

    /// Return the exponential random number with the specified mean.
    #[inline]
    pub fn random_exponential(&self, mu: f64) -> f64 {
        let gen = self.genu.get();
        unsafe {
            generate_exponential(&mut *gen, mu)
        }
    }

    /// Return the Erlang random number.
    #[inline]
    pub fn random_erlang(&self, scale: f64, shape: isize) -> f64 {
        let gen = self.genu.get();
        unsafe {
            generate_erlang(&mut *gen, scale, shape)
        }
    }

    /// Generate the Poisson random number with the specified mean.
    #[inline]
    pub fn random_poisson(&self, mu: f64) -> isize {
        let gen = self.genu.get();
        unsafe {
            generate_poisson(&mut *gen, mu)
        }
    }

    /// Generate a binomial random number with the specified probability and number of trials.
    #[inline]
    pub fn random_binomial(&self, prob: f64, trials: isize) -> isize {
        let gen = self.genu.get();
        unsafe {
            generate_binomial(&mut *gen, prob, trials)
        }
    }

    /// Generate a random number from the Gamma distribution using Marsaglia and Tsang method.
    #[inline]
    pub fn random_gamma(&self, kappa: f64, theta: f64) -> f64 {
        let genn = self.genn.get();
        let genu = self.genu.get();
        unsafe {
            generate_gamma(&mut *genn, &mut *genu, kappa, theta)
        }
    }

    /// Generate a random number from the Beta distribution.
    #[inline]
    pub fn random_beta(&self, alpha: f64, beta: f64) -> f64 {
        let genn = self.genn.get();
        let genu = self.genu.get();
        unsafe {
            generate_beta(&mut *genn, &mut *genu, alpha, beta)
        }
    }

    /// Generate a random number from the Weibull distribution.
    #[inline]
    pub fn random_weibull(&self, alpha: f64, beta: f64) -> f64 {
        let gen = self.genu.get();
        unsafe {
            generate_weibull(&mut *gen, alpha, beta)
        }
    }

    /// Generate a random value from the specified discrete distribution.
    #[inline]
    pub fn random_discrete<'a, T>(&self, dpdf: &'a [(T, f64)]) -> &'a T {
        let gen = self.genu.get();
        unsafe {
            generate_discrete(&mut *gen, dpdf)
        }
    }

    /// Generate a sequence number which can be considered quite unique.
    #[inline]
    pub fn random_sequence_no(&self) -> u64 {
        let gen = self.sequence_no.get();
        unsafe {
            *gen = (*gen).wrapping_add(1);
            *gen
        }
    }
}