Skip to main content

solverforge_solver/heuristic/move/
conflict_repair.rs

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