Skip to main content

solverforge_solver/heuristic/move/
dynamic_list_change.rs

1use 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}