use std::collections::{HashSet, VecDeque};
use std::hash::Hash;
use crate::labeled::arbitrary::NonDeterministicLabeledAutomaton;
use crate::labeled::finite::automaton::FiniteLabeledAutomaton;
use crate::labeled::finite::deterministic::DeterministicFiniteLabeledAutomaton;
use crate::utility::clone_reduce;
pub trait NonDeterministicFiniteLabeledAutomaton<Label: Hash + Eq + Clone>:
NonDeterministicLabeledAutomaton<Label> + FiniteLabeledAutomaton<Label>
{
type CorrespondingDFA: DeterministicFiniteLabeledAutomaton<
Label,
State = Self::State,
Input = Self::Input,
CorrespondingNFA = Self,
>;
fn to_dfa_by(&self, combine: impl Fn(Label, Label) -> Label) -> Self::CorrespondingDFA;
fn union(&self, other: &Self) -> Self;
fn union_all(automata: &[Self]) -> Option<Self>
where
Self: Clone,
{
clone_reduce(automata, |a, b| a.union(b))
}
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
}
}