use super::{ArrivalBound, Propagated};
use crate::time::{Duration, Time};
#[derive(Copy, Clone, Debug)]
pub struct Poisson {
pub rate: f64,
}
impl Poisson {
pub fn arrival_probability(&self, delta: Duration, njobs: usize) -> f64 {
let mut denominator = 1.0;
for x in 1..(njobs + 1) {
denominator *= x as f64;
}
let mean = Time::from(delta) as f64 * self.rate;
let mut numerator = (-mean).exp(); numerator *= mean.powi(njobs as i32); numerator / denominator
}
pub fn approximate(&self, epsilon: f64) -> ApproximatedPoisson {
ApproximatedPoisson {
poisson: *self,
epsilon,
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct ApproximatedPoisson {
poisson: Poisson,
epsilon: f64,
}
impl ApproximatedPoisson {
pub fn new(lambda: f64, epsilon: f64) -> Self {
ApproximatedPoisson {
epsilon,
poisson: Poisson { rate: lambda },
}
}
}
impl ArrivalBound for ApproximatedPoisson {
fn number_arrivals(&self, delta: Duration) -> usize {
if delta.is_non_zero() {
let mut cumulative_prob = 0.0;
let mut njobs = 0;
loop {
cumulative_prob += self.poisson.arrival_probability(delta, njobs);
if cumulative_prob + self.epsilon >= 1.0 {
break;
}
njobs += 1;
}
njobs
} else {
0
}
}
fn clone_with_jitter(&self, jitter: Duration) -> Box<dyn ArrivalBound> {
Box::new(Propagated::with_jitter(self, jitter))
}
}