use crate::solvers::search_algorithms::{BestFirstSearch, CostNode, SearchNode};
use crate::solvers::{Search, SearchParameters};
use crate::{Dominance, DpMut};
use num_traits::Signed;
use std::fmt::Display;
use std::hash::Hash;
pub fn create_dijkstra<D, S, C, L, K>(
dp: D,
parameters: SearchParameters<C>,
) -> impl Search<CostType = C, Label = L>
where
D: DpMut<State = S, CostType = C, Label = L> + Dominance<State = S, Key = K>,
C: Ord + Copy + Signed + Display,
L: Default + Copy,
K: Hash + Eq,
{
let root_node_constructor = |dp: &mut D, _| {
Some(CostNode::create_root(
dp,
dp.get_target(),
dp.get_identity_weight(),
))
};
let node_constructor =
|dp: &mut _, state, cost, transition, parent: &CostNode<_, _, _, _>, _, _: Option<&_>| {
Some(parent.create_child(dp, state, cost, transition))
};
let solution_checker = |dp: &mut _, node: &CostNode<_, _, _, _>| node.check_solution(dp);
BestFirstSearch::new(
dp,
root_node_constructor,
node_constructor,
solution_checker,
parameters,
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Solution;
use crate::dp::Dp;
use std::cell::Cell;
use std::cmp::Ordering;
#[derive(PartialEq, Eq)]
struct MockDp(i32);
impl Dp for MockDp {
type State = i32;
type CostType = i32;
type Label = usize;
fn get_target(&self) -> Self::State {
self.0
}
fn get_successors(
&self,
state: &Self::State,
) -> impl IntoIterator<Item = (Self::State, Self::CostType, Self::Label)> {
vec![(*state - 1, 1, 1)]
}
fn get_base_cost(&self, state: &Self::State) -> Option<Self::CostType> {
if *state <= 0 { Some(0) } else { None }
}
}
impl Dominance for MockDp {
type State = i32;
type Key = i32;
fn get_key(&self, state: &Self::State) -> Self::Key {
*state
}
}
struct MockNode(i32, i32, Cell<bool>, Vec<usize>);
impl SearchNode for MockNode {
type DpData = MockDp;
type State = i32;
type CostType = i32;
type Label = usize;
fn get_state(&self, _: &Self::DpData) -> &Self::State {
&self.0
}
fn get_state_mut(&mut self, _: &Self::DpData) -> &mut Self::State {
&mut self.0
}
fn get_cost(&self, _: &Self::DpData) -> Self::CostType {
self.1
}
fn get_bound(&self, _: &Self::DpData) -> Option<Self::CostType> {
None
}
fn close(&self) {
self.2.set(true)
}
fn is_closed(&self) -> bool {
self.2.get()
}
fn get_transitions(&self, _: &Self::DpData) -> Vec<Self::Label> {
self.3.clone()
}
}
impl PartialEq for MockNode {
fn eq(&self, other: &Self) -> bool {
self.1 == other.1
}
}
impl Eq for MockNode {}
impl Ord for MockNode {
fn cmp(&self, other: &Self) -> Ordering {
other.1.cmp(&self.1)
}
}
impl PartialOrd for MockNode {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[test]
fn test_dijkstra() {
let dp = MockDp(2);
let parameters = SearchParameters {
quiet: true,
..Default::default()
};
let mut search = create_dijkstra(dp, parameters);
let solution: Solution<_, usize> = search.search();
assert_eq!(solution.cost, Some(2));
assert_eq!(solution.transitions, vec![1, 1]);
assert_eq!(solution.best_bound, Some(2));
assert!(solution.is_optimal);
assert!(!solution.is_infeasible);
assert!(!solution.is_time_limit_reached);
assert!(!solution.is_expansion_limit_reached);
}
#[test]
fn test_dijkstra_infeasible() {
let dp = MockDp(2);
let parameters = SearchParameters {
primal_bound: Some(2),
quiet: true,
..Default::default()
};
let mut search = create_dijkstra(dp, parameters);
let solution: Solution<_, usize> = search.search();
assert_eq!(solution.cost, None);
assert_eq!(solution.transitions, vec![]);
assert_eq!(solution.best_bound, None);
assert!(!solution.is_optimal);
assert!(solution.is_infeasible);
assert!(!solution.is_time_limit_reached);
assert!(!solution.is_expansion_limit_reached);
}
}