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, ChangeValueTransfer,
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> Clone for DynamicListChangeMove<S> {
22 fn clone(&self) -> Self {
23 Self {
24 slot: self.slot.clone(),
25 source_entity_index: self.source_entity_index,
26 source_position: self.source_position,
27 dest_entity_index: self.dest_entity_index,
28 dest_position: self.dest_position,
29 indices: self.indices,
30 }
31 }
32}
33
34impl<S> Debug for DynamicListChangeMove<S> {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 f.debug_struct("DynamicListChangeMove")
37 .field("source_entity", &self.source_entity_index)
38 .field("source_position", &self.source_position)
39 .field("dest_entity", &self.dest_entity_index)
40 .field("dest_position", &self.dest_position)
41 .field("variable_name", &self.slot.variable_name)
42 .finish()
43 }
44}
45
46impl<S> DynamicListChangeMove<S> {
47 pub fn new(
48 slot: DynamicListVariableSlot<S>,
49 source_entity_index: usize,
50 source_position: usize,
51 dest_entity_index: usize,
52 dest_position: usize,
53 ) -> Self {
54 Self {
55 slot,
56 source_entity_index,
57 source_position,
58 dest_entity_index,
59 dest_position,
60 indices: [source_entity_index, dest_entity_index],
61 }
62 }
63
64 fn is_intra_list(&self) -> bool {
65 self.source_entity_index == self.dest_entity_index
66 }
67
68 pub fn source_entity_index(&self) -> usize {
69 self.source_entity_index
70 }
71
72 pub fn source_position(&self) -> usize {
73 self.source_position
74 }
75
76 pub fn dest_entity_index(&self) -> usize {
77 self.dest_entity_index
78 }
79
80 pub fn dest_position(&self) -> usize {
81 self.dest_position
82 }
83
84 fn coordinates(&self) -> ChangeCoordinates {
85 ChangeCoordinates {
86 source_entity: self.source_entity_index,
87 source_position: self.source_position,
88 destination_entity: self.dest_entity_index,
89 destination_position: self.dest_position,
90 }
91 }
92}
93
94impl<S> Move<S> for DynamicListChangeMove<S>
95where
96 S: PlanningSolution,
97{
98 type Undo = ();
99
100 fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
101 change_is_doable(&self.slot, self.coordinates(), score_director)
102 }
103
104 fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
105 change_do_move(
106 &self.slot,
107 self.coordinates(),
108 ChangeValueTransfer::MoveIntoInsert,
109 score_director,
110 );
111 }
112
113 fn undo_move<D: Director<S>>(&self, score_director: &mut D, (): Self::Undo) {
114 change_undo_move(&self.slot, self.coordinates(), score_director);
115 }
116
117 fn descriptor_index(&self) -> usize {
118 self.slot.descriptor_index()
119 }
120
121 fn entity_indices(&self) -> &[usize] {
122 if self.is_intra_list() {
123 &self.indices[0..1]
124 } else {
125 &self.indices
126 }
127 }
128
129 fn variable_name(&self) -> &str {
130 self.slot.variable_name
131 }
132
133 fn telemetry_label(&self) -> &'static str {
134 "dynamic_list_change"
135 }
136
137 fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
138 change_tabu_signature(&self.slot, self.coordinates(), score_director)
139 }
140
141 fn candidate_trace_identity(&self) -> Option<crate::stats::CandidateTraceIdentity> {
142 Some(change_candidate_trace_identity(
143 &self.slot,
144 self.coordinates(),
145 ))
146 }
147}