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 {
12#if 0
13void print_set(const DFASet& set) {
14 std::cout << "{";
15 for (auto state : set) std::cout << state->id() << ", ";
16 std::cout << "}\n";
17}
18#endif
19
20DFASet get_accepting_states(const DFASet& reachableStates) {
21 DFASet acceptingStates;
22 for (auto state : reachableStates)
23 if (state->is_accepting()) acceptingStates.insert(state);
24 return acceptingStates;
25}
26
27DFASet get_erroring_states(const DFASet& reachableStates) {
28 DFASet erroringStates;
29 for (auto state : reachableStates)
30 if (state->is_erroring()) erroringStates.insert(state);
31 return erroringStates;
32}
33
34std::set<std::uint16_t> get_alphabet(const DFASet& reachableStates) {
35 std::set<std::uint16_t> alphabet;
36 for (auto state : reachableStates)
37 state->for_transitions([&](auto c, auto) { alphabet.insert(c); });
38 return alphabet;
39}
40
41DFASet operator-(const DFASet& lhs, const DFASet& rhs) {
42 DFASet result;
43 for (auto state : lhs)
44 if (!rhs.contains(state)) result.insert(state);
45 return result;
46}
47DFASet operator*(const DFASet& lhs, const DFASet& rhs) {
48 DFASet result;
49 for (auto state : lhs)
50 if (rhs.contains(state)) result.insert(state);
51 return result;
52}
53
54std::vector<DFASet> hopcroft(const DFASet& reachableStates) {
55 const auto alphabet = get_alphabet(reachableStates);
56
57 const auto F = get_accepting_states(reachableStates);
58 const auto E = get_erroring_states(reachableStates);
59
60 assert((F * E).empty() && "F and E must be disjoint");
61
62 std::vector<DFASet> P = {F, E, reachableStates - F - E};
63 std::vector<DFASet> W = {F, E, reachableStates - F - E};
64
65 std::vector<DFASet> newP;
66 while (!W.empty()) {
67#if 0
68 std::cout << "P: ";
69 for (const auto& S : P) print_set(S);
70 std::cout << "W: ";
71 for (const auto& S : W) print_set(S);
72#endif
73 auto A = W.back();
74 W.pop_back();
75 for (auto c : alphabet) {
76 DFASet X{};
77 for (const auto* state : reachableStates) {
78 state->for_transitions([&](auto c_, auto to) {
79 if (c_ == c && A.contains(to)) X.insert(state);
80 });
81 }
82 newP.clear();
83 for (const auto& Y : P) {
84 auto YnX = Y * X;
85 auto Y_X = Y - X;
86 if (!YnX.empty() && !Y_X.empty()) {
87 newP.push_back(YnX);
88 newP.push_back(Y_X);
89 if (auto YWit = std::find(W.begin(), W.end(), Y); YWit != W.end()) {
90 W.erase(YWit);
91 W.push_back(YnX);
92 W.push_back(Y_X);
93 } else {
94 if (YnX.size() <= Y_X.size())
95 W.push_back(YnX);
96 else
97 W.push_back(Y_X);
98 }
99 } else
100 newP.push_back(Y);
101 }
102 std::swap(P, newP);
103 }
104 }
105
106 return P;
107}
108
109} // namespace
110
111namespace automaton {
112
113std::unique_ptr<DFA> minimize_dfa(const DFA& dfa) {
114 const auto reachableStates = dfa.get_reachable_states();
115
116 const auto P = hopcroft(reachableStates);
117
118 auto minDfa = std::make_unique<DFA>();
119 DFAMap<DFANode*> dfaStates;
120 for (auto& X : P) {
121 auto state = minDfa->add_state();
122 for (auto x : X) {
123 if (x->is_accepting()) state->set_accepting(true);
124 if (x->is_erroring()) state->set_erroring(true);
125 dfaStates.emplace(x, state);
126 }
127 }
128 minDfa->set_start(dfaStates[dfa.get_start()]);
129 for (auto& X : P) {
130 if (!X.empty()) {
131 auto state = dfaStates[*X.begin()];
132 for (auto x : X)
133 x->for_transitions([&](auto c, auto to) { state->add_transition(dfaStates[to], c); });
134 }
135 }
136 return minDfa;
137}
138
139} // 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:34
const NodeType * get_start() const
Definition automaton.h:31
std::unique_ptr< DFA > minimize_dfa(const DFA &dfa)
Definition dfamin.cpp:113
std::set< const DFANode *, DFANode::Lt > DFASet
Definition dfa.h:76
std::map< const DFANode *, To, DFANode::Lt > DFAMap
Definition dfa.h:75