tmp
This commit is contained in:
parent
afab59eb21
commit
69a17a609e
71 changed files with 199 additions and 282 deletions
249
.wip/Language/public/Automata.hpp
Normal file
249
.wip/Language/public/Automata.hpp
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Utils.hpp"
|
||||
#include "List.hpp"
|
||||
#include "Map.hpp"
|
||||
#include "Tree.hpp"
|
||||
|
||||
namespace tp {
|
||||
|
||||
// Non-Deterministic Finite-State Automata
|
||||
template <typename tAlphabetType, typename tStateType>
|
||||
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; }
|
||||
|
||||
const State* getState() const { return mState; }
|
||||
const tAlphabetType& getSymbol() const { return mSymbol; }
|
||||
|
||||
private:
|
||||
State* mState = nullptr;
|
||||
Type mType;
|
||||
tAlphabetType mSymbol;
|
||||
};
|
||||
|
||||
class State {
|
||||
friend FiniteStateAutomation;
|
||||
|
||||
public:
|
||||
State() = default;
|
||||
|
||||
public:
|
||||
void setValue(const tStateType& stateValue) { mStateVal = stateValue; }
|
||||
void setAcceptance(bool isAccepting) { mIsAccepting = isAccepting; }
|
||||
[[nodiscard]] bool isAccepting() const { return mIsAccepting; }
|
||||
const tStateType& getStateVal() const { return mStateVal; }
|
||||
[[nodiscard]] const Buffer<Transition>* getTransitions() const { return &mTransitions; }
|
||||
|
||||
private:
|
||||
Buffer<Transition> mTransitions{};
|
||||
tStateType mStateVal = tStateType();
|
||||
bool mIsAccepting = false;
|
||||
};
|
||||
|
||||
private:
|
||||
List<State> mStates;
|
||||
State* mStartState = nullptr;
|
||||
Range<ualni> mAlphabetRange = { ENV_UALNI_MAX, ENV_UALNI_MIN };
|
||||
|
||||
public:
|
||||
FiniteStateAutomation() = default;
|
||||
|
||||
State* addState(const tStateType& state, bool accepting) {
|
||||
auto node = mStates.newNode();
|
||||
node->data.mIsAccepting = accepting;
|
||||
node->data.mStateVal = state;
|
||||
mStates.pushBack(node);
|
||||
return &node->data;
|
||||
}
|
||||
|
||||
void addTransition(State* from, State* to, const tAlphabetType& symbol) {
|
||||
from->mTransitions.append(Transition(Transition::SYMBOL, to, symbol));
|
||||
if (mAlphabetRange.mBegin < ualni(symbol)) mAlphabetRange.mBegin = ualni(symbol);
|
||||
if (mAlphabetRange.mEnd > ualni(symbol)) mAlphabetRange.mEnd = ualni(symbol);
|
||||
}
|
||||
|
||||
void addEpsilonTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::SYMBOL, to)); }
|
||||
|
||||
void addAnyTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::ANY, to)); }
|
||||
|
||||
void setStartState(State* start) { mStartState = start; }
|
||||
|
||||
[[nodiscard]] State* getStartState() const { return mStartState; }
|
||||
|
||||
[[nodiscard]] bool isValid() const {
|
||||
if (!mStartState) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] ualni numStates() const { return mStates.length(); }
|
||||
|
||||
[[nodiscard]] const List<State>* getStates() const { return &mStates; }
|
||||
|
||||
[[nodiscard]] Range<ualni> getAlphabetRange() const { return mAlphabetRange; }
|
||||
|
||||
private:
|
||||
typedef AvlTree<AvlNumericKey<State*>, bool> StatesSet;
|
||||
|
||||
// Expands initial set with states that are reachable from initial set with no input consumption (E-transitions)
|
||||
static void expandSet(StatesSet& set) {
|
||||
List<State*> workingSet;
|
||||
|
||||
set.forEach([&](AvlNumericKey<State*>& key, bool) { workingSet.pushBack(key.val); });
|
||||
|
||||
while (workingSet.length()) {
|
||||
auto first = workingSet.first()->data;
|
||||
set.insert(first, {});
|
||||
|
||||
for (auto transition : first->mTransitions) {
|
||||
if (!transition->isEpsilon()) continue;
|
||||
if (set.find(transition->mState)) continue;
|
||||
workingSet.pushBack(transition->mState);
|
||||
}
|
||||
|
||||
workingSet.popFront();
|
||||
}
|
||||
}
|
||||
|
||||
// States that are reachable from initial set with symbol transition
|
||||
static void findMoveSet(StatesSet& from, StatesSet& moveSet, tAlphabetType symbol) {
|
||||
from.forEach([&](AvlNumericKey<State*>& key, bool) {
|
||||
for (auto transition : key.val->mTransitions) {
|
||||
if (transition->isEpsilon()) continue;
|
||||
if (!transition->isTransition(symbol)) continue;
|
||||
if (moveSet.find(transition->mState)) continue;
|
||||
moveSet.insert(transition->mState, {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
bool makeDeterministic() {
|
||||
if (!isValid()) return false;
|
||||
|
||||
struct GroupKey {
|
||||
const StatesSet* group;
|
||||
static ualni hash(GroupKey key) { return 0; }
|
||||
bool operator==(const GroupKey& key) const { return false; }
|
||||
};
|
||||
|
||||
struct GroupInfo {
|
||||
StatesSet* group = nullptr;
|
||||
AvlTree<AvlNumericKey<StatesSet*>, tAlphabetType> transitions;
|
||||
State* newState = nullptr;
|
||||
bool accepting = false;
|
||||
tStateType stateVal = tStateType();
|
||||
};
|
||||
|
||||
Buffer<StatesSet> groups = { {} };
|
||||
Map<GroupKey, GroupInfo, DefaultAllocator, GroupKey::hash> groupInfos;
|
||||
|
||||
groups.first().insert(getStartState(), false);
|
||||
|
||||
expandSet(groups.first());
|
||||
|
||||
groupInfos.put({ &groups.first() }, { &groups.first() });
|
||||
|
||||
// 1) find new states
|
||||
List<StatesSet*> workingSet;
|
||||
workingSet.pushBack(&groups.first());
|
||||
|
||||
while (workingSet.length()) {
|
||||
StatesSet* group = workingSet.first()->data;
|
||||
GroupInfo* info = &groupInfos.get({ group });
|
||||
|
||||
for (auto symbol : getAlphabetRange()) {
|
||||
|
||||
// calculate new possible state
|
||||
StatesSet potentialGroup;
|
||||
|
||||
findMoveSet(*group, potentialGroup, tAlphabetType(symbol));
|
||||
expandSet(potentialGroup);
|
||||
|
||||
if (!potentialGroup.size()) continue;
|
||||
|
||||
// find existing or create group
|
||||
StatesSet* targetGroup = nullptr;
|
||||
auto iter = groupInfos.presents({ &potentialGroup });
|
||||
if (iter) {
|
||||
targetGroup = groupInfos.getSlotVal(iter).group;
|
||||
} else {
|
||||
targetGroup = &groups.append(potentialGroup);
|
||||
groupInfos.put({ targetGroup }, { targetGroup });
|
||||
workingSet.pushBack(targetGroup);
|
||||
}
|
||||
|
||||
// assert transition is added
|
||||
info->transitions.insert(targetGroup, tAlphabetType(symbol));
|
||||
}
|
||||
|
||||
workingSet.popFront();
|
||||
}
|
||||
|
||||
// 2) find new states termination values
|
||||
for (auto group : groupInfos) {
|
||||
GroupInfo* info = &group->val;
|
||||
ualni accepting = 0;
|
||||
|
||||
info->group->forEach([&](AvlNumericKey<State*>& key, bool) {
|
||||
if (key.val->mIsAccepting) {
|
||||
accepting++;
|
||||
info->accepting = true;
|
||||
info->stateVal = key.val->mStateVal;
|
||||
}
|
||||
});
|
||||
|
||||
if (!accepting) {
|
||||
info->accepting = false;
|
||||
info->stateVal = info->group->head()->key.val->mStateVal;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) transfer
|
||||
mStates.removeAll();
|
||||
|
||||
// create states
|
||||
for (auto group : groupInfos) {
|
||||
group->val.newState = addState(group->val.stateVal, group->val.accepting);
|
||||
}
|
||||
|
||||
// create transitions
|
||||
for (auto group : groupInfos) {
|
||||
auto functor = [&](AvlNumericKey<StatesSet*> targetGroupKey, tAlphabetType symbol) {
|
||||
GroupInfo* targetGroup = &groupInfos.get({ (StatesSet*) targetGroupKey.val });
|
||||
addTransition(group->val.newState, targetGroup->newState, symbol);
|
||||
};
|
||||
group->val.transitions.forEach(functor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue