1use crate::{Dfa, Output, StateRef};
2use std::collections::{BTreeSet, HashMap};
3
4impl Dfa {
5 pub fn into_minimized(self) -> Self {
7 let mut accept_partitions = HashMap::<Output, Vec<StateRef>>::new();
8 for (state, output) in self.accepts.iter() {
9 if let Some(output) = output {
10 accept_partitions
11 .entry(output.clone())
12 .and_modify(|e| e.push(*state))
13 .or_insert(vec![*state]);
14 }
15 }
16 let mut p = BTreeSet::new();
17 for (_, states) in accept_partitions {
18 p.insert(BTreeSet::from_iter(states));
19 }
20 let mut non_accept = BTreeSet::new();
21 for s in 0..self.states.len() {
22 if !self.accepts.contains_key(&StateRef(s)) {
23 non_accept.insert(StateRef(s));
24 }
25 }
26 if !non_accept.is_empty() {
27 p.insert(non_accept);
28 }
29 let mut w = p.clone();
30
31 while !w.is_empty() {
32 let a = w.pop_last().unwrap();
33 for b in u8::MIN..=u8::MAX {
34 let mut x = BTreeSet::new();
35 for (num, s) in self.states.iter().enumerate() {
36 for t in s.transitions.iter() {
37 let from = StateRef(num);
38 if a.contains(&t.to) && t.when.contains(b) {
39 x.insert(from);
40 }
41 }
42 }
43 if x.is_empty() {
44 continue;
45 }
46 let mut replacements = Vec::with_capacity(p.len());
47 for y in p.iter() {
48 let cut = x.intersection(y).copied().collect::<BTreeSet<_>>();
49 let diff = y.difference(&x).copied().collect::<BTreeSet<_>>();
50 if !cut.is_empty() && !diff.is_empty() {
51 if w.contains(y) {
52 w.remove(y);
53 w.insert(cut.clone());
54 w.insert(diff.clone());
55 } else if cut.len() < diff.len() {
56 w.insert(cut.clone());
57 } else {
58 w.insert(diff.clone());
59 }
60 replacements.push((y.clone(), (cut, diff)));
61 }
62 }
63 for (y, (cut, diff)) in replacements.into_iter() {
64 p.remove(&y);
65 p.insert(cut);
66 p.insert(diff);
67 }
68 }
69 }
70
71 let mut automaton = Dfa::new();
72 let mut new_states = HashMap::new();
73 for partition in p.iter() {
74 let state = if partition.contains(&self.start) {
75 automaton.start
76 } else {
77 automaton.add()
78 };
79 for s in partition {
80 new_states.insert(s, state);
81 }
82 }
83 for partition in p.iter() {
84 for s in partition {
85 let state = new_states[&s];
86 if let Some(tok) = self.accepts.get(s) {
87 let _ = automaton.set_accept_output(state, tok.clone());
88 }
89 for t in self.states[s.0].transitions.iter() {
90 let to = new_states[&t.to];
91 automaton.add_transition(state, t.when.clone(), to);
92 }
93 }
94 }
95 automaton
96 }
97}