use crate::Result;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Interval {
pub id: usize,
pub earliest_start: i64,
pub latest_end: i64,
pub duration: i64,
pub demand: i64,
}
impl Interval {
pub fn new(id: usize, earliest_start: i64, latest_end: i64, duration: i64) -> Self {
Self {
id,
earliest_start,
latest_end,
duration,
demand: 1,
}
}
pub fn with_demand(mut self, demand: i64) -> Self {
self.demand = demand;
self
}
pub fn latest_start(&self) -> i64 {
self.latest_end - self.duration
}
pub fn earliest_end(&self) -> i64 {
self.earliest_start + self.duration
}
pub fn is_feasible(&self) -> bool {
self.earliest_start + self.duration <= self.latest_end
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScheduledInterval {
pub interval: Interval,
pub start: i64,
}
impl ScheduledInterval {
pub fn end(&self) -> i64 {
self.start + self.interval.duration
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchedulingProblem {
pub intervals: Vec<Interval>,
pub capacity: i64,
pub disjunctive: bool,
}
impl SchedulingProblem {
pub fn disjunctive(intervals: Vec<Interval>) -> Self {
Self {
intervals,
capacity: 1,
disjunctive: true,
}
}
pub fn cumulative(intervals: Vec<Interval>, capacity: i64) -> Self {
Self {
intervals,
capacity,
disjunctive: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SchedulingSolution {
pub schedule: Vec<ScheduledInterval>,
pub makespan: i64,
}
pub fn list_schedule(problem: &SchedulingProblem) -> Result<SchedulingSolution> {
let mut schedule = Vec::new();
let mut current_time = 0i64;
let mut intervals = problem.intervals.clone();
intervals.sort_by_key(|i| i.earliest_start);
for interval in intervals {
let start = current_time.max(interval.earliest_start);
if start + interval.duration > interval.latest_end {
return Err(crate::Error::infeasible(format!(
"Interval {} cannot be scheduled within time window",
interval.id
)));
}
schedule.push(ScheduledInterval {
start,
interval: interval.clone(),
});
if problem.disjunctive {
current_time = start + interval.duration;
}
}
let makespan = schedule.iter()
.map(|s| s.end())
.max()
.unwrap_or(0);
Ok(SchedulingSolution { schedule, makespan })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_disjunctive() {
let intervals = vec![
Interval::new(0, 0, 100, 10),
Interval::new(1, 0, 100, 20),
Interval::new(2, 0, 100, 15),
];
let problem = SchedulingProblem::disjunctive(intervals);
let solution = list_schedule(&problem).unwrap();
assert_eq!(solution.schedule.len(), 3);
assert_eq!(solution.makespan, 45); }
#[test]
fn test_interval_feasibility() {
let interval = Interval::new(0, 0, 10, 5);
assert!(interval.is_feasible());
let infeasible = Interval::new(0, 0, 3, 5);
assert!(!infeasible.is_feasible());
}
}