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