1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#[cfg(test)]
#[path = "../../../tests/unit/models/problem/fleet_test.rs"]
mod fleet_test;

use crate::models::common::{Dimensions, Location, Profile, TimeWindow};
use hashbrown::{HashMap, HashSet};
use std::cmp::Ordering::Less;
use std::hash::{Hash, Hasher};
use std::sync::Arc;

/// Represents operating costs for driver and vehicle.
#[derive(Clone, Debug)]
pub struct Costs {
    /// A fixed cost to use an actor.
    pub fixed: f64,
    /// Cost per distance unit.
    pub per_distance: f64,
    /// Cost per driving time unit.
    pub per_driving_time: f64,
    /// Cost per waiting time unit.
    pub per_waiting_time: f64,
    /// Cost per service time unit.
    pub per_service_time: f64,
}

/// Represents driver detail.
pub struct DriverDetail {
    /// Time windows when driver can work.
    pub time: Option<TimeWindow>,
}

/// Represents a driver, person who drives Vehicle.
/// Introduced to allow the following scenarios:
/// * reuse vehicle multiple times with different drivers
/// * solve best driver-vehicle match problem.
/// NOTE: At the moment, it is not used.
pub struct Driver {
    /// Specifies operating costs for driver.
    pub costs: Costs,
    /// Dimensions which contains extra work requirements.
    pub dimens: Dimensions,
    /// Specifies driver details.
    pub details: Vec<DriverDetail>,
}

/// Represents a vehicle detail.
#[derive(Clone, Debug)]
pub struct VehicleDetail {
    /// Location where vehicle starts.
    pub start: Option<Location>,
    /// Location where vehicle ends.
    pub end: Option<Location>,
    /// Time windows when driver can work.
    pub time: Option<TimeWindow>,
}

/// Represents a vehicle.
pub struct Vehicle {
    pub profile: Profile,
    /// Specifies operating costs for vehicle.
    pub costs: Costs,
    /// Dimensions which contains extra work requirements.
    pub dimens: Dimensions,
    /// Specifies vehicle details.
    pub details: Vec<VehicleDetail>,
}

/// Represents actor detail.
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct ActorDetail {
    /// Location where actor starts.
    pub start: Option<Location>,

    /// Location where actor ends.
    pub end: Option<Location>,

    /// Time windows when actor can work.
    pub time: TimeWindow,
}

/// Represents an actor.
pub struct Actor {
    /// A vehicle associated within actor.
    pub vehicle: Arc<Vehicle>,

    /// A driver associated within actor.
    pub driver: Arc<Driver>,

    /// Specifies actor detail.
    pub detail: ActorDetail,
}

pub type ActorGroupKeyFn = Box<dyn Fn(&[Arc<Actor>]) -> Box<dyn Fn(&Arc<Actor>) -> usize + Send + Sync>>;

/// Represents available resources to serve jobs.
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 {
    /// Creates a new fleet.
    pub fn new(drivers: Vec<Arc<Driver>>, vehicles: Vec<Arc<Vehicle>>, group_key: ActorGroupKeyFn) -> Fleet {
        // TODO we should also consider multiple drivers to support smart vehicle-driver assignment.
        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,
                        end: detail.end,
                        time: detail.time.clone().unwrap_or(TimeWindow { start: 0.0, end: 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);
    }
}