#[cfg(test)]
#[path = "../../../tests/unit/models/domain/load_test.rs"]
mod load_test;
use crate::models::common::{Dimensions, ValueDimension};
use std::cmp::Ordering;
use std::iter::Sum;
use std::ops::{Add, Mul, Sub};
const CAPACITY_DIMENSION_KEY: &str = "cpc";
const DEMAND_DIMENSION_KEY: &str = "dmd";
const LOAD_DIMENSION_SIZE: usize = 8;
pub trait Load: Add + Sub + Ord + Copy + Default + Send + Sync {
fn is_not_empty(&self) -> bool;
fn max_load(self, other: Self) -> Self;
fn can_fit(&self, other: &Self) -> bool;
}
pub struct Demand<T: Load + Add<Output = T> + Sub<Output = T> + 'static> {
pub pickup: (T, T),
pub delivery: (T, T),
}
pub trait CapacityDimension<T: Load + Add<Output = T> + Sub<Output = T> + 'static> {
fn set_capacity(&mut self, demand: T) -> &mut Self;
fn get_capacity(&self) -> Option<&T>;
}
pub trait DemandDimension<T: Load + Add<Output = T> + Sub<Output = T> + 'static> {
fn set_demand(&mut self, demand: Demand<T>) -> &mut Self;
fn get_demand(&self) -> Option<&Demand<T>>;
}
impl<T: Load + Add<Output = T> + Sub<Output = T> + 'static> Demand<T> {
pub fn change(&self) -> T {
self.pickup.0 + self.pickup.1 - self.delivery.0 - self.delivery.1
}
}
impl<T: Load + Add<Output = T> + Sub<Output = T> + 'static> Default for Demand<T> {
fn default() -> Self {
Self { pickup: (Default::default(), Default::default()), delivery: (Default::default(), Default::default()) }
}
}
impl<T: Load + Add<Output = T> + Sub<Output = T> + 'static> Clone for Demand<T> {
fn clone(&self) -> Self {
Self { pickup: self.pickup, delivery: self.delivery }
}
}
impl<T: Load + Add<Output = T> + Sub<Output = T> + 'static> CapacityDimension<T> for Dimensions {
fn set_capacity(&mut self, demand: T) -> &mut Self {
self.set_value(CAPACITY_DIMENSION_KEY, demand);
self
}
fn get_capacity(&self) -> Option<&T> {
self.get_value(CAPACITY_DIMENSION_KEY)
}
}
impl<T: Load + Add<Output = T> + Sub<Output = T> + 'static> DemandDimension<T> for Dimensions {
fn set_demand(&mut self, demand: Demand<T>) -> &mut Self {
self.set_value(DEMAND_DIMENSION_KEY, demand);
self
}
fn get_demand(&self) -> Option<&Demand<T>> {
self.get_value(DEMAND_DIMENSION_KEY)
}
}
#[derive(Clone, Copy, Debug)]
pub struct SingleDimLoad {
pub value: i32,
}
impl SingleDimLoad {
pub fn new(value: i32) -> Self {
Self { value }
}
}
impl Default for SingleDimLoad {
fn default() -> Self {
Self { value: 0 }
}
}
impl Load for SingleDimLoad {
fn is_not_empty(&self) -> bool {
self.value != 0
}
fn max_load(self, other: Self) -> Self {
let value = self.value.max(other.value);
Self { value }
}
fn can_fit(&self, other: &Self) -> bool {
self.value >= other.value
}
}
impl Add for SingleDimLoad {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let value = self.value + rhs.value;
Self { value }
}
}
impl Sub for SingleDimLoad {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let value = self.value - rhs.value;
Self { value }
}
}
impl Ord for SingleDimLoad {
fn cmp(&self, other: &Self) -> Ordering {
self.value.cmp(&other.value)
}
}
impl PartialOrd for SingleDimLoad {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for SingleDimLoad {}
impl PartialEq for SingleDimLoad {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Mul<f64> for SingleDimLoad {
type Output = Self;
fn mul(self, value: f64) -> Self::Output {
Self::new((self.value as f64 * value).round() as i32)
}
}
#[derive(Clone, Copy, Debug)]
pub struct MultiDimLoad {
pub load: [i32; LOAD_DIMENSION_SIZE],
pub size: usize,
}
impl MultiDimLoad {
pub fn new(data: Vec<i32>) -> Self {
assert!(data.len() <= LOAD_DIMENSION_SIZE);
let mut load = [0; LOAD_DIMENSION_SIZE];
for (idx, value) in data.iter().enumerate() {
load[idx] = *value;
}
Self { load, size: data.len() }
}
fn get(&self, idx: usize) -> i32 {
self.load[idx]
}
pub fn as_vec(&self) -> Vec<i32> {
if self.size == 0 {
vec![0]
} else {
self.load[..self.size].to_vec()
}
}
}
impl Load for MultiDimLoad {
fn is_not_empty(&self) -> bool {
self.size == 0 || self.load.iter().any(|v| *v != 0)
}
fn max_load(self, other: Self) -> Self {
let mut result = self;
result.load.iter_mut().zip(other.load.iter()).for_each(|(a, b)| *a = (*a).max(*b));
result
}
fn can_fit(&self, other: &Self) -> bool {
self.load.iter().zip(other.load.iter()).all(|(a, b)| a >= b)
}
}
impl Default for MultiDimLoad {
fn default() -> Self {
Self { load: [0; LOAD_DIMENSION_SIZE], size: 0 }
}
}
impl Add for MultiDimLoad {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
fn sum(acc: MultiDimLoad, rhs: &MultiDimLoad) -> MultiDimLoad {
let mut dimens = acc;
for (idx, value) in rhs.load.iter().enumerate() {
dimens.load[idx] += *value;
}
dimens.size = dimens.size.max(rhs.size);
dimens
}
if self.load.len() >= rhs.load.len() {
sum(self, &rhs)
} else {
sum(rhs, &self)
}
}
}
impl Sub for MultiDimLoad {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut dimens = self;
for (idx, value) in rhs.load.iter().enumerate() {
dimens.load[idx] -= *value;
}
dimens.size = dimens.size.max(rhs.size);
dimens
}
}
impl Ord for MultiDimLoad {
fn cmp(&self, other: &Self) -> Ordering {
let size = self.load.len().max(other.load.len());
(0..size).fold(Ordering::Equal, |acc, idx| match acc {
Ordering::Greater => Ordering::Greater,
Ordering::Equal => self.get(idx).cmp(&other.get(idx)),
Ordering::Less => {
if self.get(idx) > other.get(idx) {
Ordering::Greater
} else {
Ordering::Less
}
}
})
}
}
impl PartialOrd for MultiDimLoad {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Eq for MultiDimLoad {}
impl PartialEq for MultiDimLoad {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Mul<f64> for MultiDimLoad {
type Output = Self;
fn mul(self, value: f64) -> Self::Output {
let mut dimens = self;
dimens.load.iter_mut().for_each(|item| {
*item = (*item as f64 * value).round() as i32;
});
dimens
}
}
impl Sum for MultiDimLoad {
fn sum<I: Iterator<Item = MultiDimLoad>>(iter: I) -> Self {
iter.fold(MultiDimLoad::default(), |acc, item| item + acc)
}
}