use std::{vec, collections::HashSet};
use ddo::*;
use crate::io_utils::AlpInstance;
const DUMMY: isize = -1;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AlpState {
pub rem: Vec<usize>,
pub info: Vec<RunwayState>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
pub struct RunwayState {
pub prev_time: isize,
pub prev_class: isize,
}
pub struct AlpDecision {
pub class: usize,
pub runway: usize,
}
#[derive(Debug, Clone)]
pub struct Alp {
pub instance: AlpInstance,
pub next: Vec<Vec<usize>>, min_separation_to: Vec<isize>,
}
impl Alp {
pub fn new(instance: AlpInstance) -> Self {
let mut next = vec![vec![0]; instance.nb_classes];
for i in (0..instance.nb_aircrafts).rev() {
next[instance.classes[i]].push(i);
}
let mut min_separation_to = vec![isize::MAX; instance.nb_classes];
for i in 0..instance.nb_classes {
for j in 0..instance.nb_classes {
min_separation_to[j] = min_separation_to[j].min(instance.separation[i][j]);
}
}
Alp {
instance,
next,
min_separation_to,
}
}
pub fn get_arrival_time(&self, info: &Vec<RunwayState>, aircraft: usize, runway: usize) -> isize {
if info[runway].prev_time == 0 && info[runway].prev_class == DUMMY { self.instance.target[aircraft]
} else if info[runway].prev_class == DUMMY { self.instance.target[aircraft]
.max(info[runway].prev_time + self.min_separation_to[self.instance.classes[aircraft]])
} else {
self.instance.target[aircraft]
.max(info[runway].prev_time + self.instance.separation[info[runway].prev_class as usize][self.instance.classes[aircraft]])
}
}
pub fn to_decision(&self, decision: &AlpDecision) -> isize {
(decision.class + self.instance.nb_classes * decision.runway) as isize
}
pub fn from_decision(&self, value: isize) -> AlpDecision {
AlpDecision {
class: value as usize % self.instance.nb_classes,
runway: value as usize / self.instance.nb_classes,
}
}
}
impl Problem for Alp {
type State = AlpState;
fn nb_variables(&self) -> usize {
self.instance.nb_aircrafts
}
fn initial_state(&self) -> Self::State {
let mut rem = vec![0; self.instance.nb_classes];
for i in 0..self.instance.nb_aircrafts {
rem[self.instance.classes[i]] += 1;
}
AlpState {
rem,
info: vec![RunwayState {prev_class: DUMMY, prev_time: 0}; self.instance.nb_runways],
}
}
fn initial_value(&self) -> isize {
0
}
fn transition(&self, state: &Self::State, decision: ddo::Decision) -> Self::State {
if decision.value == DUMMY {
state.clone()
} else {
let AlpDecision {class, runway} = self.from_decision(decision.value);
let aircraft = self.next[class][state.rem[class]];
let mut next = state.clone();
next.rem[self.instance.classes[aircraft]] -= 1;
next.info[runway].prev_class = class as isize;
next.info[runway].prev_time = self.get_arrival_time(&state.info, aircraft, runway);
next.info.sort_unstable();
next
}
}
fn transition_cost(&self, state: &Self::State, _: &Self::State, decision: ddo::Decision) -> isize {
if decision.value == DUMMY {
0
} else {
let AlpDecision {class, runway} = self.from_decision(decision.value);
let aircraft = self.next[class][state.rem[class]];
- (self.get_arrival_time(&state.info, aircraft, runway) - self.instance.target[aircraft])
}
}
fn next_variable(&self, depth: usize, _: &mut dyn Iterator<Item = &Self::State>)
-> Option<ddo::Variable> {
if depth < self.instance.nb_aircrafts {
Some(Variable(depth))
} else {
None
}
}
fn for_each_in_domain(&self, variable: ddo::Variable, state: &Self::State, f: &mut dyn ddo::DecisionCallback) {
let mut tot_rem = 0;
let mut used = HashSet::new();
let mut decisions = vec![];
for (class, rem) in state.rem.iter().copied().enumerate() {
if rem > 0 {
let aircraft = self.next[class][rem];
used.clear();
for runway in 0..self.instance.nb_runways {
if used.contains(&state.info[runway]) {
continue;
}
let arrival = self.get_arrival_time(&state.info, aircraft, runway);
if arrival <= self.instance.latest[aircraft] {
decisions.push(self.to_decision(&AlpDecision { class, runway }));
used.insert(state.info[runway]);
}
}
if used.len() == 0 {
return;
}
}
tot_rem += rem;
}
if tot_rem == 0 {
f.apply(Decision {variable, value: DUMMY });
} else {
decisions.iter().for_each(|d| f.apply(Decision { variable, value: *d }));
}
}
}
pub struct AlpRelax {
pb: Alp,
}
impl AlpRelax {
pub fn new(pb: Alp) -> Self {
Self { pb }
}
}
impl Relaxation for AlpRelax {
type State = AlpState;
fn merge(&self, states: &mut dyn Iterator<Item = &Self::State>) -> Self::State {
let mut rem = vec![usize::MAX; self.pb.instance.nb_classes];
let mut info = vec![RunwayState { prev_class: DUMMY, prev_time: isize::MAX }; self.pb.instance.nb_runways];
for s in states {
rem.iter_mut().enumerate().for_each(|(k,r)| *r = (*r).min(s.rem[k]));
info.iter_mut().enumerate().for_each(|(r,i)| i.prev_time = i.prev_time.min(s.info[r].prev_time));
}
AlpState {
rem,
info,
}
}
fn relax(
&self,
_source: &Self::State,
_dest: &Self::State,
_new: &Self::State,
_decision: Decision,
cost: isize,
) -> isize {
cost
}
fn fast_upper_bound(&self, _: &Self::State) -> isize {
0
}
}
pub struct AlpRanking;
impl StateRanking for AlpRanking {
type State = AlpState;
fn compare(&self, a: &Self::State, b: &Self::State) -> std::cmp::Ordering {
let tot_a = a.info.iter().map(|i| i.prev_time).sum::<isize>();
let tot_b = b.info.iter().map(|i| i.prev_time).sum::<isize>();
tot_a.cmp(&tot_b)
}
}