pub trait ProblemChange<S: PlanningSolution>: Send + Debug {
// Required method
fn apply(&self, score_director: &mut dyn Director<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 - Changes should be idempotent when possible
- Avoid holding references to entities across changes
§Example
use solverforge_solver::realtime::ProblemChange;
use solverforge_scoring::Director;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SoftScore;
#[derive(Clone, Debug)]
struct Employee { id: usize, shift: Option<i32> }
#[derive(Clone, Debug)]
struct Schedule {
employees: Vec<Employee>,
score: Option<SoftScore>,
}
impl PlanningSolution for Schedule {
type Score = SoftScore;
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 Director<Schedule>) {
// Add the new employee
score_director.working_solution_mut().employees.push(Employee {
id: self.employee_id,
shift: None,
});
}
}
/// 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 Director<Schedule>) {
// Remove the employee
let id = self.employee_id;
score_director.working_solution_mut().employees.retain(|e| e.id != id);
}
}