// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #[cfg(test)] mod tests; use std::cmp::Ordering; pub trait Point { fn dominates(&self, other: &Rhs) -> bool; } pub struct Point2D { pub item: T, pub value1: f64, pub value2: u64, } impl Point2D { pub fn new(item: T, value1: f64, value2: u64) -> Self { Self { item, value1, value2, } } } impl Point for Point2D { fn dominates(&self, other: &Self) -> bool { (self.value1 < other.value1 && self.value2 <= other.value2) || (self.value1 <= other.value1 && self.value2 < other.value2) } } impl PartialEq for Point2D { fn eq(&self, other: &Self) -> bool { self.value1 == other.value1 && self.value2 == other.value2 } } impl Eq for Point2D {} impl PartialOrd for Point2D { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Point2D { fn cmp(&self, other: &Self) -> Ordering { if self.value1 < other.value1 { Ordering::Less } else if self.value1 > other.value1 { Ordering::Greater } else if self.value2 < other.value2 { Ordering::Less } else if self.value2 > other.value2 { Ordering::Greater } else { Ordering::Equal } } } pub struct Point4D { pub item: T, pub value1: f64, pub value2: u64, pub value3: f64, pub value4: u64, } impl Point4D { pub fn new(item: T, value1: f64, value2: u64, value3: f64, value4: u64) -> Self { Self { item, value1, value2, value3, value4, } } } impl Point for Point4D { // Allowing == comparison for better speed compared to abs() + cmp #[allow(clippy::float_cmp)] fn dominates(&self, other: &Self) -> bool { self.value1 <= other.value1 && self.value2 <= other.value2 && self.value3 <= other.value3 && self.value4 <= other.value4 && !(self.value1 == other.value1 && self.value2 == other.value2 && self.value3 == other.value3 && self.value4 == other.value4) } } impl PartialEq for Point4D { fn eq(&self, other: &Self) -> bool { self.value1 == other.value1 && self.value2 == other.value2 && self.value3 == other.value3 && self.value4 == other.value4 } } impl Eq for Point4D {} impl PartialOrd for Point4D { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Point4D { fn cmp(&self, other: &Self) -> Ordering { if self.value1 < other.value1 { Ordering::Less } else if self.value1 > other.value1 { Ordering::Greater } else if self.value2 < other.value2 { Ordering::Less } else if self.value2 > other.value2 { Ordering::Greater } else if self.value3 < other.value3 { Ordering::Less } else if self.value3 > other.value3 { Ordering::Greater } else if self.value4 < other.value4 { Ordering::Less } else if self.value4 > other.value4 { Ordering::Greater } else { Ordering::Equal } } } pub struct Population

where P: Point, P: Ord, { items: Vec

, nonexecuted_attempts_to_filter_out_dominated: usize, } impl

Default for Population

where P: Point, P: Ord, { fn default() -> Self { Self::new() } } impl

Population

where P: Point, P: Ord, { const MAX_NONEXECUTED_ATTEMPTS_TO_FILTER_OUT_DOMINATED: usize = 1000; #[must_use] pub fn new() -> Self { Self { items: Vec::new(), nonexecuted_attempts_to_filter_out_dominated: 0, } } #[must_use] pub fn items(&self) -> &[P] { &self.items } pub(crate) fn push(&mut self, point: P) { self.items.push(point); } pub(crate) fn sort_items(&mut self) { self.items.sort_by(|a, b| b.cmp(a)); } pub(crate) fn extract(self) -> Vec

{ self.items } pub(crate) fn attempt_filter_out_dominated(&mut self) { if self.nonexecuted_attempts_to_filter_out_dominated <= Self::MAX_NONEXECUTED_ATTEMPTS_TO_FILTER_OUT_DOMINATED { self.nonexecuted_attempts_to_filter_out_dominated += 1; } else { self.filter_out_dominated(); } } pub(crate) fn filter_out_dominated(&mut self) { // NOTE: Use drain_filter in the future let mut idx = 0; let mut len = self.items.len(); while idx < len { let p = &self.items[idx]; if self.dominates(p) { // remove item by swapping with the end self.items.swap(idx, len - 1); len -= 1; } else { idx += 1; } } self.nonexecuted_attempts_to_filter_out_dominated = 0; self.items.truncate(len); } pub(crate) fn dominates(&self, other: &P) -> bool { self.items.iter().any(|t| t.dominates(other)) } }