solverforge_cvrp/
helpers.rs1use crate::{ProblemData, VrpSolution};
2
3#[inline]
4pub(crate) fn problem_data_for_entity<S: VrpSolution>(
5 plan: &S,
6 entity_idx: usize,
7) -> Option<&ProblemData> {
8 if entity_idx >= plan.vehicle_count() {
9 return None;
10 }
11 let ptr = plan.vehicle_data_ptr(entity_idx);
12 assert!(
13 !ptr.is_null(),
14 "VrpSolution::vehicle_data_ptr({entity_idx}) returned null for a non-empty fleet"
15 );
16 unsafe { ptr.as_ref() }
19}
20
21pub fn depot_for_entity<S: VrpSolution>(plan: &S, entity_idx: usize) -> usize {
22 problem_data_for_entity(plan, entity_idx).map_or(0, |data| data.depot)
23}
24
25pub fn route_distance<S: VrpSolution>(plan: &S, entity_idx: usize, from: usize, to: usize) -> i64 {
27 problem_data_for_entity(plan, entity_idx).map_or(0, |data| data.distance_matrix[from][to])
28}
29
30pub fn replace_route<S: VrpSolution>(plan: &mut S, entity_idx: usize, route: Vec<usize>) {
34 *plan.vehicle_visits_mut(entity_idx) = route;
35}
36
37pub fn get_route<S: VrpSolution>(plan: &S, entity_idx: usize) -> Vec<usize> {
41 plan.vehicle_visits(entity_idx).to_vec()
42}
43
44pub fn route_feasible<S: VrpSolution>(plan: &S, entity_idx: usize, route: &[usize]) -> bool {
46 if route.is_empty() {
47 return true;
48 }
49 match problem_data_for_entity(plan, entity_idx) {
50 Some(data) => check_capacity_feasible(route, data) && check_time_feasible(route, data),
51 None => true,
52 }
53}
54
55fn check_capacity_feasible(route: &[usize], data: &ProblemData) -> bool {
56 route
57 .iter()
58 .map(|&visit| data.demands[visit] as i64)
59 .sum::<i64>()
60 <= data.capacity
61}
62
63fn check_time_feasible(route: &[usize], data: &ProblemData) -> bool {
64 let mut current_time = data.vehicle_departure_time;
65 let mut prev = data.depot;
66
67 for &visit in route {
68 current_time += data.travel_times[prev][visit];
69
70 let (min_start, max_end) = data.time_windows[visit];
71
72 if current_time < min_start {
73 current_time = min_start;
74 }
75
76 let service_end = current_time + data.service_durations[visit];
77
78 if service_end > max_end {
79 return false;
80 }
81
82 current_time = service_end;
83 prev = visit;
84 }
85
86 true
87}