#[cfg(test)]
#[path = "../../../tests/unit/models/problem/fleet_test.rs"]
mod fleet_test;
use crate::models::common::{Dimensions, Location, Profile, TimeInterval, TimeWindow};
use hashbrown::{HashMap, HashSet};
use std::cmp::Ordering::Less;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct Costs {
pub fixed: f64,
pub per_distance: f64,
pub per_driving_time: f64,
pub per_waiting_time: f64,
pub per_service_time: f64,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct DriverDetail {}
pub struct Driver {
pub costs: Costs,
pub dimens: Dimensions,
pub details: Vec<DriverDetail>,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct VehiclePlace {
pub location: Location,
pub time: TimeInterval,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct VehicleDetail {
pub start: Option<VehiclePlace>,
pub end: Option<VehiclePlace>,
}
pub struct Vehicle {
pub profile: Profile,
pub costs: Costs,
pub dimens: Dimensions,
pub details: Vec<VehicleDetail>,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct ActorDetail {
pub start: Option<VehiclePlace>,
pub end: Option<VehiclePlace>,
pub time: TimeWindow,
}
pub struct Actor {
pub vehicle: Arc<Vehicle>,
pub driver: Arc<Driver>,
pub detail: ActorDetail,
}
pub type ActorGroupKeyFn = Box<dyn Fn(&[Arc<Actor>]) -> Box<dyn Fn(&Arc<Actor>) -> usize + Send + Sync>>;
pub struct Fleet {
pub drivers: Vec<Arc<Driver>>,
pub vehicles: Vec<Arc<Vehicle>>,
pub profiles: Vec<Profile>,
pub actors: Vec<Arc<Actor>>,
pub groups: HashMap<usize, HashSet<Arc<Actor>>>,
}
impl Fleet {
pub fn new(drivers: Vec<Arc<Driver>>, vehicles: Vec<Arc<Vehicle>>, group_key: ActorGroupKeyFn) -> Fleet {
assert_eq!(drivers.len(), 1);
assert!(!vehicles.is_empty());
let profiles: HashSet<Profile> = vehicles.iter().map(|v| v.profile).collect();
let mut profiles: Vec<Profile> = profiles.into_iter().map(|p| p).collect();
profiles.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Less));
let mut actors: Vec<Arc<Actor>> = Default::default();
vehicles.iter().for_each(|vehicle| {
vehicle.details.iter().for_each(|detail| {
actors.push(Arc::new(Actor {
vehicle: vehicle.clone(),
driver: drivers.first().unwrap().clone(),
detail: ActorDetail {
start: detail.start.clone(),
end: detail.end.clone(),
time: TimeWindow {
start: detail.start.as_ref().and_then(|s| s.time.earliest).unwrap_or(0.),
end: detail.end.as_ref().and_then(|e| e.time.latest).unwrap_or(std::f64::MAX),
},
},
}));
});
});
let group_key = (*group_key)(&actors);
let groups = actors.iter().cloned().fold(HashMap::new(), |mut acc, actor| {
acc.entry((*group_key)(&actor)).or_insert_with(HashSet::new).insert(actor.clone());
acc
});
Fleet { drivers, vehicles, actors, profiles, groups }
}
}
impl Hash for Costs {
fn hash<H: Hasher>(&self, state: &mut H) {
let fixed = self.fixed.to_bits() as i64;
let per_distance = self.per_distance.to_bits() as i64;
let per_driving_time = self.per_driving_time.to_bits() as i64;
let per_service_time = self.per_service_time.to_bits() as i64;
let per_waiting_time = self.per_waiting_time.to_bits() as i64;
fixed.hash(state);
per_distance.hash(state);
per_driving_time.hash(state);
per_service_time.hash(state);
per_waiting_time.hash(state);
}
}
impl Eq for Costs {}
impl PartialEq for Costs {
fn eq(&self, other: &Self) -> bool {
self.fixed == other.fixed
&& self.per_distance == other.per_distance
&& self.per_driving_time == other.per_driving_time
&& self.per_service_time == other.per_service_time
&& self.per_waiting_time == other.per_waiting_time
}
}
impl PartialEq<Actor> for Actor {
fn eq(&self, other: &Actor) -> bool {
&*self as *const Actor == &*other as *const Actor
}
}
impl Eq for Actor {}
impl Hash for Actor {
fn hash<H: Hasher>(&self, state: &mut H) {
let address = &*self as *const Actor;
address.hash(state);
}
}