solverforge_solver/heuristic/move/
list_multi_swap.rs1use std::fmt::Debug;
4
5use smallvec::SmallVec;
6use solverforge_core::domain::PlanningSolution;
7use solverforge_scoring::Director;
8
9use super::list_kernel::{
10 multi_swap_do_move, multi_swap_entity_indices, multi_swap_is_doable, multi_swap_tabu_signature,
11 multi_swap_undo_move, MultiSwapCoordinates, StaticListSwapAccess,
12};
13use super::{Move, MoveTabuSignature};
14
15pub struct ListMultiSwapMove<S, V> {
21 swaps: MultiSwapCoordinates,
22 access: StaticListSwapAccess<S, V>,
23 indices: SmallVec<[usize; 4]>,
24 require_score_improvement: bool,
25}
26
27impl<S, V> Clone for ListMultiSwapMove<S, V> {
28 fn clone(&self) -> Self {
29 Self {
30 swaps: self.swaps.clone(),
31 access: self.access,
32 indices: self.indices.clone(),
33 require_score_improvement: self.require_score_improvement,
34 }
35 }
36}
37
38impl<S, V: Debug> Debug for ListMultiSwapMove<S, V> {
39 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 formatter
41 .debug_struct("ListMultiSwapMove")
42 .field("swaps", &self.swaps)
43 .field("variable_name", &self.access.variable_name)
44 .field("require_score_improvement", &self.require_score_improvement)
45 .finish()
46 }
47}
48
49impl<S, V> ListMultiSwapMove<S, V> {
50 pub fn new(
51 swaps: &[(usize, usize, usize)],
52 list_len: fn(&S, usize) -> usize,
53 list_get: fn(&S, usize, usize) -> Option<V>,
54 list_set: fn(&mut S, usize, usize, V),
55 variable_name: &'static str,
56 descriptor_index: usize,
57 ) -> Self {
58 Self {
59 swaps: swaps.iter().copied().collect(),
60 access: StaticListSwapAccess {
61 list_len,
62 list_get,
63 list_set,
64 variable_name,
65 descriptor_index,
66 },
67 indices: multi_swap_entity_indices(swaps),
68 require_score_improvement: false,
69 }
70 }
71
72 pub fn with_require_score_improvement(mut self, require_score_improvement: bool) -> Self {
73 self.require_score_improvement = require_score_improvement;
74 self
75 }
76
77 pub fn swaps(&self) -> &[(usize, usize, usize)] {
78 &self.swaps
79 }
80}
81
82impl<S, V> Move<S> for ListMultiSwapMove<S, V>
83where
84 S: PlanningSolution,
85 V: Clone + PartialEq + Send + Sync + Debug + 'static,
86{
87 type Undo = ();
88
89 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
90 multi_swap_is_doable(&self.access, &self.swaps, score_director)
91 }
92
93 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
94 multi_swap_do_move(&self.access, &self.swaps, &self.indices, score_director)
95 }
96
97 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
98 multi_swap_undo_move(&self.access, &self.swaps, &self.indices, score_director);
99 }
100
101 fn descriptor_index(&self) -> usize {
102 self.access.descriptor_index
103 }
104
105 fn entity_indices(&self) -> &[usize] {
106 &self.indices
107 }
108
109 fn variable_name(&self) -> &str {
110 self.access.variable_name
111 }
112
113 fn telemetry_label(&self) -> &'static str {
114 "list_multi_swap"
115 }
116
117 fn requires_score_improvement(&self) -> bool {
118 self.require_score_improvement
119 }
120
121 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
122 multi_swap_tabu_signature(&self.access, &self.swaps, &self.indices, score_director)
123 }
124}