36 static unsigned nextId;
45template<
class T_Inputs>
49 static bool equalInput(
const T_Inputs &a,
const T_Inputs &b);
52 static void inputUnion(T_Inputs &dst,
const T_Inputs &src);
56template<
class T_Inputs,
class T_Action,
class C_Traits>
class C_DFA;
58template<
class T_Inputs,
class T_Action,
class C_Traits = C_FA_Traits<T_Inputs>>
94 C_FinalState() =
default;
97 typedef std::vector<C_FinalState> C_FinalStates;
102 T_Inputs m_UserInputs;
106 C_NfaInputSet(
bool epsilon =
false): m_Epsilon(epsilon) {}
108 typedef std::map<C_NfaState,C_NfaInputSet> C_Transitions;
109 typedef std::map<C_NfaState,C_Transitions> C_TransitionMap;
114 C_TransitionMap delta;
117 void gatherStates(std::set<C_NfaState> &usedStates)
const;
118 const C_NFA &checkReuse(
const std::set<C_NfaState> &usedStates,
C_NFA &replacement)
const;
120 friend class C_DFA<T_Inputs,T_Action,C_Traits>;
123template<
class T_Inputs,
class T_Action,
class C_Traits = C_FA_Traits<T_Inputs>>
138 template<
class F_PickAction>
140 requires (
int tag,
const C_Conflict &conflict) {
141 { pickAction(tag, conflict) }->std::convertible_to<T_Action>;
146 auto n = nfa2dfa(nfa, Fraw, deltaRaw, pickAction);
147 minDfa(Fraw, deltaRaw, n, F, delta);
149 template<
class F_Get>
150 void eachFinalState(F_Get get)
const requires std::invocable<F_Get,int,const T_Action&>
152 for (
const auto &i: F)
153 get(i.first, i.second);
155 template<
class F_Get>
156 void eachTransition(F_Get get)
const requires std::invocable<F_Get,int,const T_Inputs&,int>
158 for (
const auto &i: delta)
159 for (
const auto &j: i.second)
160 get(i.first, j.second, j.first);
162 bool isFinal(
int state, T_Action &action)
const;
170 typedef std::set<C_NfaState> C_NfaClosure;
172 struct C_TaggedNfaClosure
174 C_NfaClosure m_Closure;
177 C_TaggedNfaClosure(
const C_NfaClosure &closure):
178 m_Closure(closure), m_Tag(0)
182 typedef typename C_NFA<T_Inputs,T_Action,C_Traits>::C_TransitionMap C_SourceDelta;
183 typedef std::map<int,T_Action> C_FinalMap;
184 typedef std::map<int,T_Inputs> C_State2Inputs;
185 typedef std::map<int,C_State2Inputs> C_TransitionMap;
187 typedef std::set<int> C_DfaClosure;
188 struct C_TaggedDfaClosure
190 C_DfaClosure m_Closure;
195 C_TaggedDfaClosure(
const C_DfaClosure& closure): m_Closure(closure)
198 typedef std::list<C_TaggedDfaClosure> C_DfaClosures;
199 typedef std::map<T_Action,C_DfaClosure> C_Action2Closure;
203 C_TransitionMap delta;
206 static void buildA2C(
const C_FinalMap &Ffat,
const C_DfaClosure &closure,
207 C_Action2Closure &a2c);
208 static void createClosure(C_NfaClosure &c,
const C_SourceDelta &delta);
209 static typename C_DfaClosures::const_iterator findDfaClosure(
const C_DfaClosures &Q,
int state);
210 static void minDfa(
const C_FinalMap &Ffat,
const C_TransitionMap &deltaFat,
211 int totalFatStates, C_FinalMap &Fmin, C_TransitionMap &deltaMin);
212 template<
class F_PickAction>
213 static int nfa2dfa(
const C_NFA<T_Inputs,T_Action,C_Traits> &nfa, C_FinalMap &F,
214 C_TransitionMap &delta, F_PickAction pickAction);
221template<
class T_Inputs,
class T_Action,
class C_Traits>
223 q0(a.q0), F(a.F), delta(a.delta)
227template<
class T_Inputs,
class T_Action,
class C_Traits>
234template<
class T_Inputs,
class T_Action,
class C_Traits>
238 delta[q0][f].m_UserInputs = inputs;
242template<
class T_Inputs,
class T_Action,
class C_Traits>
250template<
class T_Inputs,
class T_Action,
class C_Traits>
258template<
class T_Inputs,
class T_Action,
class C_Traits>
265 std::set<C_NfaState> usedStates;
266 gatherStates(usedStates);
268 const C_NFA &a = _a.checkReuse(usedStates, _);
269 F.insert(F.end(), a.F.begin(), a.F.end());
270 delta.insert(a.delta.begin(), a.delta.end());
271 delta[q0][a.q0].m_Epsilon =
true;
275template<
class T_Inputs,
class T_Action,
class C_Traits>
282 std::set<C_NfaState> usedStates;
283 gatherStates(usedStates);
285 const C_NFA &a = _a.checkReuse(usedStates, _);
286 delta.insert(a.delta.begin(), a.delta.end());
287 for (
const auto &i: F)
288 delta[i][a.q0].m_Epsilon =
true;
294template<
class T_Inputs,
class T_Action,
class C_Traits>
299 delta[q0][f].m_UserInputs = inputs;
302 for (
const auto &i: F)
303 delta[i][f].m_UserInputs = inputs;
311template<
class T_Inputs,
class T_Action,
class C_Traits>
314 for (
const auto &i: F)
317 delta[i][q0].m_Epsilon =
true;
319 delta[q0][i].m_Epsilon =
true;
324template<
class T_Inputs,
class T_Action,
class C_Traits>
326 const std::set<C_NfaState> &usedStates,
329 typedef std::map<C_NfaState,C_NfaState> C_Map;
331 for (
const auto &i: delta)
333 if (usedStates.find(i.first) != usedStates.end())
336 for (
const auto &j: i.second)
337 if (usedStates.find(j.first) != usedStates.end())
344 C_Map::const_iterator found = map.find(q0);
345 replacement.q0 = found != map.end()? found->second: q0;
347 for (
const auto &i: F)
350 replacement.F.emplace_back(found != map.end()? found->second: i, i.m_Tag);
353 for (
const auto &i: delta)
355 found = map.find(i.first);
356 auto &t =replacement.delta[found != map.end()? found->second: i.first];
357 for (
const auto &j: i.second)
359 found = map.find(j.first);
360 t[found != map.end()? found->second: j.first] =j.second;
366template<
class T_Inputs,
class T_Action,
class C_Traits>
367void C_NFA<T_Inputs,T_Action,C_Traits>::gatherStates(std::set<C_NfaState> &usedStates)
const
369 for (
const auto &i: delta)
371 usedStates.insert(i.first);
372 for (
const auto &j: i.second)
373 usedStates.insert(j.first);
377template<
class T_Inputs,
class T_Action,
class C_Traits>
382 i.m_Tag = std::forward<T>(action);
385template<
class T_Inputs,
class T_Action,
class C_Traits>
386void C_DFA<T_Inputs,T_Action,C_Traits>::buildA2C(
387 const C_FinalMap &Ffat,
388 const C_DfaClosure &closure,
389 C_Action2Closure &a2c )
391 for (
const auto &i: Ffat)
393 if (closure.find(i.first) != closure.end())
394 a2c[i.second].insert(i.first);
398template<
class T_Inputs,
class T_Action,
class C_Traits>
399void C_DFA<T_Inputs,T_Action,C_Traits>::createClosure(C_NfaClosure &c,
const C_SourceDelta &delta)
401 C_NfaClosure test(c);
405 for (
const auto &i: test)
407 const auto found = delta.find(i);
408 if (found != delta.end())
410 for (
const auto &j: found->second)
411 if (j.second.m_Epsilon && c.find(j.first) == c.end())
418 c.insert(add.begin(), add.end());
423template<
class T_Inputs,
class T_Action,
class C_Traits>
424auto C_DFA<T_Inputs,T_Action,C_Traits>::findDfaClosure(
const C_DfaClosures &Q,
int state) ->
typename C_DfaClosures::const_iterator
426 for (
auto i = Q.begin(), end = Q.end(); i != end; ++i)
428 if (i->m_Closure.find(state) != i->m_Closure.end())
435template<
class T_Inputs,
class T_Action,
class C_Traits>
438 const auto i =F.find(state);
447template<
class T_Inputs,
class T_Action,
class C_Traits>
448void C_DFA<T_Inputs,T_Action,C_Traits>::minDfa(
449 const C_FinalMap &Ffat,
459 auto &part0 = Qfat.front().m_Closure;
460 auto &part1 = Qfat.back().m_Closure;
462 for (
const auto &i: Ffat)
464 part0.insert(i.first);
465 while (tag < i.first)
470 while (tag < totalFatStates)
478 for (
const auto &i: Qfat)
480 auto fat = i.m_Closure;
484 auto j = fat.begin();
486 typedef std::map<const C_DfaClosure*,T_Inputs> C_CmpMap;
488 auto k = deltaFat.find(*j);
489 if (k != deltaFat.end())
490 for (
const auto &m: k->second)
491 cmpmap[&findDfaClosure(Qfat, m.first)->m_Closure] = m.second;
493 while (++j != fat.end())
497 k = deltaFat.find(*j);
498 if (k != deltaFat.end())
499 for (
const auto &m: k->second)
501 const auto *t = &findDfaClosure(Qfat, m.first)->m_Closure;
502 auto found = cmpmap.find(t);
503 if (found != cmpmap.end() &&
504 C_Traits::equalInput(m.second, found->second))
514 auto i_map = map.begin();
515 for (
auto &j_cmp: cmpmap)
517 if (i_map == map.end() ||
518 i_map->first != j_cmp.first ||
519 !C_Traits::equalInput(i_map->second, j_cmp.second))
526 if (deal && i_map == map.end())
530 Qmin.emplace_back(slim);
532 std::set_difference(fat.begin(), fat.end(),
533 slim.begin(), slim.end(), std::inserter(temp, temp.begin()));
537 if (Qmin.size() == Qfat.size())
539 for (
auto i =Qmin.begin(), end =Qmin.end(); i != end; ++i)
541 C_Action2Closure a2c;
542 buildA2C(Ffat, i->m_Closure, a2c);
546 auto j = a2c.begin();
547 i->m_Closure.swap(j->second);
550 while (++j != a2c.end())
551 i = Qmin.insert(next, j->second);
555 if (Qmin.size() != Qfat.size())
564 for (
auto i = Qfat.begin(), end = Qfat.end(); i != end; ++i, ++tag)
566 if (tag && i->m_Closure.find(0) != i->m_Closure.end())
570 Qfat.front().m_Tag = tag;
571 auto t = Fmin.find(0);
574 const auto a = t->second;
582 C_Action2Closure a2c;
583 buildA2C(Ffat, i->m_Closure, a2c);
586 Fmin[i->m_Tag] = a2c.begin()->first;
592 for (
const auto &i: deltaFat)
594 auto &dst_i = deltaMin[findDfaClosure(Qfat,i.first)->m_Tag];
595 for (
const auto &j: i.second)
597 const auto value = findDfaClosure(Qfat,j.first)->m_Tag;
598 for (
const auto &dst_j: dst_i)
600 if (C_Traits::equalInput(dst_j.second, j.second))
602 if (dst_j.first == value)
609 C_Traits::inputUnion(dst_i[value], j.second);
615template<
class T_Inputs,
class T_Action,
class C_Traits>
616template<
class F_PickAction>
621 std::list<C_TaggedNfaClosure> Q;
622 Q.emplace_back(C_NfaClosure{});
623 auto *
const q0 = &Q.front().m_Closure;
625 createClosure(*q0, nfa.delta);
627 typedef std::pair<T_Inputs, const C_TaggedNfaClosure*> C_InputClosurePair;
628 typedef std::vector<C_InputClosurePair> C_Input2Closure;
629 std::map<
const C_TaggedNfaClosure*, C_Input2Closure,
630 bool (*)(
const C_TaggedNfaClosure*,
const C_TaggedNfaClosure*)>
631 deltaNfa([](
const C_TaggedNfaClosure *a,
const C_TaggedNfaClosure *b)->
bool {
632 return a->m_Closure < b->m_Closure;
643 typedef std::map<C_NfaClosure,T_Inputs> C_ShiftMap;
646 for (
const auto &j: q.m_Closure)
648 auto found = nfa.delta.find(j);
649 if (found != nfa.delta.end())
650 for (
const auto &k: found->second)
652 if (!C_Traits::isEmptyInput(k.second.m_UserInputs))
656 C_Traits::inputUnion(map[key], k.second.m_UserInputs);
661 C_ShiftMap partitionedMap;
666 partitionedMap.insert(*map.begin());
671 for (
auto i = map.begin(), end = map.end(); i != end; ++i)
672 for (
auto j = i; ++j != end;)
675 T_Inputs insetsect(i->second);
676 C_Traits::inputIntersection(insetsect, j->second);
677 if (C_Traits::isEmptyInput(insetsect))
680 if (map.begin() != i)
683 partitionedMap.insert(map.begin(), i);
684 map.erase(map.begin(), i);
686 C_NfaClosure key(i->first);
687 key.insert(j->first.begin(), j->first.end());
689 T_Inputs t(i->second);
690 C_Traits::inputDifference(t, insetsect);
691 if (C_Traits::isEmptyInput(t))
697 C_Traits::inputDifference(t, insetsect);
698 if (C_Traits::isEmptyInput(t))
706 partitionedMap.insert(map.begin(), map.end());
708 map.swap(partitionedMap);
714 for (
const auto &j: map)
716 C_TaggedNfaClosure t(j.first);
717 createClosure(t.m_Closure, nfa.delta);
718 const C_TaggedNfaClosure *next;
719 for (
const auto &k: Q)
720 if (t.m_Closure == k.m_Closure)
728 deltaNfa[&q].emplace_back(j.second, next);
739 for (
const auto &j: nfa.F)
741 if (i.m_Closure.find(j) != i.m_Closure.end())
742 conflict.insert(j.m_Tag);
744 if (!conflict.empty())
746 if (conflict.size() > 1)
749 auto action = pickAction(i.m_Tag, conflict);
750 if (action == T_Action())
756 F[i.m_Tag] = *conflict.begin();
760 for (
const auto &i: deltaNfa)
762 auto &dstMap = delta[i.first->m_Tag];
763 for (
const auto &j: i.second)
764 C_Traits::inputUnion(dstMap[j.second->m_Tag], j.first);
#define RUNTIME_ERROR(fmtStr,...)
Wrap FILE(DATE)#__LINE__ FUNCTION: msg into std::runtime_error.
static int startingState()
void eachFinalState(F_Get get) const
std::set< T_Action > C_Conflict
size_t totalFinalStates() const
C_DFA(const C_NFA< T_Inputs, T_Action, C_Traits > &nfa, F_PickAction pickAction)
bool isFinal(int state, T_Action &action) const
void eachTransition(F_Get get) const
void operator|=(const C_NFA &a)
void operator=(C_NFA &&a)
C_NFA & append(const C_NFA &a)
void operator+=(const T_Inputs &inputs)
void operator+=(const C_NFA &a)
C_NFA & changeTo(int options)
size_t totalFinalStates() const
void setAction(T &&action)
C_NFA(const T_Inputs &inputs)
void operator=(const C_NFA &a)
C_NFA & append(const T_Inputs &inputs)
C_NfaState(const C_NfaState &a)=default
bool operator==(const C_NfaState &a) const
auto operator<=>(const C_NfaState &a) const
C_NfaState & operator=(const C_NfaState &a)=default
THE common namespace of bux library.
static void inputUnion(T_Inputs &dst, const T_Inputs &src)
static bool isEmptyInput(const T_Inputs &src)
static void inputDifference(T_Inputs &dst, const T_Inputs &src)
static bool equalInput(const T_Inputs &a, const T_Inputs &b)
static void inputIntersection(T_Inputs &dst, const T_Inputs &src)