#pragma once #include "Utils.hpp" #include "List.hpp" #include "Map.hpp" #include "Tree.hpp" namespace tp { // Non-Deterministic Finite-State Automata template class FiniteStateAutomation { public: struct State; public: class Transition { friend FiniteStateAutomation; public: enum Type { ANY, EPSILON, SYMBOL }; public: Transition(Type type, State* state, tAlphabetType symbol = tAlphabetType()) { mState = state; mType = type; mSymbol = symbol; } [[nodiscard]] bool isTransition(const tAlphabetType& symbol) const { return (mType == ANY || mType == EPSILON) || (mSymbol == symbol); } [[nodiscard]] bool doesConsumes(const tAlphabetType& symbol) const { return (mType == ANY || (mType == SYMBOL && mSymbol == symbol)); } [[nodiscard]] bool isEpsilon() const { return mType == EPSILON; } private: State* mState = nullptr; Type mType; tAlphabetType mSymbol; }; class State { friend FiniteStateAutomation; State() = default; public: void setValue(const tStateType& stateValue) { mStateVal = stateValue; } void setAcceptance(bool isAccepting) { mIsAccepting = isAccepting; } private: Buffer mTransitions; tStateType mStateVal = tStateType(); bool mIsAccepting = false; }; private: List mStates; const State* mStartState = nullptr; public: FiniteStateAutomation() = default; State* addState(const tStateType& state, bool accepting) { auto node = mStates.newNode(); node->data.mIsAccepting = accepting; node->data.mState = state; mStates.pushBack(node); return &node->data; } void addTransition(State* from, State* to, const tAlphabetType& symbol) { from->edges.pushBack(Transition(Transition::SYMBOL, to, symbol)); } void addEpsilonTransition(State* from, State* to) { from->edges.pushBack(Transition(Transition::SYMBOL, to)); } void addAnyTransition(State* from, State* to) { from->edges.pushBack(Transition(Transition::ANY, to)); } void setStartVertex(State* start) { mStartState = start; } [[nodiscard]] State* getStartState() const { return mStartState; } [[nodiscard]] bool isValid() const { if (!mStartState) { return false; } return true; } // vertices that are reachable from initial set with no input consumption (E-transitions) // does not include initial set void findClosureSet(const Buffer& from, Buffer& closureSet) const { Map lookup; List workingSet; for (auto item : from) { workingSet.pushBack(item.data()); } while (workingSet.length()) { auto first = workingSet.first()->data; closureSet.append(first); for (auto edge : first->mTransitions) { if (!edge.data().isEpsilon()) continue; if (lookup.presents(edge.data().mState)) continue; workingSet.pushBack(edge.data().mState); } workingSet.popFront(); } } // vertices that are reachable from initial set with symbol transition void findMoveSet(const Buffer& from, Buffer& moveSet, tAlphabetType symbol) const { Map lookup; for (auto vertex : from) { for (auto edge : vertex.mTransitions) { if (edge.data().isepsilon()) continue; if (!edge.data().isTransition(symbol)) continue; if (lookup.presents(edge.data().mState)) continue; moveSet.append(edge.data().mState); lookup.put(edge.data().mState, {}); } } } template bool makeDeterministic(const tAlphabetIterator& allSymbols) { if (!isValid()) { return false; } struct Group { Buffer states; AvlTree transitions; State* newState = nullptr; bool accepting = false; tStateType stateVal = tStateType(); }; struct GroupKey { const Group* group; }; Buffer newStates = { {} }; // 1) find new states Map lookup; List workingSet; findClosureSet({ getStartState() }, newStates.first().states); workingSet.pushBack(&newStates.first()); while (workingSet.length()) { auto group = workingSet.first(); for (auto symbol : allSymbols) { // calculate new possible state Group potentialGroup; findMoveSet(group.states, potentialGroup.states, symbol); if (!potentialGroup.states.size()) continue; // find existing or create group Group* targetGroup = nullptr; auto iter = lookup.presents({ &potentialGroup }); if (iter) { targetGroup = lookup.getSlotVal(iter); } else { targetGroup = newStates.append({}); lookup.put({ targetGroup }, {}); } // add transition group.transitions.insert(targetGroup, symbol); } workingSet.popFront(); } // 2) find new states termination values // ... // 3) transfer mStates.removeAll(); for (auto group : newStates) { group.newState = addState(); } for (auto group : newStates) { for (auto transition : group.transitions) { addTransition(/* ... */); } } } }; }