pub trait ProblemChange<S: PlanningSolution>: Send + Debug {
// Required method
fn apply(&self, score_director: &mut dyn ScoreDirector<S>);
}Expand description
A change to the problem that can be applied during solving.
Problem changes allow modifying the solution while the solver is running. Changes are queued and processed at step boundaries to maintain consistency.
§Implementation Notes
When implementing ProblemChange:
- Use
score_director.working_solution_mut()to access and modify the solution - Call
score_director.trigger_variable_listeners()after modifications - Changes should be idempotent when possible
- Avoid holding references to entities across changes
§Example
use solverforge_solver::realtime::ProblemChange;
use solverforge_scoring::ScoreDirector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
#[derive(Clone, Debug)]
struct Employee { id: usize, shift: Option<i32> }
#[derive(Clone, Debug)]
struct Schedule {
employees: Vec<Employee>,
score: Option<SimpleScore>,
}
impl PlanningSolution for Schedule {
type Score = SimpleScore;
fn score(&self) -> Option<Self::Score> { self.score }
fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}
/// Adds a new employee to the schedule.
#[derive(Debug)]
struct AddEmployee {
employee_id: usize,
}
impl ProblemChange<Schedule> for AddEmployee {
fn apply(&self, score_director: &mut dyn ScoreDirector<Schedule>) {
// Add the new employee
score_director.working_solution_mut().employees.push(Employee {
id: self.employee_id,
shift: None,
});
// Notify the solver of the change
score_director.trigger_variable_listeners();
}
}
/// Removes an employee from the schedule.
#[derive(Debug)]
struct RemoveEmployee {
employee_id: usize,
}
impl ProblemChange<Schedule> for RemoveEmployee {
fn apply(&self, score_director: &mut dyn ScoreDirector<Schedule>) {
// Remove the employee
let id = self.employee_id;
score_director.working_solution_mut().employees.retain(|e| e.id != id);
// Notify the solver of the change
score_director.trigger_variable_listeners();
}
}Required Methods§
Sourcefn apply(&self, score_director: &mut dyn ScoreDirector<S>)
fn apply(&self, score_director: &mut dyn ScoreDirector<S>)
Applies this change to the working solution.
This method is called by the solver at a safe point (between steps).
Access the working solution via score_director.working_solution_mut().
After making changes, call score_director.trigger_variable_listeners()
to ensure shadow variables and constraints are updated.