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 let ptr = plan.vehicle_data_ptr(entity_idx);
9 assert!(
10 !ptr.is_null(),
11 "VrpSolution::vehicle_data_ptr({entity_idx}) returned null for a non-empty fleet"
12 );
13 unsafe { ptr.as_ref() }
16}
17
18#[inline]
19fn first_problem_data<S: VrpSolution>(plan: &S) -> Option<&ProblemData> {
20 if plan.vehicle_count() == 0 {
21 return None;
22 }
23 problem_data_for_entity(plan, 0)
24}
25
26pub fn distance<S: VrpSolution>(plan: &S, i: usize, j: usize) -> i64 {
28 first_problem_data(plan).map_or(0, |data| data.distance_matrix[i][j])
29}
30
31pub fn depot_for_entity<S: VrpSolution>(plan: &S, _entity_idx: usize) -> usize {
32 first_problem_data(plan).map_or(0, |data| data.depot)
33}
34
35pub fn depot_for_cw<S: VrpSolution>(plan: &S) -> usize {
36 first_problem_data(plan).map_or(0, |data| data.depot)
37}
38
39pub fn element_load<S: VrpSolution>(plan: &S, elem: usize) -> i64 {
40 first_problem_data(plan).map_or(0, |data| data.demands[elem] as i64)
41}
42
43pub fn capacity<S: VrpSolution>(plan: &S) -> i64 {
44 first_problem_data(plan).map_or(i64::MAX, |data| data.capacity)
45}
46
47pub fn replace_route<S: VrpSolution>(plan: &mut S, entity_idx: usize, route: Vec<usize>) {
51 *plan.vehicle_visits_mut(entity_idx) = route;
52}
53
54pub fn get_route<S: VrpSolution>(plan: &S, entity_idx: usize) -> Vec<usize> {
58 plan.vehicle_visits(entity_idx).to_vec()
59}
60
61pub fn is_time_feasible<S: VrpSolution>(plan: &S, route: &[usize]) -> bool {
63 if route.is_empty() {
64 return true;
65 }
66 match first_problem_data(plan) {
67 Some(data) => check_time_feasible(route, data),
68 None => true,
69 }
70}
71
72pub fn is_kopt_feasible<S: VrpSolution>(plan: &S, _entity_idx: usize, route: &[usize]) -> bool {
75 is_time_feasible(plan, route)
76}
77
78fn check_time_feasible(route: &[usize], data: &ProblemData) -> bool {
79 let mut current_time = data.vehicle_departure_time;
80 let mut prev = data.depot;
81
82 for &visit in route {
83 current_time += data.travel_times[prev][visit];
84
85 let (min_start, max_end) = data.time_windows[visit];
86
87 if current_time < min_start {
88 current_time = min_start;
89 }
90
91 let service_end = current_time + data.service_durations[visit];
92
93 if service_end > max_end {
94 return false;
95 }
96
97 current_time = service_end;
98 prev = visit;
99 }
100
101 true
102}