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