solverforge-solver 0.11.1

Solver engine for SolverForge
Documentation
pub enum ScalarLeafSelector<S> {
    Change(ScalarChangeSelector<S>),
    Swap(ScalarSwapSelector<S>),
    NearbyChange(NearbyChangeLeafSelector<S>),
    NearbySwap(NearbySwapLeafSelector<S>),
    PillarChange(PillarChangeLeafSelector<S>),
    PillarSwap(PillarSwapLeafSelector<S>),
    RuinRecreate(RuinRecreateLeafSelector<S>),
}

fn wrap_scalar_change_move<S>(mov: ChangeMove<S, usize>) -> ScalarMoveUnion<S, usize>
where
    S: PlanningSolution + 'static,
{
    ScalarMoveUnion::Change(mov)
}

pub enum ScalarLeafCursor<'a, S>
where
    S: PlanningSolution + 'static,
{
    Change(
        MappedMoveCursor<
            S,
            ChangeMove<S, usize>,
            ScalarMoveUnion<S, usize>,
            <ScalarChangeSelector<S> as MoveSelector<S, ChangeMove<S, usize>>>::Cursor<'a>,
            fn(ChangeMove<S, usize>) -> ScalarMoveUnion<S, usize>,
        >,
    ),
    Direct(ArenaMoveCursor<S, ScalarMoveUnion<S, usize>>),
}

impl<S> MoveCursor<S, ScalarMoveUnion<S, usize>> for ScalarLeafCursor<'_, S>
where
    S: PlanningSolution + 'static,
{
    fn next_candidate(&mut self) -> Option<CandidateId> {
        match self {
            Self::Change(cursor) => cursor.next_candidate(),
            Self::Direct(cursor) => cursor.next_candidate(),
        }
    }

    fn candidate(
        &self,
        index: CandidateId,
    ) -> Option<MoveCandidateRef<'_, S, ScalarMoveUnion<S, usize>>> {
        match self {
            Self::Change(cursor) => cursor.candidate(index),
            Self::Direct(cursor) => cursor.candidate(index),
        }
    }

    fn take_candidate(&mut self, index: CandidateId) -> ScalarMoveUnion<S, usize> {
        match self {
            Self::Change(cursor) => cursor.take_candidate(index),
            Self::Direct(cursor) => cursor.take_candidate(index),
        }
    }

    fn selector_index(&self, index: CandidateId) -> Option<usize> {
        match self {
            Self::Change(cursor) => cursor.selector_index(index),
            Self::Direct(cursor) => cursor.selector_index(index),
        }
    }
}

#[cfg_attr(not(test), allow(dead_code))]
#[allow(clippy::large_enum_variant)] // Inline storage keeps selector assembly zero-erasure.
pub enum ScalarSelectorNode<S> {
    Leaf(ScalarLeafSelector<S>),
    Cartesian(ScalarCartesianSelector<S>),
}

pub enum ScalarSelectorCursor<'a, S>
where
    S: PlanningSolution + 'static,
{
    Leaf(ScalarLeafCursor<'a, S>),
    Cartesian(CartesianProductCursor<S, ScalarMoveUnion<S, usize>>),
}

impl<S> MoveCursor<S, ScalarMoveUnion<S, usize>> for ScalarSelectorCursor<'_, S>
where
    S: PlanningSolution + 'static,
{
    fn next_candidate(&mut self) -> Option<CandidateId> {
        match self {
            Self::Leaf(cursor) => cursor.next_candidate(),
            Self::Cartesian(cursor) => cursor.next_candidate(),
        }
    }

    fn candidate(
        &self,
        index: CandidateId,
    ) -> Option<MoveCandidateRef<'_, S, ScalarMoveUnion<S, usize>>> {
        match self {
            Self::Leaf(cursor) => cursor.candidate(index),
            Self::Cartesian(cursor) => cursor.candidate(index),
        }
    }

    fn take_candidate(&mut self, index: CandidateId) -> ScalarMoveUnion<S, usize> {
        match self {
            Self::Leaf(cursor) => cursor.take_candidate(index),
            Self::Cartesian(cursor) => cursor.take_candidate(index),
        }
    }

    fn selector_index(&self, index: CandidateId) -> Option<usize> {
        match self {
            Self::Leaf(cursor) => cursor.selector_index(index),
            Self::Cartesian(cursor) => cursor.selector_index(index),
        }
    }
}

impl<S> Debug for ScalarSelectorNode<S>
where
    S: PlanningSolution + 'static,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Leaf(selector) => selector.fmt(f),
            Self::Cartesian(selector) => selector.fmt(f),
        }
    }
}

impl<S> MoveSelector<S, ScalarMoveUnion<S, usize>> for ScalarSelectorNode<S>
where
    S: PlanningSolution + 'static,
    S::Score: Score,
{
    type Cursor<'a>
        = ScalarSelectorCursor<'a, S>
    where
        Self: 'a;

    fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
        match self {
            Self::Leaf(selector) => {
                ScalarSelectorCursor::Leaf(selector.open_cursor(score_director))
            }
            Self::Cartesian(selector) => {
                ScalarSelectorCursor::Cartesian(selector.open_cursor(score_director))
            }
        }
    }

    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
        match self {
            Self::Leaf(selector) => selector.size(score_director),
            Self::Cartesian(selector) => selector.size(score_director),
        }
    }

    fn append_moves<D: Director<S>>(
        &self,
        score_director: &D,
        arena: &mut MoveArena<ScalarMoveUnion<S, usize>>,
    ) {
        match self {
            Self::Leaf(selector) => selector.append_moves(score_director, arena),
            Self::Cartesian(selector) => selector.append_moves(score_director, arena),
        }
    }
}

impl<S> Debug for ScalarLeafSelector<S> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Change(selector) => selector.fmt(f),
            Self::Swap(selector) => selector.fmt(f),
            Self::NearbyChange(selector) => selector.fmt(f),
            Self::NearbySwap(selector) => selector.fmt(f),
            Self::PillarChange(selector) => selector.fmt(f),
            Self::PillarSwap(selector) => selector.fmt(f),
            Self::RuinRecreate(selector) => selector.fmt(f),
        }
    }
}

impl<S> MoveSelector<S, ScalarMoveUnion<S, usize>> for ScalarLeafSelector<S>
where
    S: PlanningSolution + 'static,
    S::Score: Score,
{
    type Cursor<'a>
        = ScalarLeafCursor<'a, S>
    where
        Self: 'a;

    fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
        match self {
            Self::Change(selector) => ScalarLeafCursor::Change(MappedMoveCursor::new(
                selector.open_cursor(score_director),
                wrap_scalar_change_move::<S>,
            )),
            Self::Swap(selector) => ScalarLeafCursor::Direct(selector.open_cursor(score_director)),
            Self::NearbyChange(selector) => {
                ScalarLeafCursor::Direct(selector.open_cursor(score_director))
            }
            Self::NearbySwap(selector) => {
                ScalarLeafCursor::Direct(selector.open_cursor(score_director))
            }
            Self::PillarChange(selector) => {
                ScalarLeafCursor::Direct(selector.open_cursor(score_director))
            }
            Self::PillarSwap(selector) => {
                ScalarLeafCursor::Direct(selector.open_cursor(score_director))
            }
            Self::RuinRecreate(selector) => {
                ScalarLeafCursor::Direct(selector.open_cursor(score_director))
            }
        }
    }

    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
        match self {
            Self::Change(selector) => selector.size(score_director),
            Self::Swap(selector) => selector.size(score_director),
            Self::NearbyChange(selector) => selector.size(score_director),
            Self::NearbySwap(selector) => selector.size(score_director),
            Self::PillarChange(selector) => selector.size(score_director),
            Self::PillarSwap(selector) => selector.size(score_director),
            Self::RuinRecreate(selector) => selector.size(score_director),
        }
    }

    fn append_moves<D: Director<S>>(
        &self,
        score_director: &D,
        arena: &mut MoveArena<ScalarMoveUnion<S, usize>>,
    ) {
        match self {
            Self::Change(selector) => {
                let mut cursor = MappedMoveCursor::new(
                    selector.open_cursor(score_director),
                    wrap_scalar_change_move::<S>,
                );
                for id in
                    collect_cursor_indices::<S, ScalarMoveUnion<S, usize>, _>(&mut cursor)
                {
                    arena.push(cursor.take_candidate(id));
                }
            }
            Self::Swap(selector) => selector.append_moves(score_director, arena),
            Self::NearbyChange(selector) => selector.append_moves(score_director, arena),
            Self::NearbySwap(selector) => selector.append_moves(score_director, arena),
            Self::PillarChange(selector) => selector.append_moves(score_director, arena),
            Self::PillarSwap(selector) => selector.append_moves(score_director, arena),
            Self::RuinRecreate(selector) => selector.append_moves(score_director, arena),
        }
    }
}

#[cfg_attr(not(test), allow(dead_code))]
fn wrap_scalar_composite<S>(
    mov: SequentialCompositeMove<S, ScalarMoveUnion<S, usize>>,
) -> ScalarMoveUnion<S, usize>
where
    S: PlanningSolution,
{
    ScalarMoveUnion::Composite(mov)
}

pub(super) fn build_scalar_flat_selector<S>(
    config: Option<&MoveSelectorConfig>,
    scalar_variables: &[ScalarVariableContext<S>],
    random_seed: Option<u64>,
) -> ScalarFlatSelector<S>
where
    S: PlanningSolution + 'static,
    S::Score: Score,
{
    let mut leaves = Vec::new();
    collect_scalar_leaf_selectors(config, scalar_variables, random_seed, &mut leaves);
    assert!(
        !leaves.is_empty(),
        "move selector configuration produced no scalar neighborhoods"
    );
    let selection_order = match config {
        Some(MoveSelectorConfig::UnionMoveSelector(union)) => union.selection_order,
        _ => solverforge_config::UnionSelectionOrder::Sequential,
    };
    VecUnionSelector::with_selection_order(leaves, selection_order)
}