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, 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}