2013-04-29 00:18:53 +10:00
|
|
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
//! Sampling from random distributions
|
|
|
|
|
|
|
|
// Some implementations use the Ziggurat method
|
|
|
|
// https://en.wikipedia.org/wiki/Ziggurat_algorithm
|
|
|
|
//
|
|
|
|
// The version used here is ZIGNOR [Doornik 2005, "An Improved
|
|
|
|
// Ziggurat Method to Generate Normal Random Samples"] which is slower
|
|
|
|
// (about double, it generates an extra random number) than the
|
|
|
|
// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for
|
|
|
|
// Generating Random Variables"], but more robust. If one wanted, one
|
|
|
|
// could implement VIZIGNOR the ZIGNOR paper for more speed.
|
|
|
|
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
use num;
|
2013-04-29 00:18:53 +10:00
|
|
|
use rand::{Rng,Rand};
|
|
|
|
|
|
|
|
mod ziggurat_tables;
|
|
|
|
|
|
|
|
// inlining should mean there is no performance penalty for this
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-05-02 23:09:50 -07:00
|
|
|
fn ziggurat<R:Rng>(rng: &mut R,
|
2013-04-29 00:18:53 +10:00
|
|
|
center_u: bool,
|
|
|
|
X: ziggurat_tables::ZigTable,
|
|
|
|
F: ziggurat_tables::ZigTable,
|
|
|
|
F_DIFF: ziggurat_tables::ZigTable,
|
|
|
|
pdf: &'static fn(f64) -> f64, // probability density function
|
2013-05-02 23:09:50 -07:00
|
|
|
zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
|
2013-04-29 00:18:53 +10:00
|
|
|
loop {
|
|
|
|
let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
|
|
|
|
let i: uint = rng.gen::<uint>() & 0xff;
|
|
|
|
let x = u * X[i];
|
|
|
|
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
let test_x = if center_u {num::abs(x)} else {x};
|
2013-04-29 00:18:53 +10:00
|
|
|
|
|
|
|
// algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
|
|
|
|
if test_x < X[i + 1] {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
if i == 0 {
|
|
|
|
return zero_case(rng, u);
|
|
|
|
}
|
|
|
|
// algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
|
|
|
|
if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a
|
|
|
|
/// standard normal, or Gaussian). Multiplying the generated values by the
|
|
|
|
/// desired standard deviation `sigma` then adding the desired mean `mu` will
|
|
|
|
/// give N(mu, sigma^2) distributed random numbers.
|
|
|
|
///
|
|
|
|
/// Note that this has to be unwrapped before use as an `f64` (using either
|
|
|
|
/// `*` or `cast::transmute` is safe).
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ~~~
|
2013-08-16 15:54:14 +10:00
|
|
|
/// use std::rand::distributions::StandardNormal;
|
2013-04-29 00:18:53 +10:00
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let normal = 2.0 + (*rand::random::<StandardNormal>()) * 3.0;
|
2013-07-22 19:03:39 +03:00
|
|
|
/// printfln!("%f is from a N(2, 9) distribution", normal)
|
2013-04-29 00:18:53 +10:00
|
|
|
/// }
|
|
|
|
/// ~~~
|
|
|
|
pub struct StandardNormal(f64);
|
|
|
|
|
|
|
|
impl Rand for StandardNormal {
|
2013-05-02 23:09:50 -07:00
|
|
|
fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-04-29 00:18:53 +10:00
|
|
|
fn pdf(x: f64) -> f64 {
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
((-x*x/2.0) as f64).exp()
|
2013-04-29 00:18:53 +10:00
|
|
|
}
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-05-02 23:09:50 -07:00
|
|
|
fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
|
2013-04-29 00:18:53 +10:00
|
|
|
// compute a random number in the tail by hand
|
|
|
|
|
|
|
|
// strange initial conditions, because the loop is not
|
|
|
|
// do-while, so the condition should be true on the first
|
|
|
|
// run, they get overwritten anyway (0 < 1, so these are
|
|
|
|
// good).
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
let mut x = 1.0f64;
|
|
|
|
let mut y = 0.0f64;
|
2013-04-29 00:18:53 +10:00
|
|
|
|
|
|
|
// XXX infinities?
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
while -2.0 * y < x * x {
|
|
|
|
x = rng.gen::<f64>().ln() / ziggurat_tables::ZIG_NORM_R;
|
|
|
|
y = rng.gen::<f64>().ln();
|
2013-04-29 00:18:53 +10:00
|
|
|
}
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
|
|
|
|
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
|
2013-04-29 00:18:53 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
StandardNormal(ziggurat(
|
|
|
|
rng,
|
|
|
|
true, // this is symmetric
|
|
|
|
&ziggurat_tables::ZIG_NORM_X,
|
|
|
|
&ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
|
|
|
|
pdf, zero_case))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by
|
|
|
|
/// the desired rate `lambda` will give Exp(lambda) distributed random
|
|
|
|
/// numbers.
|
|
|
|
///
|
|
|
|
/// Note that this has to be unwrapped before use as an `f64` (using either
|
|
|
|
/// `*` or `cast::transmute` is safe).
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ~~~
|
2013-08-16 15:54:14 +10:00
|
|
|
/// use std::rand::distributions::Exp1;
|
2013-04-29 00:18:53 +10:00
|
|
|
///
|
|
|
|
/// fn main() {
|
|
|
|
/// let exp2 = (*rand::random::<Exp1>()) * 0.5;
|
2013-07-22 19:03:39 +03:00
|
|
|
/// printfln!("%f is from a Exp(2) distribution", exp2);
|
2013-04-29 00:18:53 +10:00
|
|
|
/// }
|
|
|
|
/// ~~~
|
|
|
|
pub struct Exp1(f64);
|
|
|
|
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
|
2013-04-29 00:18:53 +10:00
|
|
|
impl Rand for Exp1 {
|
|
|
|
#[inline]
|
2013-05-02 23:09:50 -07:00
|
|
|
fn rand<R:Rng>(rng: &mut R) -> Exp1 {
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-04-29 00:18:53 +10:00
|
|
|
fn pdf(x: f64) -> f64 {
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
(-x).exp()
|
2013-04-29 00:18:53 +10:00
|
|
|
}
|
2013-06-18 14:45:18 -07:00
|
|
|
#[inline]
|
2013-05-02 23:09:50 -07:00
|
|
|
fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
|
Replaces the free-standing functions in f32, &c.
The free-standing functions in f32, f64, i8, i16, i32, i64, u8, u16,
u32, u64, float, int, and uint are replaced with generic functions in
num instead.
If you were previously using any of those functions, just replace them
with the corresponding function with the same name in num.
Note: If you were using a function that corresponds to an operator, use
the operator instead.
2013-07-08 18:05:17 +02:00
|
|
|
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
|
2013-04-29 00:18:53 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
Exp1(ziggurat(rng, false,
|
|
|
|
&ziggurat_tables::ZIG_EXP_X,
|
|
|
|
&ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
|
|
|
|
pdf, zero_case))
|
|
|
|
}
|
|
|
|
}
|