use super::superstate::Superstate;
use super::Label;
use super::{
Automaton, NfaState::*, NfaStateId, NondeterministicAutomaton, State as DfaStateId,
TransitionTable,
};
use crate::debug;
use smallvec::smallvec;
use vector_map::VecMap;
pub(crate) fn minimize(nfa: NondeterministicAutomaton) -> Automaton {
let minimizer = Minimizer {
nfa,
superstates: VecMap::new(),
checkpoints: VecMap::new(),
active_superstates: vec![],
dfa_states: vec![],
};
minimizer.run()
}
pub(crate) struct Minimizer<'q> {
nfa: NondeterministicAutomaton<'q>,
superstates: VecMap<Superstate, DfaStateId>,
checkpoints: VecMap<Superstate, NfaStateId>,
active_superstates: Vec<Superstate>,
dfa_states: Vec<TransitionTable<'q>>,
}
impl<'q> Minimizer<'q> {
fn run(mut self) -> Automaton<'q> {
self.dfa_states.push(TransitionTable {
transitions: smallvec![],
fallback_state: Self::rejecting_state(),
});
let initial_superstate = [NfaStateId(0)].into();
self.activate_if_new(initial_superstate);
while let Some(superstate) = self.active_superstates.pop() {
self.process_superstate(superstate);
}
Automaton {
states: self.dfa_states,
}
}
fn rejecting_state() -> DfaStateId {
DfaStateId(0)
}
fn activate_if_new(&mut self, superstate: Superstate) {
if !self.superstates.contains_key(&superstate) {
let identifier = DfaStateId(self.superstates.len() as u8 + 1);
self.superstates.insert(superstate, identifier);
self.active_superstates.push(superstate);
debug!("New superstate created: {superstate:?} {identifier}");
}
}
fn process_superstate(&mut self, current_superstate: Superstate) {
let current_checkpoint = self.determine_checkpoint(current_superstate);
debug!(
"Expanding superstate: {current_superstate:?}, last checkpoint is {current_checkpoint:?}"
);
let mut transitions = self.process_nfa_transitions(current_superstate);
debug!("Raw transitions: {:?}", transitions);
self.normalize_superstate_transitions(&mut transitions, current_checkpoint);
debug!("Normalized transitions: {:?}", transitions);
let translated_transitions = transitions
.into_iter()
.map(|(label, state)| (label, self.superstates[&state]))
.collect();
debug!("Translated transitions: {translated_transitions:?}");
self.dfa_states.push(TransitionTable {
transitions: translated_transitions,
fallback_state: current_checkpoint
.map(|x| [x].into())
.map_or(Self::rejecting_state(), |x: Superstate| {
self.superstates[&x]
}),
});
}
fn determine_checkpoint(&mut self, superstate: Superstate) -> Option<NfaStateId> {
if let Some(nfa_state) = self.as_checkpoint(superstate) {
self.checkpoints.insert(superstate, nfa_state);
Some(nfa_state)
} else {
self.checkpoints.get(&superstate).copied()
}
}
fn as_checkpoint(&self, superstate: Superstate) -> Option<NfaStateId> {
if let Some(single_state) = superstate.singleton() {
if matches!(self.nfa[single_state], Recursive(_)) {
return Some(single_state);
}
}
None
}
fn process_nfa_transitions(
&self,
current_superstate: Superstate,
) -> VecMap<&'q Label, Superstate> {
let mut transitions: VecMap<&Label, Superstate> = VecMap::new();
for nfa_state in current_superstate.iter() {
match self.nfa[nfa_state] {
Direct(label) | Recursive(label) => {
debug!(
"Considering transition {nfa_state} --{label:?}-> {}",
nfa_state.next()
);
if let Some(target) = transitions.get_mut(&label) {
target.insert(nfa_state.next());
} else {
transitions.insert(label, [nfa_state.next()].into());
}
}
Accepting => (),
}
}
transitions
}
fn normalize_superstate_transitions(
&mut self,
transitions: &mut VecMap<&Label, Superstate>,
current_checkpoint: Option<NfaStateId>,
) {
for (_, state) in transitions.iter_mut() {
if let Some(checkpoint) = current_checkpoint {
state.insert(checkpoint);
}
self.normalize(state);
self.activate_if_new(*state);
if let Some(checkpoint) = current_checkpoint {
self.checkpoints.insert(*state, checkpoint);
}
}
}
fn normalize(&self, superstate: &mut Superstate) {
let furthest_checkpoint = superstate
.iter()
.filter(|&x| matches!(self.nfa[x], Recursive(_)))
.max();
if let Some(cutoff) = furthest_checkpoint {
superstate.remove_all_before(cutoff);
}
}
}