use super::{Edge, Network, Times, finite, time_at};
use crate::ScheduleError;
use crate::placement::{Placed, Placement};
use dpm_model::{DependencyId, Endpoint, WorkingTime};
type Forward = (Vec<f64>, Vec<f64>, Vec<f64>);
fn read(values: &[f64], position: usize) -> Result<f64, Placed> {
Ok(time_at(values, position)?)
}
fn forward(edge: &Edge, event: f64, successor: &WorkingTime) -> Result<f64, Placed> {
if edge.working {
Ok(successor.shift(event, edge.lag)?)
} else {
Ok(event + edge.lag)
}
}
fn backward(edge: &Edge, event: f64, successor: &WorkingTime) -> Result<f64, Placed> {
if edge.working {
Ok(successor.unshift(event, edge.lag)?)
} else {
Ok(event - edge.lag)
}
}
impl Network {
pub(crate) fn times_placed(
&self,
durations: &[f64],
placement: &mut Placement,
) -> Result<Times, ScheduleError> {
placement.fit(|placement| self.placed_pass(durations, placement))
}
fn placed_pass(&self, durations: &[f64], placement: &Placement) -> Result<Times, Placed> {
let (earliest, earliest_finish, review_wait) = self.forward_placed(durations, placement)?;
let finish = earliest_finish.iter().copied().fold(0.0_f64, f64::max);
let (latest, latest_finish) = self.backward_placed(durations, placement, finish)?;
Ok(Times {
earliest,
latest,
earliest_finish,
latest_finish,
review_wait,
finish,
})
}
fn forward_placed(&self, durations: &[f64], placement: &Placement) -> Result<Forward, Placed> {
let count = self.order.len();
let (mut earliest, mut earliest_finish) =
(Vec::with_capacity(count), Vec::with_capacity(count));
let mut review_wait = Vec::with_capacity(count);
for (position, (id, edges)) in self.order.iter().zip(&self.incoming).enumerate() {
let duration = super::at(durations, position, *id)?;
let calendar = placement.execution(position)?;
let (mut start, mut finish_bound) = (0.0_f64, f64::NEG_INFINITY);
for edge in edges {
let event = match edge.kind.predecessor_endpoint() {
Endpoint::Start => read(&earliest, edge.other)?,
Endpoint::Finish => read(&earliest_finish, edge.other)?,
};
let bound = finite(*id, forward(edge, event, calendar)?)?;
match edge.kind.successor_endpoint() {
Endpoint::Start => start = start.max(bound),
Endpoint::Finish => finish_bound = finish_bound.max(bound),
}
}
if finish_bound > start {
start = start.max(calendar.sub(finish_bound, duration)?);
}
let (start, mut done) = calendar.place(start, duration)?;
let mut aligned = duration > 0.0 && placement.reviewed_on_own_calendar(position);
if done < finish_bound {
aligned = false;
done = if duration > 0.0 {
calendar.align(finish_bound)?
} else {
finish_bound
};
}
let verified = match placement.review(position)? {
Some(_) if aligned => done,
Some(verifier) => verifier.align(done + placement.review_delay())?,
None => done,
};
earliest.push(finite(*id, start)?);
earliest_finish.push(finite(*id, verified)?);
review_wait.push(verified - done);
}
Ok((earliest, earliest_finish, review_wait))
}
fn backward_placed(
&self,
durations: &[f64],
placement: &Placement,
finish: f64,
) -> Result<(Vec<f64>, Vec<f64>), Placed> {
let count = self.order.len();
let mut latest = vec![0.0; count];
let mut latest_finish = vec![0.0; count];
for (position, (id, edges)) in self.order.iter().zip(&self.outgoing).enumerate().rev() {
let duration = super::at(durations, position, *id)?;
let (mut start_bound, mut finish_bound) = (f64::INFINITY, finish);
for edge in edges {
let successor = placement.execution(edge.other)?;
let event = match edge.kind.successor_endpoint() {
Endpoint::Start => read(&latest, edge.other)?,
Endpoint::Finish => read(&latest_finish, edge.other)?,
};
let bound = finite(*id, backward(edge, event, successor)?)?;
match edge.kind.predecessor_endpoint() {
Endpoint::Start => start_bound = start_bound.min(bound),
Endpoint::Finish => finish_bound = finish_bound.min(bound),
}
}
let calendar = placement.execution(position)?;
let review = placement.review(position)?;
let latest_start = match review {
Some(_) if placement.reviewed_on_own_calendar(position) => {
calendar.retreat(finish_bound, duration)?
}
Some(verifier) => calendar.sub(
verifier.align_back(finish_bound)? - placement.review_delay(),
duration,
)?,
None => calendar.sub(finish_bound, duration)?,
};
let start = start_bound.min(latest_start);
if let (Some(slot), Some(end)) =
(latest.get_mut(position), latest_finish.get_mut(position))
{
*slot = finite(*id, start)?;
*end = finite(*id, finish_bound)?;
}
}
Ok((latest, latest_finish))
}
pub(super) fn free_float_placed(
&self,
times: &Times,
position: usize,
placement: &Placement,
) -> Result<f64, ScheduleError> {
let (Some(id), Some(edges)) = (self.order.get(position), self.outgoing.get(position))
else {
return Err(ScheduleError::UnknownPosition(position));
};
let start = time_at(×.earliest, position)?;
let finish = time_at(×.earliest_finish, position)?;
let mut available = finite(*id, times.finish - finish)?;
for edge in edges {
let own = match edge.kind.predecessor_endpoint() {
Endpoint::Start => start,
Endpoint::Finish => finish,
};
let successor = match edge.kind.successor_endpoint() {
Endpoint::Start => time_at(×.earliest, edge.other)?,
Endpoint::Finish => time_at(×.earliest_finish, edge.other)?,
};
let calendar = placement
.execution(edge.other)
.map_err(|_| ScheduleError::CalendarRange)?;
let Ok(bound) = forward(edge, own, calendar) else {
continue;
};
available = available.min(finite(*id, successor - bound)?);
}
Ok(available.max(0.0))
}
pub(super) fn incoming_slacks_placed(
&self,
durations: &[f64],
times: &Times,
position: usize,
placement: &Placement,
) -> Result<Vec<(DependencyId, usize, f64)>, ScheduleError> {
let (Some(id), Some(edges)) = (self.order.get(position), self.incoming.get(position))
else {
return Err(ScheduleError::UnknownPosition(position));
};
let duration = super::at(durations, position, *id)?;
let calendar = placement
.execution(position)
.map_err(|_| ScheduleError::CalendarRange)?;
let mut required = Vec::with_capacity(edges.len());
for edge in edges {
let event = match edge.kind.predecessor_endpoint() {
Endpoint::Start => time_at(×.earliest, edge.other)?,
Endpoint::Finish => time_at(×.earliest_finish, edge.other)?,
};
let Ok(bound) = forward(edge, event, calendar) else {
continue;
};
let start = match edge.kind.successor_endpoint() {
Endpoint::Start => bound,
Endpoint::Finish => calendar
.sub(bound, duration)
.map_err(|_| ScheduleError::CalendarRange)?,
};
let holds_finish = edge.kind.successor_endpoint() == Endpoint::Finish
&& bound
>= time_at(×.earliest_finish, position)?
- time_at(×.review_wait, position)?
- super::EPSILON;
required.push((edge.id, edge.other, start, holds_finish));
}
let strongest = required
.iter()
.map(|(_, _, start, _)| *start)
.fold(0.0_f64, f64::max);
Ok(required
.into_iter()
.map(|(dependency, from, start, holds_finish)| {
let slack = if holds_finish { 0.0 } else { strongest - start };
(dependency, from, slack)
})
.collect())
}
}