use rand::thread_rng;
use rand::distributions::Uniform;
use rand::distributions::Poisson;
use rand::prelude::*;
use ndarray::prelude::*;
pub trait Set {
fn contains(&self, p: &Array<f64, Ix1>) -> bool;
fn bounding_box(&self) -> Array<f64, Ix2>;
}
pub trait Measurable: Set {
fn measure(&self) -> f64;
}
pub struct Rectangle(Array<f64, Ix1>, Array<f64, Ix1>);
impl Rectangle {
pub fn new(close: Array<f64, Ix1>, far: Array<f64, Ix1>) -> Rectangle {
Rectangle(close, far)
}
}
impl Set for Rectangle {
fn contains(&self, p: &Array<f64, Ix1>) -> bool {
assert_eq!(p.len(), self.0.shape()[0]);
let further = self.0.iter().zip(p.iter())
.fold(true, |acc: bool, (v,w)| {
acc & (w > v)
});
let closer = self.1.iter().zip(p.iter())
.fold(true, |acc: bool, (v,w)| {
acc & (w < v)
});
further & closer
}
fn bounding_box(&self) -> Array<f64, Ix2> {
let mut result = unsafe {
Array::uninitialized((self.0.shape()[0], 2))
};
result.slice_mut(s![0,..]).assign(&self.0);
result.slice_mut(s![1,..]).assign(&self.1);
result
}
}
impl Measurable for Rectangle {
fn measure(&self) -> f64 {
let n: usize = self.0.shape()[0];
let mut result = 1.0;
for i in 0..n {
result *= self.1[i] - self.0[i];
}
result
}
}
pub struct Sphere {
center: Array<f64, Ix1>,
radius: f64
}
impl Sphere {
pub fn new(center: Array<f64, Ix1>, radius: f64) -> Sphere {
assert!(radius > 0.0);
Sphere {
center, radius
}
}
}
impl Set for Sphere {
fn contains(&self, p: &Array<f64, Ix1>) -> bool {
let diff = &self.center - p;
let distance = diff.dot(&diff).sqrt();
distance <= self.radius
}
fn bounding_box(&self) -> Array<f64, Ix2> {
let n = self.center.shape()[0];
let mut res = unsafe {
Array::uninitialized((n, 2))
};
for i in 0..n {
res[[0,i]] = self.center[i] - self.radius;
res[[1,i]] = self.center[i] + self.radius;
}
res
}
}
impl Measurable for Sphere {
fn measure(&self) -> f64 {
use std::f64::consts::PI as PI;
const MONTE_CARLO_STEPS: u32 = 1000000;
let n = self.center.shape()[0];
match n {
0 => 0.0,
1 => 2.0*self.radius,
2 => PI*self.radius.powi(2),
3 => 4.0*PI*self.radius.powi(3)/3.0,
_ => {
let ref mut rng = thread_rng();
let bounds = self.bounding_box();
let mut count = 0;
for _ in 0..MONTE_CARLO_STEPS {
let mut p = unsafe {
Array::uninitialized((n,))
};
for i in 0..n {
p[i] = rng.sample(Uniform::new(bounds[[0,i]], bounds[[1,i]]));
}
if self.contains(&p) {
count += 1;
}
}
count as f64/MONTE_CARLO_STEPS as f64
}
}
}
}
pub fn poisson_process<T>(lambda: f64, domain: &T) -> Array<f64, Ix2>
where T: Measurable {
let area: f64 = domain.measure();
let bounds = domain.bounding_box();
let d: usize = bounds.shape()[1];
let ref mut rng = thread_rng();
let num_events = Poisson::new(lambda*area).sample(rng) as usize;
let mut res = unsafe {
Array::uninitialized((num_events, d))
};
let mut counter = 0_usize;
while counter < num_events {
let mut ev = Array::zeros((d,));
for i in 0..d {
ev[i] = rng.sample(Uniform::new(bounds[[0,i]], bounds[[1,i]]));
}
if domain.contains(&ev) {
res.slice_mut(s![counter,..]).assign(&ev);
counter += 1;
}
}
res
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rectangle_test() {
let close = array![0.0, 1.0];
let far = array![1.0, 4.0];
let rect = Rectangle::new(close, far);
assert_eq!(rect.measure(), 3.0);
let p = array![0.5, 1.5];
assert!(rect.contains(&p));
let p = array![-1.0,2.0];
assert!(!rect.contains(&p));
}
}