solverforge-solver 0.8.3

Solver engine for SolverForge
Documentation
use solverforge_core::domain::PlanningSolution;
use solverforge_scoring::Director;

use crate::heuristic::r#move::MoveArena;
use crate::scope::{PendingControl, ProgressCallback, StepScope};

pub(crate) const GENERATION_POLL_INTERVAL: usize = 256;
pub(crate) const EVALUATION_POLL_INTERVAL: usize = 64;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum StepInterrupt {
    Restart,
    TerminatePhase,
}

pub(crate) fn append_interruptibly<'t, 'a, 'b, S, D, ProgressCb, M, I>(
    step_scope: &StepScope<'t, 'a, 'b, S, D, ProgressCb>,
    arena: &mut MoveArena<M>,
    iter: I,
) -> bool
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
    I: IntoIterator<Item = M>,
{
    if has_pending_control(step_scope) {
        return true;
    }

    for (generated, mov) in iter.into_iter().enumerate() {
        if generated != 0
            && generated.is_multiple_of(GENERATION_POLL_INTERVAL)
            && has_pending_control(step_scope)
        {
            return true;
        }
        arena.push(mov);
    }

    has_pending_control(step_scope)
}

pub(crate) fn should_interrupt_evaluation<'t, 'a, 'b, S, D, ProgressCb>(
    step_scope: &StepScope<'t, 'a, 'b, S, D, ProgressCb>,
    evaluated: usize,
) -> bool
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
{
    evaluated != 0
        && evaluated.is_multiple_of(EVALUATION_POLL_INTERVAL)
        && has_pending_control(step_scope)
}

pub(crate) fn settle_search_interrupt<'t, 'a, 'b, S, D, ProgressCb>(
    step_scope: &mut StepScope<'t, 'a, 'b, S, D, ProgressCb>,
) -> StepInterrupt
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
{
    if step_scope
        .phase_scope_mut()
        .solver_scope_mut()
        .should_terminate()
    {
        StepInterrupt::TerminatePhase
    } else {
        StepInterrupt::Restart
    }
}

pub(crate) fn settle_construction_interrupt<'t, 'a, 'b, S, D, ProgressCb>(
    step_scope: &mut StepScope<'t, 'a, 'b, S, D, ProgressCb>,
) -> StepInterrupt
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
{
    if step_scope
        .phase_scope_mut()
        .solver_scope_mut()
        .should_terminate_construction()
    {
        StepInterrupt::TerminatePhase
    } else {
        StepInterrupt::Restart
    }
}

fn has_pending_control<'t, 'a, 'b, S, D, ProgressCb>(
    step_scope: &StepScope<'t, 'a, 'b, S, D, ProgressCb>,
) -> bool
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
{
    !matches!(
        step_scope.phase_scope().solver_scope().pending_control(),
        PendingControl::Continue
    )
}