use super::{ArrivalBound, Curve, Propagated};
use crate::time::Duration;
use std::iter;
type Step = (Duration, usize);
#[derive(Clone, Debug)]
pub struct ArrivalCurvePrefix {
horizon: Duration,
steps: Vec<Step>,
}
impl ArrivalCurvePrefix {
pub fn new(horizon: Duration, steps: Vec<Step>) -> ArrivalCurvePrefix {
let mut last_njobs: usize = 0;
for (delta, njobs) in &steps {
assert!(*delta <= horizon);
assert!(last_njobs < *njobs);
last_njobs = *njobs;
}
ArrivalCurvePrefix { horizon, steps }
}
pub fn from_arrival_bound_until<T: ArrivalBound>(
ab: &T,
horizon: Duration,
) -> ArrivalCurvePrefix {
Self::new(
horizon,
ab.steps_iter()
.take_while(|delta| *delta <= horizon.max(Duration::epsilon()))
.map(|delta| (delta, ab.number_arrivals(delta)))
.collect(),
)
}
fn max_njobs_in_horizon(&self) -> usize {
self.steps.last().map(|(_, njobs)| *njobs).unwrap_or(0)
}
fn lookup(&self, delta: Duration) -> usize {
assert!(delta <= self.horizon);
if delta.is_zero() {
0
} else {
let step = self
.steps
.iter()
.enumerate()
.skip_while(|(_i, (min_distance, _njobs))| *min_distance <= delta)
.map(|(i, _)| i)
.next();
let i = step.unwrap_or(self.steps.len());
self.steps[i - 1].1
}
}
}
impl ArrivalBound for ArrivalCurvePrefix {
fn number_arrivals(&self, delta: Duration) -> usize {
let full_horizons = delta / self.horizon;
let partial_horizon = delta % self.horizon;
self.max_njobs_in_horizon() * (full_horizons as usize) + self.lookup(partial_horizon)
}
fn clone_with_jitter(&self, jitter: Duration) -> Box<dyn ArrivalBound> {
Box::new(Propagated::with_jitter(self, jitter))
}
fn steps_iter<'a>(&'a self) -> Box<dyn Iterator<Item = Duration> + 'a> {
let horizon = self.horizon;
Box::new(
iter::once(Duration::zero()).chain((0..).flat_map(move |cycle: u64| {
self.steps
.iter()
.map(move |(offset, _njobs)| *offset + horizon * cycle)
})),
)
}
}
impl From<&ArrivalCurvePrefix> for Curve {
fn from(ac: &ArrivalCurvePrefix) -> Self {
let njobs = ac.max_njobs_in_horizon();
let mut curve = Curve::from_arrival_bound(&ac, njobs);
curve.extrapolate_with_bound((ac.horizon + Duration::epsilon(), njobs + 1));
curve
}
}
impl From<ArrivalCurvePrefix> for Curve {
fn from(ac: ArrivalCurvePrefix) -> Self {
Self::from(&ac)
}
}