MimIR
MimIR is my Intermediate Representation
Loading...
Searching...
No Matches
dfamin.cpp
Go to the documentation of this file.
1#include "automaton/dfamin.h"
2
3#include <algorithm>
4#include <memory>
5#include <set>
6
7#include "automaton/dfa.h"
8
9using namespace automaton;
10
11namespace {
12DFASet get_accepting_states(const DFASet& reachableStates) {
13 DFASet acceptingStates;
14 for (auto state : reachableStates)
15 if (state->is_accepting()) acceptingStates.insert(state);
16 return acceptingStates;
17}
18
19DFASet get_erroring_states(const DFASet& reachableStates) {
20 DFASet erroringStates;
21 for (auto state : reachableStates)
22 if (state->is_erroring()) erroringStates.insert(state);
23 return erroringStates;
24}
25
26std::set<std::uint16_t> get_alphabet(const DFASet& reachableStates) {
27 std::set<std::uint16_t> alphabet;
28 for (auto state : reachableStates)
29 state->for_transitions([&](auto c, auto) { alphabet.insert(c); });
30 return alphabet;
31}
32
33DFASet operator-(const DFASet& lhs, const DFASet& rhs) {
34 DFASet result;
35 for (auto state : lhs)
36 if (!rhs.contains(state)) result.insert(state);
37 return result;
38}
39DFASet operator*(const DFASet& lhs, const DFASet& rhs) {
40 DFASet result;
41 for (auto state : lhs)
42 if (rhs.contains(state)) result.insert(state);
43 return result;
44}
45
46std::vector<DFASet> hopcroft(const DFASet& reachableStates) {
47 const auto alphabet = get_alphabet(reachableStates);
48
49 const auto F = get_accepting_states(reachableStates);
50 const auto E = get_erroring_states(reachableStates);
51
52 assert((F * E).empty() && "F and E must be disjoint");
53
54 // An empty block would never split and so end up as an orphan state.
55 auto P = std::vector<DFASet>();
56 for (auto&& S : {F, E, reachableStates - F - E})
57 if (!S.empty()) P.push_back(S);
58 auto W = P;
59
60 std::vector<DFASet> newP;
61 while (!W.empty()) {
62 auto A = W.back();
63 W.pop_back();
64 for (auto c : alphabet) {
65 DFASet X{};
66 for (const auto* state : reachableStates) {
67 state->for_transitions([&](auto c_, auto to) {
68 if (c_ == c && A.contains(to)) X.insert(state);
69 });
70 }
71 newP.clear();
72 for (const auto& Y : P) {
73 auto YnX = Y * X;
74 auto Y_X = Y - X;
75 if (!YnX.empty() && !Y_X.empty()) {
76 newP.push_back(YnX);
77 newP.push_back(Y_X);
78 if (auto YWit = std::find(W.begin(), W.end(), Y); YWit != W.end()) {
79 W.erase(YWit);
80 W.push_back(YnX);
81 W.push_back(Y_X);
82 } else {
83 if (YnX.size() <= Y_X.size())
84 W.push_back(YnX);
85 else
86 W.push_back(Y_X);
87 }
88 } else
89 newP.push_back(Y);
90 }
91 std::swap(P, newP);
92 }
93 }
94
95 return P;
96}
97
98} // namespace
99
100namespace automaton {
101
102std::unique_ptr<DFA> minimize_dfa(const DFA& dfa) {
103 const auto reachableStates = dfa.get_reachable_states();
104
105 const auto P = hopcroft(reachableStates);
106
107 auto minDfa = std::make_unique<DFA>();
108 DFAMap<DFANode*> dfaStates;
109 for (auto& X : P) {
110 auto state = minDfa->add_state();
111 for (auto x : X) {
112 if (x->is_accepting()) state->set_accepting(true);
113 if (x->is_erroring()) state->set_erroring(true);
114 dfaStates.emplace(x, state);
115 }
116 }
117 minDfa->set_start(dfaStates[dfa.get_start()]);
118 for (auto& X : P) {
119 auto state = dfaStates[*X.begin()];
120 for (auto x : X)
121 x->for_transitions([&](auto c, auto to) { state->add_transition(dfaStates[to], c); });
122 }
123 return minDfa;
124}
125
126} // namespace automaton
std::set< const NodeType *, typename NodeType::Lt > get_reachable_states() const
Ordered by NodeType::Lt (i.e. by id) so that iteration is deterministic.
Definition automaton.h:38
const NodeType * get_start() const
Definition automaton.h:34
std::unique_ptr< DFA > minimize_dfa(const DFA &dfa)
Definition dfamin.cpp:102
std::set< const DFANode *, DFANode::Lt > DFASet
Definition dfa.h:71
std::map< const DFANode *, To, DFANode::Lt > DFAMap
Definition dfa.h:70