use std::collections::{HashSet, VecDeque};
use crate::finite::automaton::FiniteAutomaton;
use crate::finite::deterministic::DeterministicFiniteAutomaton;
use crate::general::NonDeterministicAutomaton;
pub trait NonDeterministicFiniteAutomaton: NonDeterministicAutomaton + FiniteAutomaton {
type CorrespondingDFA: DeterministicFiniteAutomaton<State = Self::State, Input = Self::Input, CorrespondingNFA = Self>;
fn to_dfa(&self) -> Self::CorrespondingDFA;
fn union(&self, other: &Self) -> Self;
fn difference(&self, other: &Self) -> Self;
fn concatenate(&self, other: &Self) -> Self;
fn intersection(&self, other: &Self) -> Self;
fn star(&self) -> Self;
fn reverse(&self) -> Self;
fn trimmed(&self) -> Self;
fn complement(&self) -> Self;
fn accessible(&self) -> Self;
fn co_accessible(&self) -> Self;
fn is_subset_of(&self, other: &Self) -> bool;
fn is_equivalent_to(&self, other: &Self) -> bool;
fn to_minimized_dfa(&self) -> Self::CorrespondingDFA
where Self: Sized
{
self.reverse().to_dfa().to_nfa().reverse().to_dfa()
}
fn union_all(automata: &[Self]) -> Option<Self>
where Self: Clone + Sized
{
clone_reduce(automata, |a, b| a.union(b))
}
fn concatenate_all(automata: &[Self]) -> Option<Self>
where Self: Clone + Sized
{
clone_reduce(automata, |a, b| a.concatenate(b))
}
fn intersect_all(automata: &[Self]) -> Option<Self>
where Self: Clone + Sized
{
clone_reduce(automata, |a, b| a.intersection(b))
}
fn common_alphabet(&self, other: &Self) -> HashSet<Self::Input> {
let alphabet1: HashSet<Self::Input> = self.alphabet_set();
let alphabet2: HashSet<Self::Input> = other.alphabet_set();
alphabet1.intersection(&alphabet2).cloned().collect()
}
fn accepting_states_compatible_with(&self, other: &Self) -> HashSet<Self::State> {
let mut common = HashSet::new();
let mut queue = VecDeque::new();
let mut visited = HashSet::new();
let common_alphabet = self.common_alphabet(other);
for initial_state1 in self.initial_states() {
for initial_state2 in other.initial_states() {
queue.push_back((initial_state1, initial_state2));
}
}
while let Some((state1, state2)) = queue.pop_front() {
if visited.contains(&(state1, state2)) {
continue;
}
visited.insert((state1, state2));
if self.is_accepting_state(state1) && other.is_accepting_state(state2) {
common.insert(state1);
}
for input in &common_alphabet {
for new_state1 in self.successors(state1, input) {
for new_state2 in other.successors(state2, input) {
queue.push_back((new_state1, new_state2));
}
}
}
}
common
}
fn reachable_states_set(&self) -> HashSet<Self::State> {
let mut reachable = HashSet::new();
let mut queue = VecDeque::new();
for initial_state in self.initial_states() {
queue.push_back(initial_state);
}
while let Some(state) = queue.pop_front() {
if reachable.contains(&state) {
continue;
}
reachable.insert(state);
for input in self.alphabet() {
for successor in self.successors(state, &input) {
queue.push_back(successor);
}
}
}
reachable
}
fn is_empty_language(&self) -> bool {
!self.reachable_states_set().iter().any(|&s| self.is_accepting_state(s))
}
}
fn clone_reduce<T: Clone>(arr: &[T], f: impl Fn(T, &T) -> T) -> Option<T> {
let mut iter = arr.iter();
let item = iter.next()?;
Some(iter.fold(item.clone(), f))
}