use num_traits::Zero;
use std::cmp::Ordering;
use std::hash::Hash;
use std::ops::Add;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OptimizationMode {
Minimization,
Maximization,
}
pub trait Dp {
type State;
type CostType: PartialOrd + Add<Output = Self::CostType> + Zero;
type Label;
fn get_target(&self) -> Self::State;
fn get_successors(
&self,
state: &Self::State,
) -> impl IntoIterator<Item = (Self::State, Self::CostType, Self::Label)>;
fn get_base_cost(&self, state: &Self::State) -> Option<Self::CostType>;
fn combine_cost_weights(&self, a: Self::CostType, b: Self::CostType) -> Self::CostType {
a + b
}
fn get_identity_weight(&self) -> Self::CostType {
Self::CostType::zero()
}
fn get_optimization_mode(&self) -> OptimizationMode {
OptimizationMode::Minimization
}
fn is_better_cost(&self, new_cost: Self::CostType, old_cost: Self::CostType) -> bool {
match self.get_optimization_mode() {
OptimizationMode::Minimization => new_cost < old_cost,
OptimizationMode::Maximization => new_cost > old_cost,
}
}
}
pub trait Dominance {
type State;
type Key: Hash + Eq;
fn get_key(&self, state: &Self::State) -> Self::Key;
fn compare(&self, _a: &Self::State, _b: &Self::State) -> Option<Ordering> {
Some(Ordering::Equal)
}
fn update_key(&self, _state: &mut Self::State, _key: &Self::Key) {}
}
pub trait Bound {
type State;
type CostType;
fn get_dual_bound(&self, state: &Self::State) -> Option<Self::CostType>;
fn get_global_primal_bound(&self) -> Option<Self::CostType> {
None
}
fn get_global_dual_bound(&self) -> Option<Self::CostType> {
None
}
}
pub trait DpMut {
type State;
type CostType: PartialOrd + Add<Output = Self::CostType> + Zero;
type Label;
fn get_target(&self) -> Self::State;
fn get_successors(
&mut self,
state: &Self::State,
successors: &mut Vec<(Self::State, Self::CostType, Self::Label)>,
);
fn get_base_cost(&mut self, state: &Self::State) -> Option<Self::CostType>;
fn combine_cost_weights(&self, a: Self::CostType, b: Self::CostType) -> Self::CostType {
a + b
}
fn get_identity_weight(&self) -> Self::CostType {
Self::CostType::zero()
}
fn get_optimization_mode(&self) -> OptimizationMode {
OptimizationMode::Minimization
}
fn is_better_cost(&self, new_cost: Self::CostType, old_cost: Self::CostType) -> bool {
match self.get_optimization_mode() {
OptimizationMode::Minimization => new_cost < old_cost,
OptimizationMode::Maximization => new_cost > old_cost,
}
}
fn notify_primal_bound(&mut self, _primal_bound: Self::CostType) {}
}
impl<T: Dp> DpMut for T {
type State = T::State;
type CostType = T::CostType;
type Label = T::Label;
fn get_target(&self) -> Self::State {
Dp::get_target(self)
}
fn get_successors(
&mut self,
state: &Self::State,
successors: &mut Vec<(Self::State, Self::CostType, Self::Label)>,
) {
successors.extend(Dp::get_successors(self, state));
}
fn get_base_cost(&mut self, state: &Self::State) -> Option<Self::CostType> {
Dp::get_base_cost(self, state)
}
fn combine_cost_weights(&self, a: Self::CostType, b: Self::CostType) -> Self::CostType {
Dp::combine_cost_weights(self, a, b)
}
fn get_identity_weight(&self) -> Self::CostType {
Dp::get_identity_weight(self)
}
fn get_optimization_mode(&self) -> OptimizationMode {
Dp::get_optimization_mode(self)
}
fn is_better_cost(&self, new_cost: Self::CostType, old_cost: Self::CostType) -> bool {
Dp::is_better_cost(self, new_cost, old_cost)
}
}
pub trait BoundMut {
type State;
type CostType;
fn get_dual_bound(&mut self, state: &Self::State) -> Option<Self::CostType>;
fn get_global_primal_bound(&self) -> Option<Self::CostType> {
None
}
fn get_global_dual_bound(&self) -> Option<Self::CostType> {
None
}
}
impl<T: Bound> BoundMut for T {
type State = T::State;
type CostType = T::CostType;
fn get_dual_bound(&mut self, state: &Self::State) -> Option<Self::CostType> {
Bound::get_dual_bound(self, state)
}
fn get_global_primal_bound(&self) -> Option<Self::CostType> {
Bound::get_global_primal_bound(self)
}
fn get_global_dual_bound(&self) -> Option<Self::CostType> {
Bound::get_global_dual_bound(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockDp;
impl Dp for MockDp {
type State = i32;
type CostType = i32;
type Label = usize;
fn get_target(&self) -> Self::State {
0
}
fn get_successors(
&self,
_: &Self::State,
) -> impl IntoIterator<Item = (Self::State, Self::CostType, Self::Label)> {
vec![]
}
fn get_base_cost(&self, _state: &Self::State) -> Option<Self::CostType> {
None
}
}
impl Dominance for MockDp {
type State = i32;
type Key = i32;
fn get_key(&self, state: &Self::State) -> Self::Key {
*state
}
}
impl Bound for MockDp {
type State = i32;
type CostType = i32;
fn get_dual_bound(&self, _: &Self::State) -> Option<Self::CostType> {
Some(0)
}
}
#[test]
fn test_get_target_mut() {
let dp = MockDp;
assert_eq!(DpMut::get_target(&dp), 0);
}
#[test]
fn test_get_successors_mut() {
let mut dp = MockDp;
let mut successors = Vec::new();
DpMut::get_successors(&mut dp, &0, &mut successors);
assert!(successors.is_empty());
}
#[test]
fn get_base_cost_mut() {
let mut dp = MockDp;
assert_eq!(DpMut::get_base_cost(&mut dp, &0), None);
}
#[test]
fn test_combine_cost_weights_default() {
let dp = MockDp;
assert_eq!(Dp::combine_cost_weights(&dp, 1, 2), 3);
}
#[test]
fn test_combine_cost_weights_mut() {
let dp = MockDp;
assert_eq!(DpMut::combine_cost_weights(&dp, 1, 2), 3);
}
#[test]
fn test_get_identity_weight_default() {
let dp = MockDp;
assert_eq!(Dp::get_identity_weight(&dp), 0);
}
#[test]
fn test_get_identity_weight_mut() {
let dp = MockDp;
assert_eq!(DpMut::get_identity_weight(&dp), 0);
}
#[test]
fn test_get_optimization_mode_default() {
let dp = MockDp;
assert_eq!(
Dp::get_optimization_mode(&dp),
OptimizationMode::Minimization
);
}
#[test]
fn test_get_optimization_mode_mut() {
let dp = MockDp;
assert_eq!(
DpMut::get_optimization_mode(&dp),
OptimizationMode::Minimization
);
}
#[test]
fn test_is_better_cost_default() {
let dp = MockDp;
assert!(Dp::is_better_cost(&dp, 1, 2));
}
#[test]
fn test_is_better_cost_mut() {
let dp = MockDp;
assert!(DpMut::is_better_cost(&dp, 1, 2));
}
#[test]
fn test_compare_default() {
let dp = MockDp;
assert_eq!(dp.compare(&0, &0), Some(Ordering::Equal));
}
#[test]
fn test_get_global_primal_bound_default() {
let dp = MockDp;
assert_eq!(Bound::get_global_primal_bound(&dp), None);
}
#[test]
fn test_get_global_primal_bound_mut() {
let dp = MockDp;
assert_eq!(Bound::get_global_primal_bound(&dp), None);
}
#[test]
fn test_get_dual_bound_mut() {
let mut dp = MockDp;
assert_eq!(BoundMut::get_dual_bound(&mut dp, &0), Some(0));
}
#[test]
fn test_get_global_dual_bound_default() {
let dp = MockDp;
assert_eq!(Bound::get_global_dual_bound(&dp), None);
}
#[test]
fn test_get_global_dual_bound_mut() {
let dp = MockDp;
assert_eq!(BoundMut::get_global_dual_bound(&dp), None);
}
struct MockDpMut;
impl DpMut for MockDpMut {
type State = i32;
type CostType = i32;
type Label = usize;
fn get_target(&self) -> Self::State {
0
}
fn get_successors(
&mut self,
_: &Self::State,
_: &mut Vec<(Self::State, Self::CostType, Self::Label)>,
) {
}
fn get_base_cost(&mut self, _state: &Self::State) -> Option<Self::CostType> {
None
}
}
impl BoundMut for MockDpMut {
type State = i32;
type CostType = i32;
fn get_dual_bound(&mut self, _: &Self::State) -> Option<Self::CostType> {
Some(0)
}
}
#[test]
fn test_combine_cost_weights_mut_default() {
let dp = MockDpMut;
assert_eq!(dp.combine_cost_weights(1, 2), 3);
}
#[test]
fn test_get_identity_weight_mut_default() {
let dp = MockDpMut;
assert_eq!(dp.get_identity_weight(), 0);
}
#[test]
fn test_get_optimization_mode_mut_default() {
let dp = MockDpMut;
assert_eq!(dp.get_optimization_mode(), OptimizationMode::Minimization);
}
#[test]
fn test_is_better_cost_mut_default() {
let dp = MockDpMut;
assert!(dp.is_better_cost(1, 2));
}
#[test]
fn test_get_global_primal_bound_mut_default() {
let dp = MockDpMut;
assert_eq!(dp.get_global_primal_bound(), None);
}
#[test]
fn test_get_global_dual_bound_mut_default() {
let dp = MockDpMut;
assert_eq!(dp.get_global_dual_bound(), None);
}
#[test]
fn test_notify_primal_bound_mut_default() {
let mut dp = MockDpMut;
dp.notify_primal_bound(42);
}
}