solverforge_solver/heuristic/move/
dynamic_list_change.rs1use std::borrow::Cow;
2use std::fmt::Debug;
3
4use solverforge_core::domain::{DynamicListVariableSlot, PlanningSolution};
5use solverforge_scoring::Director;
6
7use super::list_kernel::{
8 change_candidate_trace_identity, change_do_move, change_is_doable, change_tabu_signature,
9 change_undo_move, ChangeCoordinates,
10};
11use super::{Move, MoveTabuSignature};
12
13pub struct DynamicListChangeMove<S> {
14 slot: DynamicListVariableSlot<S>,
15 source_entity_index: usize,
16 source_position: usize,
17 dest_entity_index: usize,
18 dest_position: usize,
19 indices: [usize; 2],
20}
21
22impl<S> Debug for DynamicListChangeMove<S> {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.debug_struct("DynamicListChangeMove")
25 .field("source_entity", &self.source_entity_index)
26 .field("source_position", &self.source_position)
27 .field("dest_entity", &self.dest_entity_index)
28 .field("dest_position", &self.dest_position)
29 .field("variable_name", &self.slot.variable_name)
30 .finish()
31 }
32}
33
34impl<S> DynamicListChangeMove<S> {
35 pub fn new(
36 slot: DynamicListVariableSlot<S>,
37 source_entity_index: usize,
38 source_position: usize,
39 dest_entity_index: usize,
40 dest_position: usize,
41 ) -> Self {
42 Self {
43 slot,
44 source_entity_index,
45 source_position,
46 dest_entity_index,
47 dest_position,
48 indices: [source_entity_index, dest_entity_index],
49 }
50 }
51
52 fn is_intra_list(&self) -> bool {
53 self.source_entity_index == self.dest_entity_index
54 }
55
56 pub fn source_entity_index(&self) -> usize {
57 self.source_entity_index
58 }
59
60 pub fn source_position(&self) -> usize {
61 self.source_position
62 }
63
64 pub fn dest_entity_index(&self) -> usize {
65 self.dest_entity_index
66 }
67
68 pub fn dest_position(&self) -> usize {
69 self.dest_position
70 }
71
72 fn coordinates(&self) -> ChangeCoordinates {
73 ChangeCoordinates {
74 source_entity: self.source_entity_index,
75 source_position: self.source_position,
76 destination_entity: self.dest_entity_index,
77 destination_position: self.dest_position,
78 }
79 }
80}
81
82impl<S> Move<S> for DynamicListChangeMove<S>
83where
84 S: PlanningSolution,
85{
86 type Undo = ();
87
88 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
89 change_is_doable(&self.slot, self.coordinates(), score_director)
90 }
91
92 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
93 change_do_move(&self.slot, self.coordinates(), score_director);
94 }
95
96 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
97 change_undo_move(&self.slot, self.coordinates(), score_director);
98 }
99
100 fn descriptor_index(&self) -> usize {
101 self.slot.descriptor_index()
102 }
103
104 fn entity_indices(&self) -> &[usize] {
105 if self.is_intra_list() {
106 &self.indices[0..1]
107 } else {
108 &self.indices
109 }
110 }
111
112 fn variable_name(&self) -> &str {
113 self.slot.variable_name
114 }
115
116 fn telemetry_label(&self) -> &'static str {
117 "dynamic_list_change"
118 }
119
120 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> Cow<'_, MoveTabuSignature> {
121 Cow::Owned(change_tabu_signature(
122 &self.slot,
123 self.coordinates(),
124 score_director,
125 ))
126 }
127
128 fn candidate_trace_identity(&self) -> Option<crate::stats::CandidateTraceIdentity> {
129 Some(change_candidate_trace_identity(
130 &self.slot,
131 self.coordinates(),
132 ))
133 }
134}