use dfa::{Dfa, RetTrait};
use nfa::{Accept, StateIdx, StateSet};
use range_map::{RangeMultiMap, RangeSet};
use refinery::Partition;
use std::collections::{HashSet, HashMap};
pub struct Minimizer {
partition: Partition,
distinguishers: HashSet<usize>,
rev: Vec<RangeMultiMap<u8, StateIdx>>,
}
impl Minimizer {
fn initial_partition<Ret: RetTrait>(dfa: &Dfa<Ret>) -> Vec<Vec<StateIdx>> {
let mut part: HashMap<(Accept, Option<&Ret>, RangeSet<u8>), Vec<StateIdx>> = HashMap::new();
for (idx, st) in dfa.states.iter().enumerate() {
let chars = st.transitions.to_range_set();
part.entry((st.accept, dfa.ret(idx), chars)).or_insert_with(Vec::new).push(idx);
}
part.into_iter().map(|x| x.1).collect()
}
fn refine(&mut self, splitter: &[StateIdx]) {
let dists = &mut self.distinguishers;
self.partition.refine_with_callback(splitter, |p, int_idx, diff_idx| {
if dists.contains(&int_idx) || p.part(diff_idx).len() < p.part(int_idx).len() {
dists.insert(diff_idx);
} else {
dists.insert(int_idx);
}
});
}
fn next_distinguisher(&mut self) -> Option<usize> {
let maybe_elt = self.distinguishers.iter().next().cloned();
if let Some(elt) = maybe_elt {
self.distinguishers.remove(&elt);
}
maybe_elt
}
fn get_input_sets(&mut self, part_idx: usize) -> Vec<StateSet> {
let inputs: Vec<_> = self.partition.part(part_idx)
.iter()
.flat_map(|s| self.rev[*s].ranges_values().cloned())
.collect();
if inputs.is_empty() {
return Vec::new();
}
let inputs = RangeMultiMap::from_vec(inputs);
let mut sets: Vec<StateSet> = inputs.group()
.ranges_values()
.map(|&(_, ref x)| x.clone())
.collect();
for set in &mut sets {
set.sort();
}
sets.sort();
sets.dedup();
sets
}
fn compute_partition(&mut self) {
while let Some(dist) = self.next_distinguisher() {
let sets = self.get_input_sets(dist);
for set in &sets {
self.refine(set);
}
}
}
pub fn minimize<Ret: RetTrait>(dfa: &Dfa<Ret>) -> Dfa<Ret> {
let mut min = Minimizer::new(dfa);
min.compute_partition();
let mut ret = Dfa::new();
let mut old_state_to_new = vec![0; dfa.num_states()];
for part in min.partition.iter() {
let rep_idx = *part.iter().next().unwrap();
ret.states.push(dfa.states[rep_idx].clone());
for &state in part.iter() {
old_state_to_new[state] = ret.states.len() - 1;
}
}
ret.map_states(|s: StateIdx| old_state_to_new[s]);
ret.init = dfa.init.iter()
.map(|x| x.map(|s: StateIdx| old_state_to_new[s]))
.collect();
ret
}
fn new<Ret: RetTrait>(dfa: &Dfa<Ret>) -> Minimizer {
let init = Minimizer::initial_partition(dfa);
let part = Partition::new(init.into_iter().map(|set| set.into_iter()), dfa.num_states());
let mut dists: HashSet<usize> = (0..part.num_parts()).collect();
let worst = (0..dists.len())
.filter(|i| dfa.states[part.part(*i)[0]].accept == Accept::Never)
.max_by_key(|i| part.part(*i).len());
if let Some(worst) = worst {
dists.remove(&worst);
}
Minimizer {
partition: part,
distinguishers: dists,
rev: dfa.reversed_transitions(),
}
}
}