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