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
use crate::format::{JobIndex, UNASSIGNABLE_ROUTE_KEY};
use std::sync::Arc;
use vrp_core::construction::constraints::ConstraintPipeline;
use vrp_core::construction::heuristics::*;
use vrp_core::models::common::{IdDimension, ValueDimension};
use vrp_core::utils::compare_floats;
pub fn get_route_modifier(constraint: Arc<ConstraintPipeline>, job_index: JobIndex) -> RouteModifier {
RouteModifier::new(move |route_ctx: RouteContext| {
let actor = &route_ctx.route.actor;
let vehicle = &actor.vehicle;
let shift_index = vehicle.dimens.get_value::<usize>("shift_index").expect("cannot find shift index");
let vehicle_id = vehicle.dimens.get_id().expect("cannot get vehicle id");
let candidates = (1..)
.map(|idx| format!("{}_dispatch_{}_{}", vehicle_id, shift_index, idx))
.map(|job_id| job_index.get(&job_id))
.take_while(|job| job.is_some())
.collect::<Vec<_>>();
let result = candidates
.iter()
.filter_map(|job| {
job.map(|job| {
evaluate_job_constraint_in_route(job, &constraint, &route_ctx, InsertionPosition::Last, 0., None)
})
.and_then(|result| match result {
InsertionResult::Success(success) => Some(success),
_ => None,
})
})
.min_by(|a, b| compare_floats(a.cost, b.cost));
if let Some(success) = result {
let mut route_ctx = success.context;
let route = route_ctx.route_mut();
success.activities.into_iter().for_each(|(activity, index)| {
route.tour.insert_at(activity, index + 1);
});
constraint.accept_route_state(&mut route_ctx);
route_ctx
} else {
let mut route_ctx = route_ctx;
if !candidates.is_empty() {
route_ctx.state_mut().put_route_state(UNASSIGNABLE_ROUTE_KEY, true);
}
route_ctx
}
})
}