vrp_core/models/problem/
fleet.rs

1#[cfg(test)]
2#[path = "../../../tests/unit/models/problem/fleet_test.rs"]
3mod fleet_test;
4
5use crate::models::common::*;
6use crate::utils::short_type_name;
7use rosomaxa::prelude::Float;
8use std::collections::{HashMap, HashSet};
9use std::fmt::{Debug, Formatter};
10use std::hash::{Hash, Hasher};
11use std::sync::Arc;
12
13custom_dimension!(VehicleId typeof String);
14
15/// Represents operating costs for driver and vehicle.
16#[derive(Clone, Debug)]
17pub struct Costs {
18    /// A fixed cost to use an actor.
19    pub fixed: Float,
20    /// Cost per distance unit.
21    pub per_distance: Float,
22    /// Cost per driving time unit.
23    pub per_driving_time: Float,
24    /// Cost per waiting time unit.
25    pub per_waiting_time: Float,
26    /// Cost per service time unit.
27    pub per_service_time: Float,
28}
29
30/// Represents driver detail (reserved for future use).
31#[derive(Clone, Hash, Eq, PartialEq)]
32pub struct DriverDetail {}
33
34/// Represents a driver, person who drives a [`Vehicle`].
35/// Reserved for future usage, e.g., to allow reusing the same vehicle more than once at different times.
36pub struct Driver {
37    /// Specifies operating costs for a driver.
38    pub costs: Costs,
39
40    /// Dimensions that contain extra work requirements.
41    pub dimens: Dimensions,
42
43    /// Specifies driver details.
44    pub details: Vec<DriverDetail>,
45}
46
47impl Driver {
48    /// Creates an empty driver definition.
49    pub(crate) fn empty() -> Self {
50        Self {
51            costs: Costs {
52                fixed: 0.,
53                per_distance: 0.,
54                per_driving_time: 0.,
55                per_waiting_time: 0.,
56                per_service_time: 0.,
57            },
58            dimens: Default::default(),
59            details: vec![],
60        }
61    }
62}
63
64/// Specifies a vehicle place.
65#[derive(Clone, Debug, Hash, Eq, PartialEq)]
66pub struct VehiclePlace {
67    /// Location of a place.
68    pub location: Location,
69
70    /// Time interval when vehicle is allowed to be at this place.
71    pub time: TimeInterval,
72}
73
74/// Represents a vehicle detail (vehicle shift).
75#[derive(Clone, Debug, Hash, Eq, PartialEq)]
76pub struct VehicleDetail {
77    /// A place where the vehicle starts.
78    pub start: Option<VehiclePlace>,
79
80    /// A place where the vehicle ends.
81    pub end: Option<VehiclePlace>,
82}
83
84/// Represents a vehicle.
85#[derive(Clone, Debug)]
86pub struct Vehicle {
87    /// A vehicle profile.
88    pub profile: Profile,
89
90    /// Specifies operating costs for vehicle.
91    pub costs: Costs,
92
93    /// Dimensions that contain extra work requirements.
94    pub dimens: Dimensions,
95
96    /// Specifies vehicle details.
97    pub details: Vec<VehicleDetail>,
98}
99
100/// Represents an actor detail: exact start/end location and operating time.
101#[derive(Clone, Hash, Eq, PartialEq)]
102pub struct ActorDetail {
103    /// A place where actor's vehicle starts.
104    pub start: Option<VehiclePlace>,
105
106    /// A place where the actor's vehicle ends.
107    pub end: Option<VehiclePlace>,
108
109    /// Time window when an actor allowed working.
110    pub time: TimeWindow,
111}
112
113/// Represents an actor: abstraction over vehicle and driver.
114pub struct Actor {
115    /// A vehicle associated within an actor.
116    pub vehicle: Arc<Vehicle>,
117
118    /// A driver associated within an actor.
119    pub driver: Arc<Driver>,
120
121    /// Specifies actor detail.
122    pub detail: ActorDetail,
123}
124
125impl Debug for Actor {
126    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
127        f.debug_struct(short_type_name::<Self>())
128            .field("vehicle", &self.vehicle.dimens.get_vehicle_id().map(|id| id.as_str()).unwrap_or("undef"))
129            .finish_non_exhaustive()
130    }
131}
132
133/// Represents available resources to serve jobs.
134pub struct Fleet {
135    /// All fleet drivers.
136    pub drivers: Vec<Arc<Driver>>,
137
138    /// All fleet vehicles.
139    pub vehicles: Vec<Arc<Vehicle>>,
140
141    /// All fleet profiles.
142    pub profiles: Vec<Profile>,
143
144    /// All fleet actors.
145    pub actors: Vec<Arc<Actor>>,
146
147    /// A grouped actors.
148    pub groups: HashMap<usize, HashSet<Arc<Actor>>>,
149}
150
151impl Fleet {
152    /// Creates a new instance of `Fleet`.
153    pub fn new<R: Fn(&Actor) -> usize + Send + Sync>(
154        drivers: Vec<Arc<Driver>>,
155        vehicles: Vec<Arc<Vehicle>>,
156        group_key: impl Fn(&[Arc<Actor>]) -> R,
157    ) -> Fleet {
158        // TODO we should also consider multiple drivers to support smart vehicle-driver assignment.
159        assert_eq!(drivers.len(), 1);
160        assert!(!vehicles.is_empty());
161
162        let profiles: HashMap<usize, Profile> = vehicles.iter().map(|v| (v.profile.index, v.profile.clone())).collect();
163        let mut profiles = profiles.into_iter().collect::<Vec<_>>();
164        profiles.sort_by(|(a, _), (b, _)| a.cmp(b));
165        let (_, profiles): (Vec<_>, Vec<_>) = profiles.into_iter().unzip();
166
167        let actors = vehicles
168            .iter()
169            .flat_map(|vehicle| {
170                vehicle.details.iter().map(|detail| {
171                    Arc::new(Actor {
172                        vehicle: vehicle.clone(),
173                        driver: drivers.first().unwrap().clone(),
174                        detail: ActorDetail {
175                            start: detail.start.clone(),
176                            end: detail.end.clone(),
177                            time: TimeWindow {
178                                start: detail.start.as_ref().and_then(|s| s.time.earliest).unwrap_or(0.),
179                                end: detail.end.as_ref().and_then(|e| e.time.latest).unwrap_or(Float::MAX),
180                            },
181                        },
182                    })
183                })
184            })
185            .collect::<Vec<_>>();
186
187        let group_key = (group_key)(&actors);
188        let groups: HashMap<_, HashSet<_>> = actors.iter().cloned().fold(HashMap::new(), |mut acc, actor| {
189            acc.entry((group_key)(&actor)).or_default().insert(actor.clone());
190            acc
191        });
192
193        Fleet { drivers, vehicles, profiles, actors, groups }
194    }
195}
196
197impl Debug for Fleet {
198    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
199        f.debug_struct(short_type_name::<Self>())
200            .field("vehicles", &self.vehicles.len())
201            .field("drivers", &self.drivers.len())
202            .field("profiles", &self.profiles.len())
203            .field("actors", &self.actors.len())
204            .field("groups", &self.groups.len())
205            .finish()
206    }
207}
208
209impl PartialEq<Actor> for Actor {
210    fn eq(&self, other: &Actor) -> bool {
211        std::ptr::eq(self, other)
212    }
213}
214
215impl Eq for Actor {}
216
217impl Hash for Actor {
218    fn hash<H: Hasher>(&self, state: &mut H) {
219        let address = self as *const Actor;
220        address.hash(state);
221    }
222}