use solverforge_core::domain::PlanningSolution;
use solverforge_scoring::Director;
use crate::heuristic::r#move::Move;
use super::solver::{PendingControl, ProgressCallback};
use super::{PhaseScope, SolverScope};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum StepControlPolicy {
ObserveConfigLimits,
CompleteMandatoryConstruction,
}
impl StepControlPolicy {
pub(crate) fn for_required_construction(required_only: bool) -> Self {
if required_only {
Self::CompleteMandatoryConstruction
} else {
Self::ObserveConfigLimits
}
}
pub(crate) fn should_terminate_construction<S, D, ProgressCb>(
self,
solver_scope: &mut SolverScope<'_, S, D, ProgressCb>,
) -> bool
where
S: PlanningSolution,
D: Director<S>,
ProgressCb: ProgressCallback<S>,
{
match self {
Self::ObserveConfigLimits => solver_scope.should_terminate_construction(),
Self::CompleteMandatoryConstruction => {
solver_scope.should_interrupt_mandatory_construction()
}
}
}
}
pub struct StepScope<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb = ()> {
phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
step_index: u64,
step_score: Option<S::Score>,
control_policy: StepControlPolicy,
control_polling_required: bool,
progress_polling_required: bool,
}
impl<'t, 'a, 'b, S: PlanningSolution, D: Director<S>, BestCb: ProgressCallback<S>>
StepScope<'t, 'a, 'b, S, D, BestCb>
{
pub fn new(phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>) -> Self {
Self::new_with_control_policy(phase_scope, StepControlPolicy::ObserveConfigLimits)
}
pub(crate) fn new_with_control_policy(
phase_scope: &'a mut PhaseScope<'t, 'b, S, D, BestCb>,
control_policy: StepControlPolicy,
) -> Self {
let step_index = phase_scope.step_count();
let control_polling_required = match control_policy {
StepControlPolicy::ObserveConfigLimits => {
phase_scope.solver_scope().config_control_polling_required()
}
StepControlPolicy::CompleteMandatoryConstruction => phase_scope
.solver_scope()
.mandatory_control_polling_required(),
};
Self {
phase_scope,
step_index,
step_score: None,
control_policy,
control_polling_required,
progress_polling_required: BestCb::PUBLISHES_PROGRESS
|| tracing::enabled!(tracing::Level::DEBUG),
}
}
pub fn step_index(&self) -> u64 {
self.step_index
}
pub fn step_score(&self) -> Option<&S::Score> {
self.step_score.as_ref()
}
pub(crate) fn control_policy(&self) -> StepControlPolicy {
self.control_policy
}
pub(crate) fn pending_control(&self) -> PendingControl {
if !self.control_polling_required {
return PendingControl::Continue;
}
match self.control_policy {
StepControlPolicy::ObserveConfigLimits => {
self.phase_scope.solver_scope().pending_control()
}
StepControlPolicy::CompleteMandatoryConstruction => self
.phase_scope
.solver_scope()
.mandatory_construction_pending_control(),
}
}
pub(crate) fn progress_polling_required(&self) -> bool {
self.progress_polling_required
}
pub fn set_step_score(&mut self, score: S::Score)
where
S::Score: Copy,
{
self.phase_scope.solver_scope_mut().set_current_score(score);
self.phase_scope
.solver_scope_mut()
.observe_phase_step_score(score);
self.step_score = Some(score);
}
pub fn complete(&mut self) {
self.phase_scope.increment_step_count();
self.phase_scope.solver_scope_mut().pause_if_requested();
self.phase_scope.report_progress_if_due();
}
pub fn phase_scope(&self) -> &PhaseScope<'t, 'b, S, D, BestCb> {
self.phase_scope
}
pub fn phase_scope_mut(&mut self) -> &mut PhaseScope<'t, 'b, S, D, BestCb> {
self.phase_scope
}
pub fn score_director(&self) -> &D {
self.phase_scope.score_director()
}
pub(crate) fn score_director_mut(&mut self) -> &mut D {
self.phase_scope.score_director_mut()
}
pub fn mutate<T, F>(&mut self, mutate: F) -> T
where
F: FnOnce(&mut D) -> T,
{
self.phase_scope.mutate(mutate)
}
pub(crate) fn apply_committed_move<M>(&mut self, mov: &M)
where
M: Move<S>,
{
self.phase_scope
.solver_scope_mut()
.apply_committed_move(mov);
}
pub(crate) fn apply_committed_change<F>(&mut self, change: F)
where
F: FnOnce(&mut D),
{
self.phase_scope
.solver_scope_mut()
.apply_committed_change(change);
}
pub fn calculate_score(&mut self) -> S::Score {
self.phase_scope.calculate_score()
}
}