35 static unsigned nextId;
44template<
class T_Inputs>
48 static bool equalInput(
const T_Inputs &a,
const T_Inputs &b);
51 static void inputUnion(T_Inputs &dst,
const T_Inputs &src);
55template<
class T_Inputs,
class T_Action,
class C_Traits>
class C_DFA;
57template<
class T_Inputs,
class T_Action,
class C_Traits = C_FA_Traits<T_Inputs>>
72 C_NFA(
const T_Inputs &inputs);
81 template<
class T>
void setAction(T &&action);
93 C_FinalState() =
default;
96 typedef std::vector<C_FinalState> C_FinalStates;
101 T_Inputs m_UserInputs;
105 C_NfaInputSet(
bool epsilon =
false): m_Epsilon(epsilon) {}
107 typedef std::map<C_NfaState,C_NfaInputSet> C_Transitions;
108 typedef std::map<C_NfaState,C_Transitions> C_TransitionMap;
113 C_TransitionMap delta;
116 void gatherStates(std::set<C_NfaState> &usedStates)
const;
117 const C_NFA &checkReuse(
const std::set<C_NfaState> &usedStates,
C_NFA &replacement)
const;
119 friend class C_DFA<T_Inputs,T_Action,C_Traits>;
122template<
class T_Inputs,
class T_Action,
class C_Traits = C_FA_Traits<T_Inputs>>
137 template<
class F_PickAction>
139 requires (
int tag,
const C_Conflict &conflict) {
140 { pickAction(tag, conflict) }->std::convertible_to<T_Action>;
144 C_TransitionMap deltaRaw;
145 auto n = nfa2dfa(nfa, Fraw, deltaRaw, pickAction);
146 minDfa(Fraw, deltaRaw, n, F, delta);
148 template<
class F_Get>
149 void eachFinalState(F_Get get)
const requires std::invocable<F_Get,int,const T_Action&>
151 for (
const auto &i: F)
152 get(i.first, i.second);
154 template<
class F_Get>
155 void eachTransition(F_Get get)
const requires std::invocable<F_Get,int,const T_Inputs&,int>
157 for (
const auto &i: delta)
158 for (
const auto &j: i.second)
159 get(i.first, j.second, j.first);
161 bool isFinal(
int state, T_Action &action)
const;
169 typedef std::set<C_NfaState> C_NfaClosure;
171 struct C_TaggedNfaClosure
173 C_NfaClosure m_Closure;
176 C_TaggedNfaClosure(
const C_NfaClosure &closure):
177 m_Closure(closure), m_Tag(0)
181 typedef typename C_NFA<T_Inputs,T_Action,C_Traits>::C_TransitionMap C_SourceDelta;
182 typedef std::map<int,T_Action> C_FinalMap;
183 typedef std::map<int,T_Inputs> C_State2Inputs;
184 typedef std::map<int,C_State2Inputs> C_TransitionMap;
186 typedef std::set<int> C_DfaClosure;
187 struct C_TaggedDfaClosure
189 C_DfaClosure m_Closure;
194 C_TaggedDfaClosure(
const C_DfaClosure& closure): m_Closure(closure)
197 typedef std::list<C_TaggedDfaClosure> C_DfaClosures;
198 typedef std::map<T_Action,C_DfaClosure> C_Action2Closure;
202 C_TransitionMap delta;
205 static void buildA2C(
const C_FinalMap &Ffat,
const C_DfaClosure &closure,
206 C_Action2Closure &a2c);
207 static void createClosure(C_NfaClosure &c,
const C_SourceDelta &delta);
208 static typename C_DfaClosures::const_iterator findDfaClosure(
const C_DfaClosures &Q,
int state);
209 static void minDfa(
const C_FinalMap &Ffat,
const C_TransitionMap &deltaFat,
210 int totalFatStates, C_FinalMap &Fmin, C_TransitionMap &deltaMin);
211 template<
class F_PickAction>
212 static int nfa2dfa(
const C_NFA<T_Inputs,T_Action,C_Traits> &nfa, C_FinalMap &F,
213 C_TransitionMap &delta, F_PickAction pickAction);
220template<
class T_Inputs,
class T_Action,
class C_Traits>
222 q0(a.q0), F(a.F), delta(a.delta)
226template<
class T_Inputs,
class T_Action,
class C_Traits>
233template<
class T_Inputs,
class T_Action,
class C_Traits>
237 delta[q0][f].m_UserInputs = inputs;
241template<
class T_Inputs,
class T_Action,
class C_Traits>
249template<
class T_Inputs,
class T_Action,
class C_Traits>
257template<
class T_Inputs,
class T_Action,
class C_Traits>
264 std::set<C_NfaState> usedStates;
265 gatherStates(usedStates);
267 const C_NFA &a = _a.checkReuse(usedStates, _);
268 F.insert(F.end(), a.F.begin(), a.F.end());
269 delta.insert(a.delta.begin(), a.delta.end());
270 delta[q0][a.q0].m_Epsilon =
true;
274template<
class T_Inputs,
class T_Action,
class C_Traits>
281 std::set<C_NfaState> usedStates;
282 gatherStates(usedStates);
284 const C_NFA &a = _a.checkReuse(usedStates, _);
285 delta.insert(a.delta.begin(), a.delta.end());
286 for (
const auto &i: F)
287 delta[i][a.q0].m_Epsilon =
true;
293template<
class T_Inputs,
class T_Action,
class C_Traits>
298 delta[q0][f].m_UserInputs = inputs;
301 for (
const auto &i: F)
302 delta[i][f].m_UserInputs = inputs;
310template<
class T_Inputs,
class T_Action,
class C_Traits>
313 for (
const auto &i: F)
316 delta[i][q0].m_Epsilon =
true;
318 delta[q0][i].m_Epsilon =
true;
323template<
class T_Inputs,
class T_Action,
class C_Traits>
325 const std::set<C_NfaState> &usedStates,
328 typedef std::map<C_NfaState,C_NfaState> C_Map;
330 for (
const auto &i: delta)
332 if (usedStates.find(i.first) != usedStates.end())
335 for (
const auto &j: i.second)
336 if (usedStates.find(j.first) != usedStates.end())
343 C_Map::const_iterator found = map.find(q0);
344 replacement.q0 = found != map.end()? found->second: q0;
346 for (
const auto &i: F)
349 replacement.F.emplace_back(found != map.end()? found->second: i, i.m_Tag);
352 for (
const auto &i: delta)
354 found = map.find(i.first);
355 auto &t =replacement.delta[found != map.end()? found->second: i.first];
356 for (
const auto &j: i.second)
358 found = map.find(j.first);
359 t[found != map.end()? found->second: j.first] =j.second;
365template<
class T_Inputs,
class T_Action,
class C_Traits>
366void C_NFA<T_Inputs,T_Action,C_Traits>::gatherStates(std::set<C_NfaState> &usedStates)
const
368 for (
const auto &i: delta)
370 usedStates.insert(i.first);
371 for (
const auto &j: i.second)
372 usedStates.insert(j.first);
376template<
class T_Inputs,
class T_Action,
class C_Traits>
381 i.m_Tag = std::forward<T>(action);
384template<
class T_Inputs,
class T_Action,
class C_Traits>
386 const C_FinalMap &Ffat,
387 const C_DfaClosure &closure,
388 C_Action2Closure &a2c )
390 for (
const auto &i: Ffat)
392 if (closure.find(i.first) != closure.end())
393 a2c[i.second].insert(i.first);
397template<
class T_Inputs,
class T_Action,
class C_Traits>
398void C_DFA<T_Inputs,T_Action,C_Traits>::createClosure(C_NfaClosure &c,
const C_SourceDelta &delta)
400 C_NfaClosure test(c);
404 for (
const auto &i: test)
406 const auto found = delta.find(i);
407 if (found != delta.end())
409 for (
const auto &j: found->second)
410 if (j.second.m_Epsilon && c.find(j.first) == c.end())
417 c.insert(add.begin(), add.end());
422template<
class T_Inputs,
class T_Action,
class C_Traits>
423auto C_DFA<T_Inputs,T_Action,C_Traits>::findDfaClosure(
const C_DfaClosures &Q,
int state) ->
typename C_DfaClosures::const_iterator
425 for (
auto i = Q.begin(), end = Q.end(); i != end; ++i)
427 if (i->m_Closure.find(state) != i->m_Closure.end())
434template<
class T_Inputs,
class T_Action,
class C_Traits>
437 const auto i =F.find(state);
446template<
class T_Inputs,
class T_Action,
class C_Traits>
448 const C_FinalMap &Ffat,
449 const C_TransitionMap &deltaFat,
452 C_TransitionMap &deltaMin )
458 auto &part0 = Qfat.front().m_Closure;
459 auto &part1 = Qfat.back().m_Closure;
461 for (
const auto &i: Ffat)
463 part0.insert(i.first);
464 while (tag < i.first)
469 while (tag < totalFatStates)
477 for (
const auto &i: Qfat)
479 auto fat = i.m_Closure;
483 auto j = fat.begin();
485 typedef std::map<const C_DfaClosure*,T_Inputs> C_CmpMap;
487 auto k = deltaFat.find(*j);
488 if (k != deltaFat.end())
489 for (
const auto &m: k->second)
490 cmpmap[&findDfaClosure(Qfat, m.first)->m_Closure] = m.second;
492 while (++j != fat.end())
496 k = deltaFat.find(*j);
497 if (k != deltaFat.end())
498 for (
const auto &m: k->second)
500 const auto *t = &findDfaClosure(Qfat, m.first)->m_Closure;
501 auto found = cmpmap.find(t);
502 if (found != cmpmap.end() &&
503 C_Traits::equalInput(m.second, found->second))
513 auto i_map = map.begin();
514 for (
auto &j_cmp: cmpmap)
516 if (i_map == map.end() ||
517 i_map->first != j_cmp.first ||
518 !C_Traits::equalInput(i_map->second, j_cmp.second))
525 if (deal && i_map == map.end())
529 Qmin.emplace_back(slim);
531 std::set_difference(fat.begin(), fat.end(),
532 slim.begin(), slim.end(), std::inserter(temp, temp.begin()));
536 if (Qmin.size() == Qfat.size())
538 for (
auto i =Qmin.begin(), end =Qmin.end(); i != end; ++i)
540 C_Action2Closure a2c;
541 buildA2C(Ffat, i->m_Closure, a2c);
545 auto j = a2c.begin();
546 i->m_Closure.swap(j->second);
549 while (++j != a2c.end())
550 i = Qmin.insert(next, j->second);
554 if (Qmin.size() != Qfat.size())
563 for (
auto i = Qfat.begin(), end = Qfat.end(); i != end; ++i, ++tag)
565 if (tag && i->m_Closure.find(0) != i->m_Closure.end())
569 Qfat.front().m_Tag = tag;
570 auto t = Fmin.find(0);
573 const auto a = t->second;
581 C_Action2Closure a2c;
582 buildA2C(Ffat, i->m_Closure, a2c);
585 Fmin[i->m_Tag] = a2c.begin()->first;
591 for (
const auto &i: deltaFat)
593 auto &dst_i = deltaMin[findDfaClosure(Qfat,i.first)->m_Tag];
594 for (
const auto &j: i.second)
596 const auto value = findDfaClosure(Qfat,j.first)->m_Tag;
597 for (
const auto &dst_j: dst_i)
599 if (C_Traits::equalInput(dst_j.second, j.second))
601 if (dst_j.first == value)
608 C_Traits::inputUnion(dst_i[value], j.second);
614template<
class T_Inputs,
class T_Action,
class C_Traits>
615template<
class F_PickAction>
616int C_DFA<T_Inputs,T_Action,C_Traits>::nfa2dfa(
const C_NFA<T_Inputs,T_Action,C_Traits> &nfa,
617 C_FinalMap &F, C_TransitionMap &delta, F_PickAction pickAction)
620 std::list<C_TaggedNfaClosure> Q;
621 Q.emplace_back(C_NfaClosure{});
622 auto *
const q0 = &Q.front().m_Closure;
624 createClosure(*q0, nfa.delta);
626 typedef std::pair<T_Inputs, const C_TaggedNfaClosure*> C_InputClosurePair;
627 typedef std::vector<C_InputClosurePair> C_Input2Closure;
628 std::map<
const C_TaggedNfaClosure*, C_Input2Closure,
629 bool (*)(
const C_TaggedNfaClosure*,
const C_TaggedNfaClosure*)>
630 deltaNfa([](
const C_TaggedNfaClosure *a,
const C_TaggedNfaClosure *b)->
bool {
631 return a->m_Closure < b->m_Closure;
642 typedef std::map<C_NfaClosure,T_Inputs> C_ShiftMap;
645 for (
const auto &j: q.m_Closure)
647 auto found = nfa.delta.find(j);
648 if (found != nfa.delta.end())
649 for (
const auto &k: found->second)
651 if (!C_Traits::isEmptyInput(k.second.m_UserInputs))
655 C_Traits::inputUnion(map[key], k.second.m_UserInputs);
660 C_ShiftMap partitionedMap;
665 partitionedMap.insert(*map.begin());
670 for (
auto i = map.begin(), end = map.end(); i != end; ++i)
671 for (
auto j = i; ++j != end;)
674 T_Inputs insetsect(i->second);
675 C_Traits::inputIntersection(insetsect, j->second);
676 if (C_Traits::isEmptyInput(insetsect))
679 if (map.begin() != i)
682 partitionedMap.insert(map.begin(), i);
683 map.erase(map.begin(), i);
685 C_NfaClosure key(i->first);
686 key.insert(j->first.begin(), j->first.end());
688 T_Inputs t(i->second);
689 C_Traits::inputDifference(t, insetsect);
690 if (C_Traits::isEmptyInput(t))
696 C_Traits::inputDifference(t, insetsect);
697 if (C_Traits::isEmptyInput(t))
705 partitionedMap.insert(map.begin(), map.end());
707 map.swap(partitionedMap);
713 for (
const auto &j: map)
715 C_TaggedNfaClosure t(j.first);
716 createClosure(t.m_Closure, nfa.delta);
717 const C_TaggedNfaClosure *next;
718 for (
const auto &k: Q)
719 if (t.m_Closure == k.m_Closure)
727 deltaNfa[&q].emplace_back(j.second, next);
738 for (
const auto &j: nfa.F)
740 if (i.m_Closure.find(j) != i.m_Closure.end())
741 conflict.insert(j.m_Tag);
743 if (!conflict.empty())
745 if (conflict.size() > 1)
748 auto action = pickAction(i.m_Tag, conflict);
749 if (action == T_Action())
755 F[i.m_Tag] = *conflict.begin();
759 for (
const auto &i: deltaNfa)
761 auto &dstMap = delta[i.first->m_Tag];
762 for (
const auto &j: i.second)
763 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
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
std::set< T_Action > C_Conflict
void operator|=(const 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)
void operator=(const C_NFA &a)
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)