solverforge-solver 0.18.0

Solver engine for SolverForge
Documentation
use std::collections::HashSet;

use solverforge_core::domain::PlanningSolution;

use crate::builder::context::{ScalarAssignmentBinding, ScalarCandidate, ScalarGroupBinding};
use crate::heuristic::r#move::CompoundScalarMove;
use crate::planning::ScalarEdit;

pub(crate) fn compound_move_for_group_candidate<S>(
    group: &ScalarGroupBinding<S>,
    solution: &S,
    candidate: &ScalarCandidate<S>,
) -> Option<CompoundScalarMove<S>> {
    let mut edits = Vec::with_capacity(candidate.edits().len());
    for edit in candidate.edits() {
        let member = group.member_for_edit(edit)?;
        if !member.value_is_legal(solution, edit.entity_index(), edit.to_value()) {
            return None;
        }
        edits.push(member.compound_edit(edit.entity_index(), edit.to_value()));
    }

    Some(CompoundScalarMove::new(candidate.reason(), edits))
}

pub(super) fn compound_move_for_prevalidated_group_candidate<S>(
    group: &ScalarGroupBinding<S>,
    candidate: &ScalarCandidate<S>,
) -> CompoundScalarMove<S> {
    let edits = candidate
        .edits()
        .iter()
        .map(|edit| {
            let member = group
                .member_for_edit(edit)
                .expect("prevalidated grouped scalar candidate member must exist");
            member.compound_edit(edit.entity_index(), edit.to_value())
        })
        .collect();
    CompoundScalarMove::new(candidate.reason(), edits)
}

pub(super) fn compound_move_for_assignment_edits<S>(
    group: &ScalarAssignmentBinding<S>,
    solution: &S,
    edits: &[ScalarEdit<S>],
    reason: &'static str,
) -> Option<CompoundScalarMove<S>>
where
    S: PlanningSolution,
{
    if edits.is_empty() {
        return None;
    }

    let mut targets = HashSet::new();
    let mut compound_edits = Vec::with_capacity(edits.len());
    for edit in edits {
        if !targets.insert(edit.entity_index()) {
            return None;
        }
        if !group.value_is_legal(solution, edit.entity_index(), edit.to_value()) {
            return None;
        }
        compound_edits.push(
            group
                .target()
                .compound_edit(edit.entity_index(), edit.to_value()),
        );
    }

    Some(CompoundScalarMove::new(reason, compound_edits))
}