ProblemChange

Trait ProblemChange 

Source
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§

Source

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.

Implementors§

Source§

impl<S, F> ProblemChange<S> for ClosureProblemChange<S, F>
where S: PlanningSolution, F: Fn(&mut dyn ScoreDirector<S>) + Send,