vrp_core/construction/heuristics/
context.rs1#[cfg(test)]
2#[path = "../../../tests/unit/construction/heuristics/context_test.rs"]
3mod context_test;
4
5use crate::construction::enablers::{TotalDistanceTourState, TotalDurationTourState};
6use crate::construction::heuristics::factories::*;
7use crate::models::common::Cost;
8use crate::models::problem::*;
9use crate::models::solution::*;
10use crate::models::GoalContext;
11use crate::models::{Problem, Solution};
12use crate::prelude::ViolationCode;
13use rosomaxa::evolution::TelemetryMetrics;
14use rosomaxa::prelude::*;
15use rustc_hash::FxHasher;
16use std::any::{Any, TypeId};
17use std::collections::{HashMap, HashSet};
18use std::fmt::{Debug, Formatter};
19use std::hash::BuildHasherDefault;
20use std::ops::Deref;
21use std::sync::Arc;
22
23pub struct InsertionContext {
25 pub problem: Arc<Problem>,
27
28 pub solution: SolutionContext,
30
31 pub environment: Arc<Environment>,
33}
34
35impl InsertionContext {
36 pub fn new(problem: Arc<Problem>, environment: Arc<Environment>) -> Self {
38 create_insertion_context(problem, environment)
39 }
40
41 pub fn new_empty(problem: Arc<Problem>, environment: Arc<Environment>) -> Self {
43 create_empty_insertion_context(problem, environment)
44 }
45
46 pub fn new_from_solution(
48 problem: Arc<Problem>,
49 solution: (Solution, Option<Cost>),
50 environment: Arc<Environment>,
51 ) -> Self {
52 let mut ctx = create_insertion_context_from_solution(problem, solution, environment);
53 ctx.restore();
54
55 ctx
56 }
57
58 pub fn get_total_cost(&self) -> Option<Cost> {
62 let get_cost = |costs: &Costs, distance: Float, duration: Float| {
63 costs.fixed
64 + costs.per_distance * distance
65 + costs.per_driving_time.max(costs.per_service_time).max(costs.per_waiting_time) * duration
71 };
72
73 self.solution.routes.iter().try_fold(Cost::default(), |acc, route_ctx| {
74 let actor = &route_ctx.route.actor;
75 let distance = route_ctx.state.get_total_distance();
76 let duration = route_ctx.state.get_total_duration();
77
78 distance.zip(duration).map(|(&distance, &duration)| {
79 acc + get_cost(&actor.vehicle.costs, distance, duration)
80 + get_cost(&actor.driver.costs, distance, duration)
81 })
82 })
83 }
84
85 pub fn restore(&mut self) {
87 self.problem.goal.accept_solution_state(&mut self.solution);
88 self.solution.remove_empty_routes();
89 }
90}
91
92impl HeuristicSolution for InsertionContext {
93 fn fitness(&self) -> impl Iterator<Item = Float> {
94 self.problem.goal.fitness(self)
95 }
96
97 fn deep_copy(&self) -> Self {
98 InsertionContext {
99 problem: self.problem.clone(),
100 solution: self.solution.deep_copy(),
101 environment: self.environment.clone(),
102 }
103 }
104}
105
106impl Debug for InsertionContext {
107 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
108 f.debug_struct(short_type_name::<Self>())
109 .field("problem", &self.problem)
110 .field("solution", &self.solution)
111 .finish_non_exhaustive()
112 }
113}
114
115#[derive(Clone, Debug)]
117pub enum UnassignmentInfo {
118 Unknown,
120 Simple(ViolationCode),
122 Detailed(Vec<(Arc<Actor>, ViolationCode)>),
124}
125
126pub struct SolutionContext {
128 pub required: Vec<Job>,
130
131 pub ignored: Vec<Job>,
133
134 pub unassigned: HashMap<Job, UnassignmentInfo>,
136
137 pub locked: HashSet<Job>,
139
140 pub routes: Vec<RouteContext>,
142
143 pub registry: RegistryContext,
145
146 pub state: SolutionState,
148}
149
150impl SolutionContext {
151 pub fn get_jobs_amount(&self) -> usize {
154 let assigned = self.routes.iter().map(|route_ctx| route_ctx.route().tour.job_count()).sum::<usize>();
155
156 let required = self.required.iter().filter(|job| !self.unassigned.contains_key(*job)).count();
157
158 self.unassigned.len() + required + self.ignored.len() + assigned
159 }
160
161 pub fn keep_routes(&mut self, predicate: &dyn Fn(&RouteContext) -> bool) {
163 let (keep, remove): (Vec<_>, Vec<_>) = self.routes.drain(0..).partition(predicate);
165
166 remove.into_iter().for_each(|route_ctx| {
167 assert!(self.registry.free_route(route_ctx));
168 });
169
170 self.routes = keep;
171 }
172
173 pub(crate) fn remove_empty_routes(&mut self) {
175 self.keep_routes(&|route_ctx| route_ctx.route().tour.has_jobs())
176 }
177
178 pub fn deep_copy(&self) -> Self {
180 Self {
181 required: self.required.clone(),
182 ignored: self.ignored.clone(),
183 unassigned: self.unassigned.clone(),
184 locked: self.locked.clone(),
185 routes: self.routes.iter().map(|rc| rc.deep_copy()).collect(),
186 registry: self.registry.deep_copy(),
187 state: self.state.clone(),
188 }
189 }
190}
191
192impl Debug for SolutionContext {
193 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
194 f.debug_struct(short_type_name::<Self>())
195 .field("required", &self.required.len())
196 .field("locked", &self.locked.len())
197 .field("routes", &self.routes)
198 .field("unassigned", &self.unassigned)
199 .finish_non_exhaustive()
200 }
201}
202
203impl From<InsertionContext> for Solution {
204 fn from(insertion_ctx: InsertionContext) -> Self {
205 (insertion_ctx, None).into()
206 }
207}
208
209impl From<(InsertionContext, Option<TelemetryMetrics>)> for Solution {
210 fn from(value: (InsertionContext, Option<TelemetryMetrics>)) -> Self {
211 let (insertion_ctx, telemetry) = value;
212 let cost = insertion_ctx.get_total_cost().unwrap_or_default();
213 let solution_ctx = insertion_ctx.solution;
214
215 Solution {
216 cost,
217 registry: solution_ctx.registry.resources().deep_copy(),
218 routes: solution_ctx.routes.iter().map(|rc| rc.route.deep_copy()).collect(),
219 unassigned: solution_ctx
220 .unassigned
221 .iter()
222 .map(|(job, code)| (job.clone(), code.clone()))
223 .chain(solution_ctx.required.iter().map(|job| (job.clone(), UnassignmentInfo::Unknown)))
224 .collect(),
225 telemetry,
226 }
227 }
228}
229
230#[derive(Clone, Default)]
232pub struct SolutionState {
233 index: HashMap<TypeId, Arc<dyn Any + Send + Sync>, BuildHasherDefault<FxHasher>>,
234}
235
236impl SolutionState {
237 pub fn get_value<K: 'static, V: Send + Sync + 'static>(&self) -> Option<&V> {
239 self.index.get(&TypeId::of::<K>()).and_then(|any| any.downcast_ref::<V>())
240 }
241 pub fn set_value<K: 'static, V: 'static + Sync + Send>(&mut self, value: V) {
243 self.index.insert(TypeId::of::<K>(), Arc::new(value));
244 }
245}
246
247pub struct RouteContext {
249 route: Route,
250 state: RouteState,
251 cache: RouteCache,
252}
253
254#[derive(Clone)]
258pub struct RouteState {
259 index: HashMap<TypeId, Arc<dyn Any + Send + Sync>, BuildHasherDefault<FxHasher>>,
260}
261
262impl RouteContext {
263 pub fn new(actor: Arc<Actor>) -> Self {
265 let tour = Tour::new(&actor);
266 Self::new_with_state(Route { actor, tour }, RouteState::default())
267 }
268
269 pub fn new_with_state(route: Route, state: RouteState) -> Self {
271 RouteContext { route, state, cache: RouteCache { is_stale: true } }
272 }
273
274 pub fn deep_copy(&self) -> Self {
276 let new_route = Route { actor: self.route.actor.clone(), tour: self.route.tour.deep_copy() };
277 let new_state = self.state.clone();
278
279 RouteContext { route: new_route, state: new_state, cache: RouteCache { is_stale: self.cache.is_stale } }
280 }
281
282 pub fn route(&self) -> &Route {
284 &self.route
285 }
286
287 pub fn state(&self) -> &RouteState {
289 &self.state
290 }
291
292 pub fn as_mut(&mut self) -> (&mut Route, &mut RouteState) {
295 self.mark_stale(true);
296 (&mut self.route, &mut self.state)
297 }
298
299 pub fn route_mut(&mut self) -> &mut Route {
302 self.mark_stale(true);
303 &mut self.route
304 }
305
306 pub fn state_mut(&mut self) -> &mut RouteState {
309 self.mark_stale(true);
310 &mut self.state
311 }
312
313 pub fn is_stale(&self) -> bool {
316 self.cache.is_stale
317 }
318
319 pub(crate) fn mark_stale(&mut self, is_stale: bool) {
321 self.cache.is_stale = is_stale;
322 }
323}
324
325impl PartialEq<RouteContext> for RouteContext {
326 fn eq(&self, other: &RouteContext) -> bool {
327 std::ptr::eq(self.route.actor.deref(), other.route.actor.deref())
328 }
329}
330
331impl Eq for RouteContext {}
332
333impl Debug for RouteContext {
334 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
335 f.debug_struct(short_type_name::<Self>())
336 .field("route", &self.route)
337 .field("is_stale", &self.is_stale())
338 .finish_non_exhaustive()
339 }
340}
341
342impl Default for RouteState {
343 fn default() -> RouteState {
344 RouteState { index: HashMap::with_capacity_and_hasher(4, BuildHasherDefault::<FxHasher>::default()) }
345 }
346}
347
348impl RouteState {
349 pub fn get_tour_state<K: 'static, V: Send + Sync + 'static>(&self) -> Option<&V> {
351 self.index.get(&TypeId::of::<K>()).and_then(|any| any.downcast_ref::<V>())
352 }
353
354 pub fn set_tour_state<K: 'static, V: Send + Sync + 'static>(&mut self, value: V) {
356 self.index.insert(TypeId::of::<K>(), Arc::new(value));
357 }
358
359 pub fn remove_tour_state<K: 'static>(&mut self) -> bool {
362 self.index.remove(&TypeId::of::<K>()).is_some()
363 }
364
365 pub fn get_activity_state<K: 'static, V: Send + Sync + 'static>(&self, activity_idx: usize) -> Option<&V> {
367 self.index
368 .get(&TypeId::of::<K>())
369 .and_then(|s| s.downcast_ref::<Vec<V>>())
370 .and_then(|activity_states| activity_states.get(activity_idx))
371 }
372
373 pub fn get_activity_states<K: 'static, V: Send + Sync + 'static>(&self) -> Option<&Vec<V>> {
375 self.index.get(&TypeId::of::<K>()).and_then(|s| s.downcast_ref::<Vec<V>>())
376 }
377
378 pub fn set_activity_states<K: 'static, V: Send + Sync + 'static>(&mut self, values: Vec<V>) {
380 self.index.insert(TypeId::of::<K>(), Arc::new(values));
381 }
382
383 pub fn clear(&mut self) {
385 self.index.clear();
386 }
387}
388
389struct RouteCache {
390 is_stale: bool,
391}
392
393pub struct RegistryContext {
395 registry: Registry,
396 index: HashMap<Arc<Actor>, Arc<RouteContext>>,
398}
399
400impl RegistryContext {
401 pub fn new(goal: &GoalContext, registry: Registry) -> Self {
403 let index = registry
404 .all()
405 .map(|actor| {
406 let mut route_ctx = RouteContext::new(actor.clone());
407 goal.accept_route_state(&mut route_ctx);
409
410 (actor, Arc::new(route_ctx))
411 })
412 .collect();
413 Self { registry, index }
414 }
415
416 pub fn resources(&self) -> &Registry {
418 &self.registry
419 }
420
421 pub fn next_route(&self) -> impl Iterator<Item = &RouteContext> {
423 self.registry.next().map(move |actor| self.index[&actor].as_ref())
424 }
425
426 pub fn get_route(&mut self, actor: &Arc<Actor>) -> Option<RouteContext> {
430 self.registry.use_actor(actor).then(|| self.index.get(actor).map(|route_ctx| route_ctx.deep_copy())).flatten()
431 }
432
433 pub fn use_route(&mut self, route_ctx: &RouteContext) -> bool {
436 self.registry.use_actor(&route_ctx.route.actor)
437 }
438
439 pub fn free_route(&mut self, route: RouteContext) -> bool {
442 self.registry.free_actor(&route.route.actor)
443 }
444
445 pub fn deep_copy(&self) -> Self {
447 Self {
448 registry: self.registry.deep_copy(),
449 index: self.index.iter().map(|(actor, route_ctx)| (actor.clone(), route_ctx.clone())).collect(),
450 }
451 }
452
453 pub fn deep_slice(&self, filter: impl Fn(&Actor) -> bool) -> Self {
455 let index = self
456 .index
457 .iter()
458 .filter(|(actor, _)| filter(actor.as_ref()))
459 .map(|(actor, route_ctx)| (actor.clone(), route_ctx.clone()))
460 .collect();
461 Self { registry: self.registry.deep_slice(filter), index }
462 }
463}
464
465pub struct ActivityContext<'a> {
467 pub index: usize,
469
470 pub prev: &'a Activity,
472
473 pub target: &'a Activity,
475
476 pub next: Option<&'a Activity>,
478}
479
480pub enum MoveContext<'a> {
482 Route {
484 solution_ctx: &'a SolutionContext,
486 route_ctx: &'a RouteContext,
488 job: &'a Job,
490 },
491 Activity {
493 route_ctx: &'a RouteContext,
495 activity_ctx: &'a ActivityContext<'a>,
497 },
498}
499
500impl<'a> MoveContext<'a> {
501 pub fn route(solution_ctx: &'a SolutionContext, route_ctx: &'a RouteContext, job: &'a Job) -> MoveContext<'a> {
503 MoveContext::Route { solution_ctx, route_ctx, job }
504 }
505
506 pub fn activity(route_ctx: &'a RouteContext, activity_ctx: &'a ActivityContext) -> MoveContext<'a> {
508 MoveContext::Activity { route_ctx, activity_ctx }
509 }
510}