1use std::fmt;
2use std::marker::PhantomData;
3
4use solverforge_core::domain::PlanningSolution;
5
6use crate::heuristic::selector::nearby_list_change::CrossEntityDistanceMeter;
7use crate::scope::{ProgressCallback, SolverScope};
8
9#[path = "runtime/compiler/mod.rs"]
12pub(crate) mod compiler;
13#[path = "runtime/provider_cursor.rs"]
14pub(crate) mod provider_cursor;
15
16#[cfg(test)]
17#[path = "runtime/provider_cursor_tests.rs"]
18mod provider_cursor_tests;
19
20pub struct ListVariableMetadata<S, DM, IDM> {
21 pub cross_distance_meter: DM,
22 pub intra_distance_meter: IDM,
23 pub route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
24 pub route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
25 pub route_depot_fn: Option<fn(&S, usize) -> usize>,
26 pub route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
27 pub route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
28 pub savings_depot_fn: Option<fn(&S, usize) -> usize>,
29 pub savings_metric_class_fn: Option<fn(&S, usize) -> usize>,
30 pub savings_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
31 pub savings_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
32 pub element_owner_fn: Option<fn(&S, &usize) -> Option<usize>>,
33 _phantom: PhantomData<fn() -> S>,
34}
35
36pub trait ListVariableEntity<S> {
37 type CrossDistanceMeter: CrossEntityDistanceMeter<S> + Clone + fmt::Debug;
38 type IntraDistanceMeter: CrossEntityDistanceMeter<S> + Clone + fmt::Debug + 'static;
39
40 const HAS_LIST_VARIABLE: bool;
41 const LIST_VARIABLE_NAME: &'static str;
42 const LIST_ELEMENT_SOURCE: Option<&'static str>;
43
44 fn list_field(entity: &Self) -> &[usize];
45 fn list_field_mut(entity: &mut Self) -> &mut Vec<usize>;
46 fn list_metadata() -> ListVariableMetadata<S, Self::CrossDistanceMeter, Self::IntraDistanceMeter>;
47}
48
49impl<S, DM, IDM> ListVariableMetadata<S, DM, IDM> {
50 #[allow(clippy::too_many_arguments)]
51 pub fn new(
52 cross_distance_meter: DM,
53 intra_distance_meter: IDM,
54 route_get_fn: Option<fn(&S, usize) -> Vec<usize>>,
55 route_set_fn: Option<fn(&mut S, usize, Vec<usize>)>,
56 route_depot_fn: Option<fn(&S, usize) -> usize>,
57 route_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
58 route_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
59 savings_depot_fn: Option<fn(&S, usize) -> usize>,
60 savings_metric_class_fn: Option<fn(&S, usize) -> usize>,
61 savings_distance_fn: Option<fn(&S, usize, usize, usize) -> i64>,
62 savings_feasible_fn: Option<fn(&S, usize, &[usize]) -> bool>,
63 ) -> Self {
64 Self {
65 cross_distance_meter,
66 intra_distance_meter,
67 route_get_fn,
68 route_set_fn,
69 route_depot_fn,
70 route_distance_fn,
71 route_feasible_fn,
72 savings_depot_fn,
73 savings_metric_class_fn,
74 savings_distance_fn,
75 savings_feasible_fn,
76 element_owner_fn: None,
77 _phantom: PhantomData,
78 }
79 }
80
81 pub fn with_element_owner_fn(
82 mut self,
83 element_owner_fn: Option<fn(&S, &usize) -> Option<usize>>,
84 ) -> Self {
85 self.element_owner_fn = element_owner_fn;
86 self
87 }
88}
89
90pub(crate) fn finalize_noop_construction<S, D, ProgressCb>(
91 solver_scope: &mut SolverScope<'_, S, D, ProgressCb>,
92) where
93 S: PlanningSolution,
94 D: solverforge_scoring::Director<S>,
95 ProgressCb: ProgressCallback<S>,
96{
97 let had_best = solver_scope.best_score().is_some();
98 solver_scope.update_best_solution();
99 if had_best {
100 solver_scope.promote_current_solution_on_score_tie();
101 }
102}