Skip to main content

solverforge_scoring/director/
traits.rs

1// Score director trait definition.
2
3use solverforge_core::domain::{PlanningSolution, SolutionDescriptor};
4
5/// Snapshot of the director's committed score state.
6///
7/// Construction and local-search trial evaluation use this to restore the
8/// wrapped director after speculative scoring.
9#[derive(Debug, PartialEq, Eq)]
10pub struct DirectorScoreState<Sc> {
11    pub solution_score: Option<Sc>,
12    pub committed_score: Option<Sc>,
13    pub initialized: bool,
14}
15
16/* The score director manages solution state and score calculation.
17
18It is responsible for:
19- Maintaining the working solution
20- Calculating scores (incrementally when possible)
21- Notifying about variable changes for incremental updates
22- Providing access to solution metadata via descriptors
23*/
24pub trait Director<S: PlanningSolution>: Send {
25    // Returns a reference to the working solution.
26    fn working_solution(&self) -> &S;
27
28    // Returns a mutable reference to the working solution.
29    fn working_solution_mut(&mut self) -> &mut S;
30
31    // Calculates and returns the current score.
32    fn calculate_score(&mut self) -> S::Score;
33
34    // Returns the solution descriptor for this solution type.
35    fn solution_descriptor(&self) -> &SolutionDescriptor;
36
37    // Clones the working solution.
38    fn clone_working_solution(&self) -> S;
39
40    // Called before a planning variable is changed.
41    fn before_variable_changed(&mut self, descriptor_index: usize, entity_index: usize);
42
43    // Called after a planning variable is changed.
44    fn after_variable_changed(&mut self, descriptor_index: usize, entity_index: usize);
45
46    // Returns the number of entities for a given descriptor index.
47    fn entity_count(&self, descriptor_index: usize) -> Option<usize>;
48
49    // Returns the total number of entities across all collections.
50    fn total_entity_count(&self) -> Option<usize>;
51
52    // Returns true if this score director supports incremental scoring.
53    fn is_incremental(&self) -> bool {
54        false
55    }
56
57    // Snapshots the committed score state so speculative evaluation can roll
58    // back exactly.
59    fn snapshot_score_state(&self) -> DirectorScoreState<S::Score> {
60        let solution_score = self.working_solution().score();
61        DirectorScoreState {
62            solution_score,
63            committed_score: solution_score,
64            initialized: solution_score.is_some(),
65        }
66    }
67
68    // Restores a previously snapshotted committed score state.
69    fn restore_score_state(&mut self, state: DirectorScoreState<S::Score>) {
70        self.working_solution_mut().set_score(state.solution_score);
71    }
72
73    // Resets the score director state.
74    fn reset(&mut self) {}
75
76    /* Registers a typed undo closure.
77
78    Called by moves after applying changes to enable automatic undo.
79    The closure will be called in reverse order during `undo_changes()`.
80
81    Default implementation does nothing (for non-recording directors).
82    */
83    fn register_undo(&mut self, _undo: Box<dyn FnOnce(&mut S) + Send>) {
84        // Default: no-op - only RecordingDirector stores undo closures
85    }
86}