use std::{cmp::Ordering, sync::Arc};
#[derive(Debug, PartialEq, Eq)]
pub struct DominanceCmpResult {
pub ordering: Ordering,
pub only_val_diff: bool,
}
pub trait Dominance {
type State;
type Key;
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key>;
fn nb_dimensions(&self, state: &Self::State) -> usize;
fn get_coordinate(&self, state: &Self::State, i: usize) -> isize;
fn use_value(&self) -> bool { false }
fn partial_cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Option<DominanceCmpResult> {
let mut ordering = Ordering::Equal;
for i in 0..self.nb_dimensions(a) {
match (ordering, self.get_coordinate(a, i).cmp(&self.get_coordinate(b, i))) {
(Ordering::Less, Ordering::Greater) => return None,
(Ordering::Greater, Ordering::Less) => return None,
(Ordering::Equal, Ordering::Greater) => ordering = Ordering::Greater,
(Ordering::Equal, Ordering::Less) => ordering = Ordering::Less,
(_, _) => (),
}
}
if self.use_value() {
match (ordering, val_a.cmp(&val_b)) {
(Ordering::Less, Ordering::Greater) => None,
(Ordering::Greater, Ordering::Less) => None,
(Ordering::Equal, Ordering::Greater) => Some(DominanceCmpResult { ordering: Ordering::Greater, only_val_diff: true }),
(Ordering::Equal, Ordering::Less) => Some(DominanceCmpResult { ordering: Ordering::Less, only_val_diff: true }),
(_, _) => Some(DominanceCmpResult { ordering, only_val_diff: false }),
}
} else {
Some(DominanceCmpResult { ordering, only_val_diff: false })
}
}
fn cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Ordering {
if self.use_value() {
match val_a.cmp(&val_b) {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => (),
}
}
for i in 0..self.nb_dimensions(a) {
match self.get_coordinate(a, i).cmp(&self.get_coordinate(b, i)) {
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => (),
}
}
Ordering::Equal
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct DominanceCheckResult {
pub dominated: bool,
pub threshold: Option<isize>,
}
pub trait DominanceChecker {
type State;
fn clear_layer(&self, depth: usize);
fn is_dominated_or_insert(&self, state: Arc<Self::State>, depth: usize, value: isize) -> DominanceCheckResult;
fn cmp(&self, a: &Self::State, val_a: isize, b: &Self::State, val_b: isize) -> Ordering;
}
#[cfg(test)]
mod tests {
use std::{sync::Arc, cmp::Ordering};
use crate::{Dominance, DominanceCmpResult};
#[test]
fn by_default_value_is_unused() {
let dominance = DummyDominance;
assert!(!dominance.use_value());
}
#[test]
fn partial_cmp_returns_none_when_coordinates_disagree() {
let dominance = DummyDominance;
assert_eq!(None, dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, -1, 1], 0));
let dominance = DummyDominanceWithValue;
assert_eq!(None, dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], -1));
}
#[test]
fn partial_cmp_returns_some_when_coordinates_agree() {
let dominance = DummyDominance;
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Less, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], 0));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Less, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], -1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Greater, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 0));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Greater, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Equal, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], 1));
let dominance = DummyDominanceWithValue;
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Less, only_val_diff: true}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], 1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Less, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![1, 1, 1], 1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Greater, only_val_diff: true}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], -1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Greater, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![-1, -1, -1], -1));
assert_eq!(Some(DominanceCmpResult{ordering: Ordering::Equal, only_val_diff: false}), dominance.partial_cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], 0));
}
#[test]
fn cmp_returns_first_diff() {
let dominance = DummyDominance;
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], 0));
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 1, -1], 0));
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], -1));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 0));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, -1, 1], 0));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 1));
assert_eq!(Ordering::Equal, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], 1));
let dominance = DummyDominanceWithValue;
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], 0));
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 1, -1], 0));
assert_eq!(Ordering::Less, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 1));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, -1], 0));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, -1, 1], 0));
assert_eq!(Ordering::Greater, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 1], -1));
assert_eq!(Ordering::Equal, dominance.cmp(&vec![0, 0, 0], 0, &vec![0, 0, 0], 0));
}
struct DummyDominance;
impl Dominance for DummyDominance {
type State = Vec<isize>;
type Key = isize;
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
Some(state[0])
}
fn nb_dimensions(&self, state: &Self::State) -> usize {
state.len()
}
fn get_coordinate(&self, state: &Self::State, i: usize) -> isize {
state[i]
}
}
struct DummyDominanceWithValue;
impl Dominance for DummyDominanceWithValue {
type State = Vec<isize>;
type Key = isize;
fn get_key(&self, state: Arc<Self::State>) -> Option<Self::Key> {
Some(state[0])
}
fn nb_dimensions(&self, state: &Self::State) -> usize {
state.len()
}
fn get_coordinate(&self, state: &Self::State, i: usize) -> isize {
state[i]
}
fn use_value(&self) -> bool {
true
}
}
}