use order::PartialOrder;
#[derive(Default, Clone, Eq, PartialEq, Debug)]
pub struct Antichain<T> {
elements: Vec<T>
}
impl<T: PartialOrder> Antichain<T> {
pub fn insert(&mut self, element: T) -> bool {
if !self.elements.iter().any(|x| x.less_equal(&element)) {
self.elements.retain(|x| !element.less_equal(x));
self.elements.push(element);
true
}
else {
false
}
}
pub fn new() -> Antichain<T> { Antichain { elements: Vec::new() } }
pub fn from_elem(element: T) -> Antichain<T> { Antichain { elements: vec![element] } }
pub fn clear(&mut self) { self.elements.clear() }
pub fn sort(&mut self) where T: Ord { self.elements.sort() }
#[inline]
pub fn less_than(&self, time: &T) -> bool {
self.elements.iter().any(|x| x.less_than(time))
}
#[inline]
pub fn less_equal(&self, time: &T) -> bool {
self.elements.iter().any(|x| x.less_equal(time))
}
#[inline]
pub fn dominates(&self, other: &Antichain<T>) -> bool {
other.elements().iter().all(|t2| self.elements().iter().any(|t1| t1.less_equal(t2)))
}
#[inline] pub fn elements(&self) -> &[T] { &self.elements[..] }
}
#[derive(Default, Debug, Clone)]
pub struct MutableAntichain<T: PartialOrder+Ord> {
dirty: usize,
updates: Vec<(T, i64)>,
frontier: Vec<T>,
frontier_temp: Vec<T>,
}
impl<T: PartialOrder+Ord+Clone+'static> MutableAntichain<T> {
#[inline]
pub fn new() -> MutableAntichain<T> {
MutableAntichain {
dirty: 0,
updates: Vec::new(),
frontier: Vec::new(),
frontier_temp: Vec::new(),
}
}
#[inline]
pub fn clear(&mut self) {
self.dirty = 0;
self.updates.clear();
self.frontier.clear();
self.frontier_temp.clear();
}
pub fn empty(&mut self) {
for index in 0 .. self.updates.len() { self.updates[index].1 = 0; }
self.dirty = self.updates.len();
}
#[inline]
pub fn frontier(&self) -> &[T] {
debug_assert_eq!(self.dirty, 0);
&self.frontier
}
#[inline]
pub fn new_bottom(bottom: T) -> MutableAntichain<T> {
MutableAntichain {
dirty: 0,
updates: vec![(bottom.clone(), 1)],
frontier: vec![bottom.clone()],
frontier_temp: Vec::new(),
}
}
#[inline]
pub fn is_empty(&self) -> bool {
debug_assert_eq!(self.dirty, 0);
self.frontier.is_empty()
}
#[inline]
pub fn less_than(&self, time: &T) -> bool {
debug_assert_eq!(self.dirty, 0);
self.frontier.iter().any(|x| x.less_than(time))
}
#[inline]
pub fn less_equal(&self, time: &T) -> bool {
debug_assert_eq!(self.dirty, 0);
self.frontier.iter().any(|x| x.less_equal(time))
}
#[inline]
pub fn update_dirty(&mut self, time: T, delta: i64) {
self.updates.push((time, delta));
self.dirty += 1;
}
#[inline]
pub fn update_iter<I>(&mut self, updates: I)
where
I: IntoIterator<Item = (T, i64)>
{
self.update_iter_and(updates, |_,_| { });
}
#[inline]
pub fn update_iter_and<I, A>(&mut self, updates: I, action: A)
where
I: IntoIterator<Item = (T, i64)>,
A: FnMut(&T, i64)
{
for (time, delta) in updates {
self.updates.push((time, delta));
self.dirty += 1;
}
let mut rebuild_required = false;
while self.dirty > 0 && !rebuild_required {
let time = &self.updates[self.updates.len() - self.dirty].0;
let delta = self.updates[self.updates.len() - self.dirty].1;
let beyond_frontier = self.frontier.iter().any(|f| f.less_than(time));
let before_frontier = !self.frontier.iter().any(|f| f.less_equal(time));
rebuild_required = rebuild_required || !(beyond_frontier || (delta < 0 && before_frontier));
self.dirty -= 1;
}
self.dirty = 0;
if rebuild_required {
self.rebuild_and(action);
}
}
fn rebuild_and<A: FnMut(&T, i64)>(&mut self, mut action: A) {
if !self.updates.is_empty() {
self.updates.sort_by(|x,y| x.0.cmp(&y.0));
for i in 0 .. self.updates.len() - 1 {
if self.updates[i].0 == self.updates[i+1].0 {
self.updates[i+1].1 += self.updates[i].1;
self.updates[i].1 = 0;
}
}
self.updates.retain(|x| x.1 != 0);
}
for time in self.updates.iter().filter(|x| x.1 > 0) {
if !self.frontier_temp.iter().any(|f| f.less_equal(&time.0)) {
self.frontier_temp.push(time.0.clone());
}
}
for time in self.frontier.iter() {
if !self.frontier_temp.contains(time) {
action(time, -1);
}
}
::std::mem::swap(&mut self.frontier, &mut self.frontier_temp);
for time in self.frontier.iter() {
if !self.frontier_temp.contains(time) {
action(time, 1);
}
}
self.frontier_temp.clear();
}
}