Skip to main content

create_blind_parallel_cabs

Function create_blind_parallel_cabs 

Source
pub fn create_blind_parallel_cabs<'a, D, S, C, L, K>(
    dp: D,
    parameters: SearchParameters<C>,
    cabs_parameters: CabsParameters,
    threads: usize,
) -> Box<dyn Search<CostType = C, Label = L> + 'a>
where D: DpMut<State = S, CostType = C, Label = L> + Dominance<State = S, Key = K> + Clone + Send + 'a, S: Clone + Send, C: Ord + Copy + Signed + Display + Send + Sync + 'a, L: Default + Copy + Send + Sync + 'a, K: Hash + Eq,
Expand description

Creates complete anytime hash distributed beam search 2 (CAHDBS2) solver without guidance. This is the default parallelization version of CABS without guidance.

Search nodes are ordered by the cost.

§References

Ryo Kuroiwa and J. Christopher Beck. “Parallel Beam Search Algorithms for Domain-Independent Dynamic Programming,” Proceedings of the 38th Annual AAAI Conference on Artificial Intelligence (AAAI), 2024.

§Panic

When threads argument takes 0 value.

§Examples

use rpid::prelude::*;
use rpid::solvers;
use fixedbitset::FixedBitSet;

#[derive(Clone)]
struct Tsp {
    c: Vec<Vec<i32>>,
}

#[derive(Clone, Hash)]
struct TspState {
    unvisited: FixedBitSet,
    current: usize,
}

impl Dp for Tsp {
    type State = TspState;
    type CostType = i32;
    type Label = usize;

    fn get_target(&self) -> Self::State {
        let mut unvisited = FixedBitSet::with_capacity(self.c.len());
        unvisited.insert_range(1..);

        TspState {
            unvisited,
            current: 0,
       }
    }

    fn get_successors(
        &self,
        state: &Self::State,
    ) -> impl IntoIterator<Item = (Self::State, Self::CostType, Self::Label)> {
        state.unvisited.ones().map(|next| {
            let mut unvisited = state.unvisited.clone();
            unvisited.remove(next);

            let successor = TspState {
                unvisited,
                current: next,
            };
            let weight = self.c[state.current][next];
             
            (successor, weight, next)
        })
    }

    fn get_base_cost(&self, state: &Self::State) -> Option<Self::CostType> {
        if state.unvisited.is_clear() {
            Some(self.c[state.current][0])
        } else {
            None
        }
    }
}

impl Dominance for Tsp {
    type State = TspState;
    type Key = (FixedBitSet, usize);

    fn get_key(&self, state: &Self::State) -> Self::Key {
        (state.unvisited.clone(), state.current)
    }
}

let tsp = Tsp { c: vec![vec![0, 1, 2], vec![1, 0, 3], vec![2, 3, 0]] };
let parameters = SearchParameters {
    quiet: true,
    ..Default::default()
};

let cabs_parameters = CabsParameters::default();
let mut solver = solvers::create_blind_parallel_cabs(tsp, parameters, cabs_parameters, 8);
let solution = solver.search();
assert_eq!(solution.cost, Some(6));
assert_eq!(solution.transitions, vec![1, 2]);
assert!(solution.is_optimal);
assert!(!solution.is_infeasible);
assert_eq!(solution.best_bound, Some(6));