Skip to main content

solverforge_solver/heuristic/move/
conflict_repair.rs

1use std::fmt::{self, Debug};
2
3use solverforge_core::domain::PlanningSolution;
4use solverforge_scoring::Director;
5
6use crate::stats::CandidateTraceIdentity;
7
8use super::compound_scalar::{CompoundScalarEdit, CompoundScalarMove};
9use super::{Move, MoveAffectedEntity, MoveTabuSignature};
10
11const CONFLICT_REPAIR_VARIABLE: &str = "conflict_repair";
12
13pub struct ConflictRepairScalarEdit<S> {
14    pub descriptor_index: usize,
15    pub entity_index: usize,
16    pub variable_index: usize,
17    pub variable_name: &'static str,
18    pub to_value: Option<usize>,
19    pub getter: fn(&S, usize, usize) -> Option<usize>,
20    pub setter: fn(&mut S, usize, usize, Option<usize>),
21}
22
23impl<S> Debug for ConflictRepairScalarEdit<S> {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        f.debug_struct("ConflictRepairScalarEdit")
26            .field("descriptor_index", &self.descriptor_index)
27            .field("entity_index", &self.entity_index)
28            .field("variable_index", &self.variable_index)
29            .field("variable_name", &self.variable_name)
30            .field("to_value", &self.to_value)
31            .finish()
32    }
33}
34
35pub struct ConflictRepairMove<S> {
36    compound: CompoundScalarMove<S>,
37}
38
39impl<S> ConflictRepairMove<S> {
40    pub fn new(reason: &'static str, edits: Vec<ConflictRepairScalarEdit<S>>) -> Self {
41        let edits = edits
42            .into_iter()
43            .map(|edit| {
44                CompoundScalarEdit::static_edit(
45                    edit.descriptor_index,
46                    edit.entity_index,
47                    edit.variable_index,
48                    edit.variable_name,
49                    edit.to_value,
50                    edit.getter,
51                    edit.setter,
52                    None,
53                )
54            })
55            .collect();
56        Self {
57            compound: CompoundScalarMove::with_label(reason, CONFLICT_REPAIR_VARIABLE, edits),
58        }
59    }
60}
61
62impl<S> Debug for ConflictRepairMove<S> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        f.debug_tuple("ConflictRepairMove")
65            .field(&self.compound)
66            .finish()
67    }
68}
69
70impl<S> Move<S> for ConflictRepairMove<S>
71where
72    S: PlanningSolution,
73{
74    type Undo = <CompoundScalarMove<S> as Move<S>>::Undo;
75
76    fn is_doable<D: Director<S>>(&self, score_director: &D) -> bool {
77        self.compound.is_doable(score_director)
78    }
79
80    fn do_move<D: Director<S>>(&self, score_director: &mut D) -> Self::Undo {
81        self.compound.do_move(score_director)
82    }
83
84    fn undo_move<D: Director<S>>(&self, score_director: &mut D, undo: Self::Undo) {
85        self.compound.undo_move(score_director, undo);
86    }
87
88    fn descriptor_index(&self) -> usize {
89        self.compound.descriptor_index()
90    }
91
92    fn entity_indices(&self) -> &[usize] {
93        self.compound.entity_indices()
94    }
95
96    fn variable_name(&self) -> &str {
97        self.compound.variable_name()
98    }
99
100    fn telemetry_label(&self) -> &'static str {
101        self.compound.reason()
102    }
103
104    fn tabu_signature<D: Director<S>>(&self, score_director: &D) -> MoveTabuSignature {
105        self.compound.tabu_signature(score_director)
106    }
107
108    fn candidate_trace_identity(&self) -> Option<CandidateTraceIdentity> {
109        self.compound.candidate_trace_identity()
110    }
111
112    fn for_each_affected_entity<V: FnMut(MoveAffectedEntity<'_>)>(&self, visitor: &mut V) {
113        self.compound.for_each_affected_entity(visitor);
114    }
115}