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