vrp_core/solver/search/local/
mod.rs1use crate::construction::heuristics::*;
4use crate::solver::RefinementContext;
5use rosomaxa::prelude::*;
6use std::cmp::Ordering;
7use std::sync::Arc;
8
9mod exchange_inter_route;
10pub use self::exchange_inter_route::*;
11
12mod exchange_intra_route;
13pub use self::exchange_intra_route::*;
14
15mod exchange_sequence;
16pub use self::exchange_sequence::*;
17
18mod exchange_swap_star;
19pub use self::exchange_swap_star::*;
20
21mod reschedule_departure;
22pub use self::reschedule_departure::*;
23
24pub trait LocalOperator: Send + Sync {
26 fn explore(&self, refinement_ctx: &RefinementContext, insertion_ctx: &InsertionContext)
29 -> Option<InsertionContext>;
30}
31
32pub struct CompositeLocalOperator {
34 operators: Vec<Arc<dyn LocalOperator>>,
35 weights: Vec<usize>,
36 times: (i32, i32),
37}
38
39impl CompositeLocalOperator {
40 pub fn new(operators: Vec<(Arc<dyn LocalOperator>, usize)>, min: usize, max: usize) -> Self {
42 let weights = operators.iter().map(|(_, weight)| *weight).collect();
43 let operators = operators.into_iter().map(|(operator, _)| operator).collect();
44
45 Self { operators, weights, times: (min as i32, max as i32) }
46 }
47}
48
49impl LocalOperator for CompositeLocalOperator {
50 fn explore(
51 &self,
52 refinement_ctx: &RefinementContext,
53 insertion_ctx: &InsertionContext,
54 ) -> Option<InsertionContext> {
55 let random = insertion_ctx.environment.random.as_ref();
56 let times = random.uniform_int(self.times.0, self.times.1);
57
58 let mut old_result = insertion_ctx.deep_copy();
59
60 for _ in 0..times {
61 let index = random.weighted(self.weights.as_slice());
62 let new_result = self.operators.get(index).unwrap().explore(refinement_ctx, &old_result);
63
64 if let Some(new_result) = new_result {
65 if refinement_ctx.problem.goal.total_order(insertion_ctx, &new_result) == Ordering::Greater {
66 return Some(new_result);
67 } else {
68 old_result = new_result;
69 }
70 }
71 }
72
73 Some(old_result)
74 }
75}
76
77fn apply_insertion_with_route(insertion_ctx: &mut InsertionContext, result: (InsertionSuccess, Option<RouteContext>)) {
79 let (success, route_ctx) = result;
80
81 if let Some(route_ctx) = route_ctx {
82 debug_assert!(success.actor == route_ctx.route().actor);
83
84 let route_index = insertion_ctx
85 .solution
86 .routes
87 .iter()
88 .position(|route_ctx| route_ctx.route().actor == success.actor)
89 .unwrap();
90
91 insertion_ctx.solution.routes[route_index] = route_ctx;
93 }
94
95 apply_insertion_success(insertion_ctx, success)
96}