7 #include <unordered_map> 13 #include <forward_list> 40 string const& initialState,
47 for (
string const& a : acceptingStates) {
60 auto reIt = from.find(pLabel);
61 if (reIt == from.end() || !reIt->second) {
96 state =
string(1, prefix).append(std::to_string(0));
97 for (
size_t q(1);
transitions.count(state) != 0; q++) {
98 state =
string(1, prefix).append(std::to_string(q));
101 for (state =
string(1, prefix).append(1, suffix);
103 state.append(1, suffix)
125 auto& entry = transitions[qLabel];
127 acceptingStates.push_front(qLabel);
131 size_t pi = d.
delta(qi, si);
140 p = std::make_unique<pImpl>(transitions, d.
getLabelOf(0), acceptingStates,
new nfa(d));
158 auto& entry = transitions[qLabel];
160 acceptingStates.push_front(qLabel);
163 auto& pSet = n.
delta(qi, symbol);
164 for (
size_t pi(0); pi < pSet.size(); pi++) {
176 p = std::make_unique<pImpl>(transitions, n.
getLabelOf(0), acceptingStates,
new nfa(n));
186 p->transitions[p->initial][p->accepting] = r;
191 case expression::operation::alternation :
194 case expression::operation::concatenation :
197 case expression::operation::kleene :
200 case expression::operation::symbol :
203 case expression::operation::empty :
222 for (
auto const& entry : p->transitions) {
223 if (entry.first != p->initial && entry.first != p->accepting) {
224 active.push_back(std::cref(entry.first));
232 return p->getTransition(qLabel, pLabel);
241 splittable.reserve(p->transitions.size()*p->transitions.size());
244 if (to.second && to.second->getOperation() > expression::operation::symbol) {
245 splittable.push_back(std::make_pair(std::ref(from.first), std::ref(to.first)));
249 splittable.shrink_to_fit();
263 auto const& re = p->getTransition(qLabel, pLabel);
264 switch (re->getOperation()) {
265 case expression::operation::alternation : {
266 auto sub1 = *(re->begin());
267 auto sub2 = *(re->begin()+1);
269 newStates.reserve(4);
270 for (
size_t i(0); i < 4; i++) {
271 newStates.push_back(p->generateState());
274 p->transitions[qLabel][newStates[0]] = epsilon;
275 p->transitions[newStates[0]][newStates[1]] = sub1;
276 p->transitions[newStates[1]][pLabel] = epsilon;
277 p->transitions[qLabel][newStates[2]] = epsilon;
278 p->transitions[newStates[2]][newStates[3]] = sub2;
279 p->transitions[newStates[3]][pLabel] = epsilon;
282 case expression::operation::concatenation : {
283 auto sub1 = *(re->begin());
284 auto sub2 = *(re->begin()+1);
286 newStates.reserve(2);
287 for (
size_t i(0); i < 2; i++) {
288 newStates.push_back(p->generateState());
290 p->transitions[qLabel][newStates[0]] = sub1;
292 p->transitions[newStates[1]][pLabel] = sub2;
295 case expression::operation::kleene : {
296 auto sub = *(re->begin());
298 p->transitions[qLabel][pLabel] = epsilon;
299 newStates.reserve(2);
300 for (
size_t i(0); i < 2; i++) {
301 newStates.push_back(p->generateState());
303 p->transitions[qLabel][newStates[0]] = epsilon;
304 p->transitions[newStates[1]][pLabel] = epsilon;
305 p->transitions[newStates[1]][newStates[0]] = epsilon;
306 p->transitions[newStates[0]][newStates[1]] = sub;
309 case expression::operation::symbol :
310 case expression::operation::empty :
326 for (
auto const& nodes : splittable) {
332 for (
auto const& from : p->transitions) {
333 for (
auto const& to : from.second) {
334 if (to.second != empty) {
335 b.
addTransition(from.first, to.first, to.second->extractSymbol());
346 auto const& re = p->getTransition(qLabel, pLabel);
350 auto const& selfRe = p->getTransition(qLabel, qLabel);
351 for (
auto const& from : p->transitions) {
352 if (from.first != qLabel) {
353 auto to = from.second.find(qLabel);
354 if (to != from.second.end() && to->second) {
369 p->transitions[qLabel].erase(pLabel);
375 for (
auto const& to : p->transitions[qLabel]) {
376 right.push_front(to.first);
378 for (
auto const& to : right) {
379 if (to.get() != qLabel) {
383 for (
auto& from : p->transitions) {
384 from.second.erase(qLabel);
386 p->transitions.erase(qLabel);
407 #ifndef DOXYGEN_SHOULD_SKIP_THIS 408 gnfa::operator
nfa const&()
const {
409 if (!p->equivalent) {
412 return *p->equivalent;
414 #endif // DOXYGEN_SHOULD_SKIP_THIS 421 return other.operator==(*this);
435 p.reset(
new pImpl(*(n.p)));
450 gnfa::~gnfa() =
default;
pImpl()
Constructs private implementation object for a GNFA accepting the empty language ∅.
void addTransition(string const &qLabel, string const &pLabel, expression::exptr re, bool optimized=true, bool aggressive=false)
Safely adds a transition RE between two states.
void ripState(std::string const &qLabel)
Removes a state, bypassing all its outgoing transitions.
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this DFA.
std::vector< std::reference_wrapper< std::string const > > getActiveStates() const
Reveals the names of this GNFA's non-initial, non-accepting states.
nfa build()
Builds the NFA, as defined by previous operations.
expression::exptr getTransition(std::string const &qLabel, std::string const &pLabel) const
Extracts the RE labelling the transition between two states.
Represents nondeterministic finite automata with ε-moves.
unordered_map< string, unordered_map< string, expression::exptr > > transitions
Holds the transition table viz state × state → regular expression.
bool operator!=(nfa const &n) const
Checks whether this RE describes a different regular language than another object.
std::vector< char32_t > const & getAlphabet() const
Fetches this NFA's set of processable symbols.
std::string const & getLabelOf(size_t q) const
pImpl(unordered_map< string, unordered_map< string, expression::exptr >> &transitionMap, string const &initialState, forward_list< reference_wrapper< string const >> &acceptingStates, nfa const *eq)
Constructs private implementation object with provided members.
Represents deterministic finite automata.
std::vector< exptr >::const_iterator begin() const
Returns an iterator pointing to this RE's first subexpression.
static exptr const & spawnEmptyString()
Gives an RE representing the empty string ε.
Constructs NFAs step by step.
nfa splitAllTransitions()
Splits all transitions until only ∅, ε, and symbol REs remain and builds the resulting NFA...
expression::exptr ripAllStates()
Removes all active states, constructing an RE semantically equivalent to this GNFA.
std::string const & getAcceptingState() const
Reveals the name of this GNFA's accept state.
static exptr spawnAlternation(exptr const &l, exptr const &r, bool optimized=true, bool aggressive=false)
Gives an RE representing the alternation of two given REs.
Represents formal regular expressions.
char32_t extractSymbol() const
Reports this symbol expression's UTF-32-encoded symbol.
std::string const & getInitialState() const
Reveals the name of this GNFA's initial state.
size_t delta(size_t qi, size_t si) const
Computes this DFA's transition function for a state index and a symbol index.
std::vector< char32_t > const & getAlphabet() const
Fetches this DFA's set of processable symbols.
bool operator==(nfa const &n) const
Checks whether this RE describes the same regular language as another object.
std::vector< std::pair< std::reference_wrapper< std::string const >, std::reference_wrapper< std::string const > > > getSplittableTransitions() const
Reveals this GNFA's splittable transitions.
gnfa & operator=(gnfa const &n)
Copy-assigns this GNFA by copying another one's private implementation object.
static exptr const & spawnSymbol(char32_t symbol)
Gives an RE representing the given UTF-32-encoded symbol.
size_t getNumberOfSymbols() const
string initial
Holds the name of the initial state.
builder & setAccepting(std::string const &state, bool accept)
Sets whether or not a state will be accepting within the prospective NFA.
expression::exptr const & getTransition(string const &qLabel, string const &pLabel) const
Safely fetches a transition RE between two states.
Contains the reg::nfa class definition.
operation getOperation() const
Reports this RE's function.
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this NFA.
Represents generalized nondeterministic finite automata.
string const & generateState(char prefix='q', char suffix='\0')
Generates a unique new state name with given prefix (and suffix).
std::vector< std::string > const & getStates() const
Fetches this DFA's set of states.
size_t getNumberOfStates() const
builder & makeInitial(std::string const &state)
Resets the initial state for the prospective NFA.
std::vector< std::reference_wrapper< std::string const > > splitTransition(std::string const &qLabel, std::string const &pLabel)
Splits a transition between two states, adding new states if needed.
size_t getNumberOfStates() const
void bypassTransition(std::string const &qLabel, std::string const &pLabel)
Removes a transition between two states and replaces it with equivalent ones, bypassing its beginning...
Contains the reg::gnfa class definition.
Where this library lives.
std::shared_ptr< nfa const > equivalent
Points to a DFA accepting the same language as the owning GNFA.
builder & addTransition(std::string const &from, std::string const &to, char32_t symbol)
Adds a transition for the prospective NFA.
std::valarray< bool > const & delta(size_t qi, size_t si) const
Computes this NFA's transition function for a state index and a symbol index.
std::string const & getLabelOf(size_t qi) const
string accepting
Holds the name of the accept state.
gnfa(dfa const &d)
Constructs a GNFA with the same states and transitions as a given DFA.
static exptr const & spawnEmptySet()
Gives an RE representing the empty set ∅.
Contains the reg::dfa class definition.
static exptr spawnKleene(exptr const &b, bool optimized=true, bool aggressive=false)
Gives an RE representing the Kleene closure of a given RE.
static exptr spawnConcatenation(exptr const &l, exptr const &r, bool optimized=true, bool aggressive=false)
Gives an RE representing the concatenation of two given REs.
Private implementation details of GNFAs.