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}