use std::{mem, ptr};
use std::os::raw::{c_int, c_longlong};
use ::bindings;
use ::ffi::LandingPad;
use ::traits::{IntegrandInput, IntegrandOutput};
use ::{Integrator, Real};
use super::{cuba_integrand, CubaError, CubaIntegrationResult, CubaIntegrationResults,
RandomNumberSource};
#[derive(Copy, Clone, Debug)]
pub struct Suave {
mineval: usize,
maxeval: usize,
seed: usize,
nnew: usize,
nmin: usize,
flatness: Real,
flags: c_int,
}
impl Default for Suave {
fn default() -> Self {
Suave {
mineval: 1,
maxeval: c_longlong::max_value() as usize,
seed: 0,
nnew: 1000,
nmin: 5,
flatness: 25 as Real,
flags: 0,
}
}
}
impl Suave {
pub fn new() -> Self {
Self::default()
}
pub fn with_mineval(self, maxeval: usize) -> Self {
Suave {
maxeval, ..self
}
}
pub fn with_maxeval(self, maxeval: usize) -> Self {
Suave {
maxeval, ..self
}
}
pub fn with_seed(self, seed: usize) -> Self {
Suave {
seed, ..self
}
}
pub fn with_nnew(self, nnew: usize) -> Self {
Suave {
nnew, ..self
}
}
pub fn with_nmin(self, nmin: usize) -> Self {
Suave {
nmin, ..self
}
}
pub fn with_flatness(self, flatness: Real) -> Self {
Suave {
flatness, ..self
}
}
pub fn with_rng(self, rng: RandomNumberSource) -> Self {
Suave {
flags: (self.flags & !0x8) & match rng {
RandomNumberSource::Sobol => 0,
RandomNumberSource::MersenneTwister => 8,
}, ..self
}
}
}
impl Integrator for Suave {
type Success = CubaIntegrationResults;
type Failure = super::CubaError;
fn integrate<A, B, F: FnMut(A) -> B>(&mut self, mut fun: F, epsrel: Real, epsabs: Real) -> Result<Self::Success, Self::Failure>
where A: IntegrandInput,
B: IntegrandOutput
{
unsafe { bindings::cubacores(0, 0) };
let (ndim, ncomp) = {
let inputs = A::input_size();
let outputs = fun(A::from_args(&vec![0.5; inputs][..])).output_size();
(inputs, outputs)
};
let mut nregions = 0;
let mut neval = 0;
let mut fail = 0;
let (mut value, mut error, mut prob) =
(vec![0.0; ncomp], vec![0.0; ncomp], vec![0.0; ncomp]);
let mut lp = LandingPad::new(fun);
unsafe {
bindings::llSuave(ndim as c_int, ncomp as c_int,
Some(cuba_integrand::<A, B, F>), mem::transmute(&mut lp),
1 ,
epsrel,
epsabs,
self.flags,
self.seed as c_int,
self.mineval as c_longlong,
self.maxeval as c_longlong,
self.nnew as c_longlong,
self.nmin as c_longlong,
self.flatness,
ptr::null(),
ptr::null_mut(),
&mut nregions,
&mut neval,
&mut fail,
value.as_mut_ptr(),
error.as_mut_ptr(),
prob.as_mut_ptr());
}
lp.maybe_resume_unwind();
if fail == 0 {
Ok(CubaIntegrationResults {
nregions: Some(nregions), neval,
results: value.iter().zip(error.iter()).zip(prob.iter())
.map(|((&value, &error), &prob)|
CubaIntegrationResult {
value, error, prob
})
.collect()
})
} else if fail == -1 {
Err(CubaError::BadDim("suave", ndim))
} else if fail == -2 {
Err(CubaError::BadComp("suave", ncomp))
} else if fail == 1 {
Err(CubaError::DidNotConverge(CubaIntegrationResults {
nregions: None, neval,
results: value.iter().zip(error.iter()).zip(prob.iter())
.map(|((&value, &error), &prob)|
CubaIntegrationResult {
value, error, prob
})
.collect()
}))
} else {
unreachable!("Suave returned invalid failure code: {}", fail)
}
}
}