use super::*;
use std::iter::FromIterator;
use std::cmp::Ordering;
#[derive(Serialize, Deserialize, Debug)]
pub struct Distribution1D {
func: Vec<Float>,
cdf: Vec<Float>,
func_integral: Float,
}
impl Distribution1D {
pub fn new<I>(func: I) -> Distribution1D
where I: IntoIterator<Item=Float>,
{
let func: Vec<_> = func.into_iter().collect();
let mut cdf = Vec::with_capacity(func.len() + 1);
cdf.push(0. as Float);
for i in 0..func.len() {
let lastcdf = unsafe {
*cdf.get_unchecked(i)
};
let curfunc = unsafe {
*func.get_unchecked(i)
};
assert!(curfunc>=0. as Float);
cdf.push(lastcdf + curfunc);
}
let func_integral = unsafe {
*cdf.get_unchecked(func.len())
};
if func_integral == 0. as Float {
for i in 1..cdf.len() {
unsafe {
*cdf.get_unchecked_mut(i) = i as Float / cdf.len() as Float;
}
}
} else {
for i in 1..cdf.len() {
unsafe {
*cdf.get_unchecked_mut(i) /= func_integral;
}
}
}
Distribution1D{
func: func,
cdf: cdf,
func_integral: func_integral,
}
}
#[inline]
pub fn len(&self) -> usize {
self.func.len()
}
#[inline]
pub fn sample_continuous(&self, u: Float) -> (Float, Float, usize) {
let offset = self.search_offset(u);
debug_assert!(offset < self.func.len());
let floor = unsafe {
*self.cdf.get_unchecked(offset)
};
let ceil = unsafe {
*self.cdf.get_unchecked(offset + 1)
};
let mut du = u - floor;
if ceil - floor > 0. as Float {
du /= ceil - floor;
}
let pdf = if self.func_integral > 0. as Float {unsafe {
*self.func.get_unchecked(offset) / self.func_integral
}} else {
0. as Float
};
let value = (offset as Float + du)/self.len() as Float;
(value, pdf, offset)
}
#[inline]
pub fn sample_discrete(&self, u: Float) -> (usize, Float, Float) {
let offset = self.search_offset(u);
debug_assert!(offset < self.func.len());
let floor = unsafe {
*self.cdf.get_unchecked(offset)
};
let ceil = unsafe {
*self.cdf.get_unchecked(offset + 1)
};
let mut du = u - floor;
if ceil - floor > 0. as Float {
du /= ceil - floor;
}
let pdf = if self.func_integral > 0. as Float {unsafe {
*self.func.get_unchecked(offset) / self.func_integral
}} else {
0. as Float
};
(offset, pdf, du)
}
#[inline]
pub fn discrete_pdf(&self, index: usize) -> Float {
self.func[index] / (self.func_integral * self.len() as Float)
}
#[inline]
fn search_offset(&self, mut u: Float) -> usize {
if u == 0. as Float { u += float::epsilon(); }
self.cdf.binary_search_by(|v| {
if *v < u { Ordering::Less }
else if *v == u { Ordering::Equal }
else { Ordering::Greater }
}).unwrap_or_else(|v| v) - 1
}
}
impl FromIterator<Float> for Distribution1D {
#[inline]
fn from_iter<T>(iter: T) -> Self
where T: IntoIterator<Item = Float>,
{
Distribution1D::new(iter)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Distribution2D {
pcv: Vec<Distribution1D>,
pmarginal: Distribution1D,
}
impl Distribution2D {
pub fn new(floats: &[Float], nu: usize) -> Distribution2D {
let n = floats.len();
assert!(nu < n);
let nv = n / nu;
let mut pcv = Vec::with_capacity(nv);
let mut marginal_func = Vec::with_capacity(nv);
for v in 0..nv {
pcv.push(Distribution1D::new(floats[v*nu..(v+1)*nu].to_vec()));
marginal_func.push(pcv.last().unwrap().func_integral);
}
let pmarginal = Distribution1D::new(marginal_func);
Distribution2D{
pcv: pcv,
pmarginal: pmarginal,
}
}
pub fn sample_continuous(&self, u: Point2f) -> (Point2f, Float) {
let (d1, pdf1, v) = self.pmarginal.sample_continuous(u.y);
let (d0, pdf0, _) = self.pcv[v].sample_continuous(u.x);
(Point2f::new(d0, d1), pdf0 * pdf1)
}
pub fn pdf(&self, p: Point2f) -> Float {
let n = self.pcv[0].len();
let iu = (p.x * n as Float) as isize;
let iu = if iu < 0 {
0
} else if iu > (n-1) as isize {
n-1
} else {
iu as usize
};
let m = self.pmarginal.len();
let iv = (p.y * m as Float) as isize;
let iv = if iv < 0 {
0
} else if iv > (m-1) as isize {
m-1
} else {
iv as usize
};
self.pcv[iv].func[iu] / self.pmarginal.func_integral
}
}