solverforge-solver 0.15.0

Solver engine for SolverForge
Documentation
use std::fmt::{self, Debug};
use std::marker::PhantomData;

use solverforge_config::PartitionedSearchConfig;
use solverforge_core::domain::PlanningSolution;
use solverforge_scoring::Director;

use crate::heuristic::r#move::Move;
use crate::heuristic::MoveSelector;
use crate::phase::localsearch::{Acceptor, LocalSearchForager, LocalSearchPhase};
use crate::phase::partitioned::{ChildPhases, PartitionedSearchPhase, SolutionPartitioner};
use crate::phase::Phase;
use crate::scope::{ProgressCallback, SolverScope};

use super::SearchContext;

pub trait CustomSearchPhase<S>: Debug + Send
where
    S: PlanningSolution,
{
    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
    where
        D: Director<S>,
        ProgressCb: ProgressCallback<S>;

    fn phase_type_name(&self) -> &'static str {
        "CustomSearchPhase"
    }
}

impl<S, M, MS, A, Fo> CustomSearchPhase<S> for LocalSearchPhase<S, M, MS, A, Fo>
where
    S: PlanningSolution,
    M: Move<S>,
    MS: MoveSelector<S, M> + Debug,
    A: Acceptor<S> + Debug,
    Fo: LocalSearchForager<S, M> + Debug,
{
    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
    where
        D: Director<S>,
        ProgressCb: ProgressCallback<S>,
    {
        Phase::solve(self, solver_scope);
    }

    fn phase_type_name(&self) -> &'static str {
        "LocalSearchPhase"
    }
}

impl<S, PD, Part, SDF, PF, CP> CustomSearchPhase<S>
    for PartitionedSearchPhase<S, PD, Part, SDF, PF, CP>
where
    S: PlanningSolution + 'static,
    PD: Director<S> + 'static,
    Part: SolutionPartitioner<S>,
    SDF: Fn(S) -> PD + Send + Sync,
    PF: Fn() -> CP + Send + Sync,
    CP: ChildPhases<S, PD> + Send,
{
    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
    where
        D: Director<S>,
        ProgressCb: ProgressCallback<S>,
    {
        Phase::solve(self, solver_scope);
    }

    fn phase_type_name(&self) -> &'static str {
        "PartitionedSearch"
    }
}

pub trait CustomPhaseRegistry<S, V, DM, IDM>
where
    S: PlanningSolution,
{
    type Phase: CustomSearchPhase<S>;

    fn contains(&self, name: &str) -> bool;

    fn build_named(
        &self,
        name: &str,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase>;

    fn contains_partitioned(&self, name: &str) -> bool;

    fn build_partitioned_named(
        &self,
        name: &str,
        config: &PartitionedSearchConfig,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase>;
}

pub struct NoCustomPhases;

impl<S, V, DM, IDM> CustomPhaseRegistry<S, V, DM, IDM> for NoCustomPhases
where
    S: PlanningSolution,
{
    type Phase = NoCustomPhase;

    fn contains(&self, _name: &str) -> bool {
        false
    }

    fn build_named(
        &self,
        _name: &str,
        _context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        None
    }

    fn contains_partitioned(&self, _name: &str) -> bool {
        false
    }

    fn build_partitioned_named(
        &self,
        _name: &str,
        _config: &PartitionedSearchConfig,
        _context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        None
    }
}

#[derive(Clone, Copy)]
pub enum NoCustomPhase {}

impl Debug for NoCustomPhase {
    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {}
    }
}

impl<S> CustomSearchPhase<S> for NoCustomPhase
where
    S: PlanningSolution,
{
    fn solve<D, ProgressCb>(&mut self, _solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
    where
        D: Director<S>,
        ProgressCb: ProgressCallback<S>,
    {
        match *self {}
    }

    fn phase_type_name(&self) -> &'static str {
        match *self {}
    }
}

impl<S, D, ProgressCb> Phase<S, D, ProgressCb> for NoCustomPhase
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
{
    fn solve(&mut self, _solver_scope: &mut SolverScope<'_, S, D, ProgressCb>) {
        match *self {}
    }

    fn phase_type_name(&self) -> &'static str {
        match *self {}
    }
}

pub struct CustomPhaseNode<Previous, Builder, Phase> {
    previous: Previous,
    name: &'static str,
    builder: Builder,
    _marker: PhantomData<fn() -> Phase>,
}

pub struct PartitionedPhaseNode<Previous, Builder, Phase> {
    previous: Previous,
    name: &'static str,
    builder: Builder,
    _marker: PhantomData<fn() -> Phase>,
}

impl<Previous, Builder, Phase> PartitionedPhaseNode<Previous, Builder, Phase> {
    pub fn new(previous: Previous, name: &'static str, builder: Builder) -> Self {
        Self {
            previous,
            name,
            builder,
            _marker: PhantomData,
        }
    }
}

impl<Previous, Builder, Phase> CustomPhaseNode<Previous, Builder, Phase> {
    pub fn new(previous: Previous, name: &'static str, builder: Builder) -> Self {
        Self {
            previous,
            name,
            builder,
            _marker: PhantomData,
        }
    }
}

pub enum CustomPhaseUnion<PreviousPhase, CurrentPhase> {
    Previous(PreviousPhase),
    Current(CurrentPhase),
}

impl<PreviousPhase: Debug, CurrentPhase: Debug> Debug
    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Previous(phase) => f.debug_tuple("CustomPhase::Previous").field(phase).finish(),
            Self::Current(phase) => f.debug_tuple("CustomPhase::Current").field(phase).finish(),
        }
    }
}

impl<S, PreviousPhase, CurrentPhase> CustomSearchPhase<S>
    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
where
    S: PlanningSolution,
    PreviousPhase: CustomSearchPhase<S>,
    CurrentPhase: CustomSearchPhase<S>,
{
    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
    where
        D: Director<S>,
        ProgressCb: ProgressCallback<S>,
    {
        match self {
            Self::Previous(phase) => phase.solve(solver_scope),
            Self::Current(phase) => phase.solve(solver_scope),
        }
    }

    fn phase_type_name(&self) -> &'static str {
        "CustomPhase"
    }
}

impl<S, D, ProgressCb, PreviousPhase, CurrentPhase> Phase<S, D, ProgressCb>
    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
where
    S: PlanningSolution,
    D: Director<S>,
    ProgressCb: ProgressCallback<S>,
    PreviousPhase: CustomSearchPhase<S>,
    CurrentPhase: CustomSearchPhase<S>,
{
    fn solve(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>) {
        CustomSearchPhase::solve(self, solver_scope);
    }

    fn phase_type_name(&self) -> &'static str {
        CustomSearchPhase::<S>::phase_type_name(self)
    }
}

impl<S, V, DM, IDM, Previous, Builder, CurrentPhase> CustomPhaseRegistry<S, V, DM, IDM>
    for CustomPhaseNode<Previous, Builder, CurrentPhase>
where
    S: PlanningSolution,
    Previous: CustomPhaseRegistry<S, V, DM, IDM>,
    Builder: Fn(&SearchContext<S, V, DM, IDM>) -> CurrentPhase,
    CurrentPhase: CustomSearchPhase<S>,
{
    type Phase = CustomPhaseUnion<Previous::Phase, CurrentPhase>;

    fn contains(&self, name: &str) -> bool {
        self.name == name || self.previous.contains(name)
    }

    fn build_named(
        &self,
        name: &str,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        if self.name == name {
            return Some(CustomPhaseUnion::Current((self.builder)(context)));
        }
        self.previous
            .build_named(name, context)
            .map(CustomPhaseUnion::Previous)
    }

    fn contains_partitioned(&self, name: &str) -> bool {
        self.previous.contains_partitioned(name)
    }

    fn build_partitioned_named(
        &self,
        name: &str,
        config: &PartitionedSearchConfig,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        self.previous
            .build_partitioned_named(name, config, context)
            .map(CustomPhaseUnion::Previous)
    }
}

impl<S, V, DM, IDM, Previous, Builder, CurrentPhase> CustomPhaseRegistry<S, V, DM, IDM>
    for PartitionedPhaseNode<Previous, Builder, CurrentPhase>
where
    S: PlanningSolution,
    Previous: CustomPhaseRegistry<S, V, DM, IDM>,
    Builder: Fn(&SearchContext<S, V, DM, IDM>, &PartitionedSearchConfig) -> CurrentPhase,
    CurrentPhase: CustomSearchPhase<S>,
{
    type Phase = CustomPhaseUnion<Previous::Phase, CurrentPhase>;

    fn contains(&self, name: &str) -> bool {
        self.previous.contains(name)
    }

    fn build_named(
        &self,
        name: &str,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        self.previous
            .build_named(name, context)
            .map(CustomPhaseUnion::Previous)
    }

    fn contains_partitioned(&self, name: &str) -> bool {
        self.name == name || self.previous.contains_partitioned(name)
    }

    fn build_partitioned_named(
        &self,
        name: &str,
        config: &PartitionedSearchConfig,
        context: &SearchContext<S, V, DM, IDM>,
    ) -> Option<Self::Phase> {
        if self.name == name {
            return Some(CustomPhaseUnion::Current((self.builder)(context, config)));
        }
        self.previous
            .build_partitioned_named(name, config, context)
            .map(CustomPhaseUnion::Previous)
    }
}