use ffi;
use libc::{c_void, c_double, size_t};
use std::slice;
use std::mem::transmute;
use std::marker::PhantomData;
pub struct PlainMonteCarlo {
s: *mut ffi::gsl_monte_plain_state,
}
impl PlainMonteCarlo {
pub fn new(dim: usize) -> Option<PlainMonteCarlo> {
let tmp = unsafe { ffi::gsl_monte_plain_alloc(dim) };
if tmp.is_null() {
None
} else {
Some(PlainMonteCarlo { s: tmp })
}
}
pub fn init(&mut self) -> ::Value {
::Value::from(unsafe { ffi::gsl_monte_plain_init(self.s) })
}
pub fn integrate<F: FnMut(&[f64]) -> f64>(&mut self,
dim: usize,
f: F,
xl: &[f64],
xu: &[f64],
t_calls: usize,
r: &mut ::Rng)
-> Result<(f64, f64), ::Value> {
unsafe {
assert!(xl.len() == xu.len());
let mut result = 0f64;
let mut abserr = 0f64;
let f: Box<Box<FnMut(&[f64]) -> f64>> = Box::new(Box::new(f));
let mut func = ffi::gsl_monte_function {
f: transmute(monte_trampoline as usize),
dim: dim,
params: Box::into_raw(f) as *mut _,
};
let ret = ::Value::from(
ffi::gsl_monte_plain_integrate(&mut func as *mut _ as *mut c_void,
xl.as_ptr(),
xu.as_ptr(),
xl.len(),
t_calls,
ffi::FFI::unwrap_unique(r),
self.s,
(&mut result) as *mut c_double,
(&mut abserr) as *mut c_double));
if ret == ::Value::Success {
Ok((result, abserr))
} else {
Err(ret)
}
}
}
}
impl Drop for PlainMonteCarlo {
fn drop(&mut self) {
unsafe { ffi::gsl_monte_plain_free(self.s) };
self.s = ::std::ptr::null_mut();
}
}
impl ffi::FFI<ffi::gsl_monte_plain_state> for PlainMonteCarlo {
fn wrap(s: *mut ffi::gsl_monte_plain_state) -> PlainMonteCarlo {
PlainMonteCarlo { s: s }
}
fn soft_wrap(s: *mut ffi::gsl_monte_plain_state) -> PlainMonteCarlo {
Self::wrap(s)
}
fn unwrap_shared(s: &PlainMonteCarlo) -> *const ffi::gsl_monte_plain_state {
s.s as *const _
}
fn unwrap_unique(s: &mut PlainMonteCarlo) -> *mut ffi::gsl_monte_plain_state {
s.s
}
}
pub struct MiserMonteCarlo {
s: *mut ffi::gsl_monte_miser_state,
}
impl MiserMonteCarlo {
pub fn new(dim: usize) -> Option<MiserMonteCarlo> {
let tmp_pointer = unsafe { ffi::gsl_monte_miser_alloc(dim) };
if tmp_pointer.is_null() {
None
} else {
Some(MiserMonteCarlo { s: tmp_pointer })
}
}
pub fn init(&mut self) -> ::Value {
::Value::from(unsafe { ffi::gsl_monte_miser_init(self.s) })
}
pub fn integrate<F: FnMut(&[f64]) -> f64>(&mut self,
dim: usize,
f: F,
xl: &[f64],
xu: &[f64],
t_calls: usize,
r: &mut ::Rng)
-> Result<(f64, f64), ::Value> {
unsafe {
assert!(xl.len() == xu.len());
let mut result = 0f64;
let mut abserr = 0f64;
let f: Box<Box<FnMut(&[f64]) -> f64>> = Box::new(Box::new(f));
let mut func = ffi::gsl_monte_function {
f: transmute(monte_trampoline as usize),
dim: dim,
params: Box::into_raw(f) as *mut _,
};
let ret = ::Value::from(
ffi::gsl_monte_miser_integrate(&mut func as *mut _ as *mut c_void,
xl.as_ptr(),
xu.as_ptr(),
xl.len(),
t_calls,
ffi::FFI::unwrap_unique(r),
self.s,
(&mut result) as *mut c_double,
(&mut abserr) as *mut c_double));
if ret == ::Value::Success {
Ok((result, abserr))
} else {
Err(ret)
}
}
}
pub fn get_params(&self) -> MiserParams {
let mut m = MiserParams {
estimate_frac: 0f64,
min_calls: 0,
min_calls_per_bisection: 0,
alpha: 0f64,
dither: 0f64,
};
unsafe {
ffi::gsl_monte_miser_params_get(self.s, &mut m as *mut MiserParams);
}
m
}
pub fn set_params(&mut self, params: &MiserParams) {
unsafe {
ffi::gsl_monte_miser_params_set(self.s, params as *const MiserParams);
}
}
}
impl Drop for MiserMonteCarlo {
fn drop(&mut self) {
unsafe { ffi::gsl_monte_miser_free(self.s) };
self.s = ::std::ptr::null_mut();
}
}
impl ffi::FFI<ffi::gsl_monte_miser_state> for MiserMonteCarlo {
fn wrap(s: *mut ffi::gsl_monte_miser_state) -> MiserMonteCarlo {
MiserMonteCarlo { s: s }
}
fn soft_wrap(s: *mut ffi::gsl_monte_miser_state) -> MiserMonteCarlo {
Self::wrap(s)
}
fn unwrap_shared(s: &MiserMonteCarlo) -> *const ffi::gsl_monte_miser_state {
s.s as *const _
}
fn unwrap_unique(s: &mut MiserMonteCarlo) -> *mut ffi::gsl_monte_miser_state {
s.s
}
}
#[repr(C)]
pub struct MiserParams {
pub estimate_frac: f64,
pub min_calls: usize,
pub min_calls_per_bisection: usize,
pub alpha: f64,
pub dither: f64,
}
pub struct VegasMonteCarlo {
s: *mut ffi::gsl_monte_vegas_state,
}
impl VegasMonteCarlo {
pub fn new(dim: usize) -> Option<VegasMonteCarlo> {
let tmp_pointer = unsafe { ffi::gsl_monte_vegas_alloc(dim) };
if tmp_pointer.is_null() {
None
} else {
Some(VegasMonteCarlo { s: tmp_pointer })
}
}
pub fn init(&mut self) -> ::Value {
::Value::from(unsafe { ffi::gsl_monte_vegas_init(self.s) })
}
pub fn integrate<F: FnMut(&[f64]) -> f64>(&mut self,
dim: usize,
f: F,
xl: &[f64],
xu: &[f64],
t_calls: usize,
r: &mut ::Rng)
-> Result<(f64, f64), ::Value> {
unsafe {
assert!(xl.len() == xu.len());
let mut result = 0f64;
let mut abserr = 0f64;
let f: Box<Box<FnMut(&[f64]) -> f64>> = Box::new(Box::new(f));
let mut func = ffi::gsl_monte_function {
f: transmute(monte_trampoline as usize),
dim: dim,
params: Box::into_raw(f) as *mut _,
};
let ret = ::Value::from(
ffi::gsl_monte_vegas_integrate(&mut func as *mut _ as *mut c_void,
xl.as_ptr(),
xu.as_ptr(),
xl.len(),
t_calls,
ffi::FFI::unwrap_unique(r),
self.s,
(&mut result) as *mut c_double,
(&mut abserr) as *mut c_double));
if ret == ::Value::Success {
Ok((result, abserr))
} else {
Err(ret)
}
}
}
pub fn chisq(&mut self) -> f64 {
unsafe { ffi::gsl_monte_vegas_chisq(self.s) }
}
pub fn runval(&mut self, result: &mut f64, sigma: &mut f64) {
unsafe {
ffi::gsl_monte_vegas_runval(self.s, result as *mut c_double, sigma as *mut c_double)
}
}
pub fn get_params(&self) -> VegasParams {
let mut params = VegasParams::default();
unsafe {
ffi::gsl_monte_vegas_params_get(self.s, &mut params.inner as *mut _);
}
params
}
pub fn set_params(&mut self, params: &VegasParams) {
unsafe {
ffi::gsl_monte_vegas_params_set(self.s, ¶ms.inner as *const _);
}
}
}
pub struct VegasParams<'a> {
inner: ffi::gsl_monte_vegas_params,
lt: PhantomData<&'a ()>,
}
impl<'a> VegasParams<'a> {
pub fn new(alpha: f64,
iterations: usize,
stage: i32,
mode: ::VegasMode,
verbosity: VegasVerbosity,
stream: Option<&'a mut ::IOStream>)
-> Result<VegasParams, String> {
if !verbosity.is_off() && stream.is_none() {
return Err("rust-GSL: need to provide an input stream for Vegas Monte Carlo \
integration if verbosity is not 'Off'"
.to_string());
} else if verbosity.is_off() && stream.is_some() {
return Err("rust-GSL: need to provide the verbosity flag for Vegas Monta Carlo \
integration, currently set to 'Off'"
.to_string());
}
let stream = if let Some(stream) = stream {
if !stream.write_mode() {
return Err("rust-GSL: input stream not flagged as 'write' mode".to_string());
}
stream.as_raw()
} else {
::std::ptr::null_mut()
};
Ok(VegasParams {
inner: ffi::gsl_monte_vegas_params {
alpha: alpha,
iterations: iterations,
stage: stage,
mode: mode.into(),
verbose: verbosity.to_int(),
ostream: stream,
},
lt: PhantomData,
})
}
}
impl<'a> ::std::default::Default for VegasParams<'a> {
fn default() -> VegasParams<'a> {
VegasParams {
inner: ffi::gsl_monte_vegas_params {
alpha: 1.5,
iterations: 5,
stage: 0,
mode: ::VegasMode::ImportanceOnly.into(),
verbose: -1,
ostream: ::std::ptr::null_mut(),
},
lt: PhantomData,
}
}
}
#[derive(Clone, Copy)]
pub enum VegasVerbosity {
Off, Summary, Grid, Rebinning, }
impl VegasVerbosity {
fn to_int(&self) -> i32 {
match *self {
VegasVerbosity::Off => -1,
VegasVerbosity::Summary => 0,
VegasVerbosity::Grid => 1,
VegasVerbosity::Rebinning => 2,
}
}
fn is_off(&self) -> bool {
match *self {
VegasVerbosity::Off => true,
_ => false,
}
}
}
impl Drop for VegasMonteCarlo {
fn drop(&mut self) {
unsafe { ffi::gsl_monte_vegas_free(self.s) };
self.s = ::std::ptr::null_mut();
}
}
impl ffi::FFI<ffi::gsl_monte_vegas_state> for VegasMonteCarlo {
fn wrap(s: *mut ffi::gsl_monte_vegas_state) -> VegasMonteCarlo {
VegasMonteCarlo { s: s }
}
fn soft_wrap(s: *mut ffi::gsl_monte_vegas_state) -> VegasMonteCarlo {
Self::wrap(s)
}
fn unwrap_shared(s: &VegasMonteCarlo) -> *const ffi::gsl_monte_vegas_state {
s.s as *const _
}
fn unwrap_unique(s: &mut VegasMonteCarlo) -> *mut ffi::gsl_monte_vegas_state {
s.s
}
}
unsafe extern "C" fn monte_trampoline(x: *mut c_double,
dim: size_t,
param: *mut c_void)
-> c_double {
let f: &mut Box<FnMut(&[f64]) -> f64> = transmute(param);
f(slice::from_raw_parts(x, dim as usize))
}
#[test]
fn plain() {
use std::f64::consts::PI;
fn g(k: &[f64]) -> f64 {
let a = 1f64 / (PI * PI * PI);
a / (1.0 - k[0].cos() * k[1].cos() * k[2].cos())
}
let xl: [f64; 3] = [0f64; 3];
let xu: [f64; 3] = [PI, PI, PI];
let calls = 500000;
::RngType::env_setup();
let t: ::RngType = ::rng::default();
let mut r = ::Rng::new(&t).unwrap();
{
let mut s = PlainMonteCarlo::new(3).unwrap();
let (res, err) = s.integrate(3, g, &xl, &xu, calls, &mut r).unwrap();
assert_eq!(&format!("{:.6}", res), "1.412209");
assert_eq!(&format!("{:.6}", err), "0.013436");
}
}
#[test]
fn miser() {
use std::f64::consts::PI;
fn g(k: &[f64]) -> f64 {
let a = 1f64 / (PI * PI * PI);
a / (1.0 - k[0].cos() * k[1].cos() * k[2].cos())
}
let xl: [f64; 3] = [0f64; 3];
let xu: [f64; 3] = [PI, PI, PI];
let calls = 500000;
::RngType::env_setup();
let t: ::RngType = ::rng::default();
let mut r = ::Rng::new(&t).unwrap();
{
let mut s = MiserMonteCarlo::new(3).unwrap();
let (res, err) = s.integrate(3, g, &xl, &xu, calls, &mut r).unwrap();
assert_eq!(&format!("{:.6}", res), "1.389530");
assert_eq!(&format!("{:.6}", err), "0.005011");
}
}
#[test]
fn miser_closure() {
use std::f64::consts::PI;
let xl: [f64; 3] = [0f64; 3];
let xu: [f64; 3] = [PI, PI, PI];
let calls = 500000;
::RngType::env_setup();
let t: ::RngType = ::rng::default();
let mut r = ::Rng::new(&t).unwrap();
{
let mut s = MiserMonteCarlo::new(3).unwrap();
let (res, err) = s.integrate(3,
|k| {
let a = 1f64 / (PI * PI * PI);
a / (1.0 - k[0].cos() * k[1].cos() * k[2].cos())
},
&xl,
&xu,
calls,
&mut r)
.unwrap();
assert_eq!(&format!("{:.6}", res), "1.389530");
assert_eq!(&format!("{:.6}", err), "0.005011");
}
}
#[test]
fn vegas_warm_up() {
use std::f64::consts::PI;
fn g(k: &[f64]) -> f64 {
let a = 1f64 / (PI * PI * PI);
a / (1.0 - k[0].cos() * k[1].cos() * k[2].cos())
}
let xl: [f64; 3] = [0f64; 3];
let xu: [f64; 3] = [PI, PI, PI];
::RngType::env_setup();
let t: ::RngType = ::rng::default();
let mut r = ::Rng::new(&t).unwrap();
{
let mut s = VegasMonteCarlo::new(3).unwrap();
let (res, err) = s.integrate(3, g, &xl, &xu, 10000, &mut r).unwrap();
assert_eq!(&format!("{:.6}", res), "1.385603");
assert_eq!(&format!("{:.6}", err), "0.002212");
}
}
#[test]
fn vegas() {
use std::f64::consts::PI;
fn g(k: &[f64]) -> f64 {
let a = 1f64 / (PI * PI * PI);
a / (1.0 - k[0].cos() * k[1].cos() * k[2].cos())
}
let calls = 500000;
let xl: [f64; 3] = [0f64; 3];
let xu: [f64; 3] = [PI, PI, PI];
::RngType::env_setup();
let t: ::RngType = ::rng::default();
let mut r = ::Rng::new(&t).unwrap();
{
let mut s = VegasMonteCarlo::new(3).unwrap();
s.integrate(3, g, &xl, &xu, 10000, &mut r).unwrap();
let mut res;
let mut err;
loop {
let (_res, _err) = s.integrate(3, g, &xl, &xu, calls / 5, &mut r).unwrap();
res = _res;
err = _err;
println!("result = {:.6} sigma = {:.6} chisq/dof = {:.1}",
res,
err,
s.chisq());
if (s.chisq() - 1f64).abs() <= 0.5f64 {
break;
}
}
assert_eq!(&format!("{:.6}", res), "1.393307");
assert_eq!(&format!("{:.6}", err), "0.000335");
}
}