pub mod params;
mod type_support;
pub use self::type_support::*;
use std::iter::Iterator;
use std::ops::{AddAssign, BitAnd, BitXor, BitXorAssign, Mul, Shl, Shr, Sub};
use std::str::FromStr;
use std::fmt::Display;
extern crate num_traits;
use num_traits::{Bounded, One, Zero, Unsigned, PrimInt};
#[derive(Clone)]
pub struct Sobol<T: SobolType> {
pub dims: usize,
pub resolution: usize,
dir_vals: Vec<Vec<T::IT>>,
previous: Option<Vec<T::IT>>,
pub count: T::IT,
pub max_len: T::IT
}
impl<T: SobolType> Sobol<T> {
pub fn new<P>(dims: usize, params: &dyn SobolParams<P>) -> Self
where T::IT: LossyFrom<P> {
Self::new_with_resolution::<P>(dims, params, None)
}
pub fn new_with_resolution<P>(dims: usize, params: &dyn SobolParams<P>, resolution: Option<usize>) -> Self
where T::IT: LossyFrom<P> {
let res = resolution
.filter(|res| *res <= T::MAX_RESOLUTION)
.unwrap_or(T::MAX_RESOLUTION);
assert!(dims <= params.max_dims(), "Parameters for this Sobol sequence support values with a maximum of \
{} dimensions but was configured for {}.", params.max_dims(), dims);
Sobol {
dims,
resolution: res,
dir_vals: Self::init_direction_vals::<P>(dims, res, params),
count: T::IT::zero(),
max_len: T::IT::max_value() >> (T::IT::BITS - res),
previous: None
} as Sobol<T>
}
pub fn init_direction_vals<P>(dims: usize, resolution: usize, params: &dyn SobolParams<P>) -> Vec<Vec<T::IT>>
where T::IT: LossyFrom<P> {
let bits = T::IT::BITS;
(1 ..= dims).map(|dim| match dim {
1 => (1 ..= resolution).map(|i| T::IT::one() << (bits - i)).collect(),
_ => {
let p = params.get_dim(dim);
let s = if resolution >= p.s() { p.s() } else { resolution };
let mut dirs: Vec<T::IT> = vec![T::IT::zero(); resolution];
for i in 1 ..= s {
let m = T::IT::lossy_from(p.m(i - 1));
dirs[i - 1] = m << (bits - i);
}
for i in s + 1 ..= resolution {
dirs[i - 1] = dirs[i - s - 1] ^ (dirs[i - s - 1] >> s);
for k in 1 .. s {
let a = T::IT::lossy_from(p.coefficient(s - k - 1));
let dir = dirs[i - k - 1];
dirs[i - 1] ^= a * dir;
}
}
dirs
}
}).collect()
}
#[inline] pub fn rightmost_zero(n: T::IT) -> usize {
(n ^ T::IT::max_value()).trailing_zeros() as usize
}
}
impl<T: SobolType> Iterator for Sobol<T> {
type Item = Vec<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.count < self.max_len {
let next = match &self.previous {
None => vec![T::IT::zero(); self.dims],
Some(previous) => {
let a = self.count - T::IT::one();
let c = Self::rightmost_zero(a);
self.dir_vals.iter()
.enumerate()
.map(|(dim, dirs)| previous[dim] ^ dirs[c as usize])
.collect::<Vec<T::IT>>()
}
};
let next_render: Vec<T> = next.iter()
.map(|v| T::render(*v))
.collect();
self.count += T::IT::one();
self.previous = Some(next);
Some(next_render)
} else { None }
}
}
pub trait SobolType: Sized + Display {
type IT: InternalType;
fn render(val: Self::IT) -> Self;
const MAX_RESOLUTION: usize = Self::IT::BITS;
}
pub trait InternalType:
PrimInt +
Unsigned +
One +
Zero +
AddAssign +
BitXorAssign +
Sub<Output = Self> +
Mul<Output = Self> +
Shl<usize, Output = Self> +
Shr<usize, Output = Self> +
BitAnd<Output = Self> +
BitXor<Output = Self> +
Copy +
PartialEq +
PartialOrd +
FromStr +
Display {
const BITS: usize;
}
pub trait SobolParams<P> {
fn get_dim(&self, dim: usize) -> &dyn ParamDimension<P>;
fn max_dims(&self) -> usize;
}
pub trait ParamDimension<P> {
fn d(&self) -> u16;
fn s(&self) -> usize;
fn coefficient(&self, i: usize) -> P;
fn m(&self, i: usize) -> P;
}
pub trait LossyFrom<T>: Sized {
fn lossy_from(_: T) -> Self;
}