use std::hash::BuildHasherDefault;
use std::iter::FromIterator;
use im::{hashset, HashSet};
use seahash::SeaHasher;
use once_cell::sync::Lazy;
use crate::auto::{Automaton, StateId};
use crate::{Constructor, Polarity};
#[derive(Copy, Clone, Debug)]
pub struct Pair {
pub neg: StateId,
pub pos: StateId,
}
#[derive(Debug, Clone)]
pub struct FlowSet {
set: HashSet<StateId, BuildHasherDefault<SeaHasher>>,
}
impl Pair {
pub(crate) fn from_pol(pol: Polarity, a: StateId, b: StateId) -> Self {
let (pos, neg) = pol.flip(a, b);
Pair { pos, neg }
}
pub fn get(&self, pol: Polarity) -> StateId {
match pol {
Polarity::Pos => self.pos,
Polarity::Neg => self.neg,
}
}
}
impl FlowSet {
pub fn iter(&self) -> hashset::ConsumingIter<StateId> {
self.set.clone().into_iter()
}
pub(in crate::auto) fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = StateId>,
{
FlowSet {
set: HashSet::from_iter(iter),
}
}
pub(crate) fn shift(self, offset: u32) -> Self {
FlowSet::from_iter(self.set.into_iter().map(|id| id.shift(offset)))
}
pub(in crate::auto) fn union(&mut self, other: &Self) {
self.set.extend(other.iter());
}
}
impl Default for FlowSet {
fn default() -> Self {
static EMPTY: Lazy<FlowSet> = Lazy::new(|| FlowSet {
set: HashSet::default()
});
EMPTY.clone()
}
}
impl<C: Constructor> Automaton<C> {
pub(crate) fn add_flow(&mut self, pair: Pair) {
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.pos].pol, Polarity::Pos);
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.neg].pol, Polarity::Neg);
let had_p = self[pair.pos].flow.set.insert(pair.neg).is_some();
let had_n = self[pair.neg].flow.set.insert(pair.pos).is_some();
debug_assert_eq!(had_p, had_n);
}
pub(crate) fn remove_flow(&mut self, pair: Pair) {
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.pos].pol, Polarity::Pos);
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.neg].pol, Polarity::Neg);
let had_p = self[pair.pos].flow.set.remove(&pair.neg).is_some();
let had_n = self[pair.neg].flow.set.remove(&pair.pos).is_some();
debug_assert_eq!(had_p, had_n);
}
pub(crate) fn has_flow(&self, pair: Pair) -> bool {
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.pos].pol, Polarity::Pos);
#[cfg(debug_assertions)]
debug_assert_eq!(self[pair.neg].pol, Polarity::Neg);
self[pair.neg].flow.set.contains(&pair.pos)
}
pub(crate) fn merge_flow(&mut self, pol: Polarity, a: StateId, source: StateId) {
#[cfg(debug_assertions)]
debug_assert_eq!(self[a].pol, pol);
#[cfg(debug_assertions)]
debug_assert_eq!(self[source].pol, pol);
for b in self[source].flow.iter() {
self.add_flow(Pair::from_pol(pol, a, b));
}
}
#[cfg(debug_assertions)]
pub(in crate::auto) fn check_flow(&self) -> bool {
self.enumerate().all(|(from, st)| {
st.flow
.iter()
.all(|to| self[to].pol != st.pol && self[to].flow.set.contains(&from))
})
}
}