24 #include <unordered_map> 30 #include <forward_list> 61 string const& initialState,
69 for (
string const& a : acceptingStates) {
82 string const& pLabel)
const {
84 auto reIt = from.find(pLabel);
85 if (reIt == from.end() || !reIt->second) {
104 bool aggressive =
false) {
126 if (suffix ==
'\0') {
127 state =
string(!!prefix, prefix).append(std::to_string(0));
128 for (
size_t q(1);
transitions.count(state) != 0; q++) {
129 state =
string(!!prefix, prefix).append(std::to_string(q));
132 for (state =
string(!!prefix, prefix).append(1, suffix);
133 transitions.count(state) != 0; state.append(!!prefix, suffix)) {
160 for (
size_t qi(0); qi < d.
getStates().size(); qi++) {
162 auto& entry = transitions[qLabel];
164 acceptingStates.push_front(qLabel);
166 for (
size_t si(0); si < d.
getAlphabet_().size(); si++) {
168 size_t pi = d.
delta(qi, si);
179 acceptingStates,
new nfa(d));
200 for (
size_t qi(0); qi < n.
getStates().size(); qi++) {
202 auto& entry = transitions[qLabel];
204 acceptingStates.push_front(qLabel);
207 auto& pSet = n.
delta_(qi, symbol);
208 for (
size_t pi(0); pi < pSet.size(); pi++) {
222 acceptingStates,
new nfa(n));
232 pim->transitions[pim->initial][pim->accepting] = r;
237 case expression::operation::alternation:
238 pim->transitions[pim->initial][pim->accepting] =
241 case expression::operation::concatenation:
242 pim->transitions[pim->initial][pim->accepting] =
245 case expression::operation::kleene:
246 pim->transitions[pim->initial][pim->accepting] =
249 case expression::operation::symbol:
250 pim->transitions[pim->initial][pim->accepting] =
253 case expression::operation::empty:
254 pim->transitions[pim->initial][pim->accepting] =
269 for (
auto const& entry : pim->transitions) {
270 if (entry.first != pim->initial && entry.first != pim->accepting) {
271 active.push_back(std::cref(entry.first));
279 string const& pLabel)
const {
280 return pim->getTransition(qLabel, pLabel);
290 splittable.reserve(pim->transitions.size() * pim->transitions.size());
291 for (
auto const& from : pim->transitions) {
292 for (
auto const& to : from.second) {
294 to.second->getOperation() > expression::operation::symbol) {
295 splittable.emplace_back(std::ref(from.first), std::ref(to.first));
299 splittable.shrink_to_fit();
314 auto const& re = pim->getTransition(q, p);
315 switch (re->getOperation()) {
316 case expression::operation::alternation: {
317 auto sub1 = *(re->begin());
318 auto sub2 = *(re->begin() + 1);
320 newStates.reserve(4);
321 for (
size_t i(0); i < 4; i++) {
322 newStates.push_back(pim->generateState());
325 pim->transitions[q][newStates[0]] = epsilon;
326 pim->transitions[newStates[0]][newStates[1]] = sub1;
327 pim->transitions[newStates[1]][p] = epsilon;
328 pim->transitions[q][newStates[2]] = epsilon;
329 pim->transitions[newStates[2]][newStates[3]] = sub2;
330 pim->transitions[newStates[3]][p] = epsilon;
333 case expression::operation::concatenation: {
334 auto sub1 = *(re->begin());
335 auto sub2 = *(re->begin() + 1);
337 newStates.reserve(2);
338 for (
size_t i(0); i < 2; i++) {
339 newStates.push_back(pim->generateState());
341 pim->transitions[q][newStates[0]] = sub1;
342 pim->transitions[newStates[0]][newStates[1]] =
344 pim->transitions[newStates[1]][p] = sub2;
347 case expression::operation::kleene: {
348 auto sub = *(re->begin());
350 pim->transitions[q][p] = epsilon;
351 newStates.reserve(2);
352 for (
size_t i(0); i < 2; i++) {
353 newStates.push_back(pim->generateState());
355 pim->transitions[q][newStates[0]] = epsilon;
356 pim->transitions[newStates[1]][p] = epsilon;
357 pim->transitions[newStates[1]][newStates[0]] = epsilon;
358 pim->transitions[newStates[0]][newStates[1]] = sub;
361 case expression::operation::symbol:
362 case expression::operation::empty:;
381 for (
auto const& nodes : splittable) {
387 for (
auto const& from : pim->transitions) {
388 for (
auto const& to : from.second) {
389 if (to.second != empty) {
390 b.
addTransition_(from.first, to.first, to.second->extractSymbol_());
402 auto const& re = pim->getTransition(qLabel, pLabel);
406 auto const& selfRe = pim->getTransition(qLabel, qLabel);
407 for (
auto const& from : pim->transitions) {
408 if (from.first != qLabel) {
409 auto to = from.second.find(qLabel);
410 if (to != from.second.end() && to->second) {
419 pim->transitions[qLabel].erase(pLabel);
425 for (
auto const& to : pim->transitions[qLabel]) {
426 right.push_front(to.first);
428 for (
auto const& to : right) {
429 if (to.get() != qLabel) {
433 for (
auto& from : pim->transitions) {
434 from.second.erase(qLabel);
436 pim->transitions.erase(qLabel);
464 #ifndef DOXYGEN_SHOULD_SKIP_THIS 465 gnfa::operator
nfa const&()
const {
466 if (!pim->equivalent) {
470 return *pim->equivalent;
472 #endif // DOXYGEN_SHOULD_SKIP_THIS 481 return other.operator==(*this);
496 pim.reset(
new impl(*(n.pim)));
515 gnfa::~gnfa() =
default;
void ripState(std::string const &q)
Removes a state, bypassing all its outgoing transitions.
std::string const & getInitialState() const
Names this DFA's initial state.
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this DFA.
std::shared_ptr< nfa const > equivalent
Points to a DFA accepting the same language as the owning GNFA.
Represents nondeterministic finite automata with ε-moves.
bool operator!=(nfa const &n) const
Checks whether this RE describes a different regular language than another object.
expression::exptr getTransition(std::string const &q, std::string const &p) const
Extracts the RE labelling the transition between two states.
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 ε.
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.
std::vector< char32_t > const & getAlphabet_() const
Fetches this NFA's set of processable symbols.
Represents formal regular expressions.
std::string const & getInitialState() const
Reveals the name of this GNFA's initial state.
static exptr const & spawnSymbol_(char32_t u32symbol)
Gives an RE representing the given UTF-32-encoded symbol.
size_t delta(size_t qi, size_t si) const
Computes this DFA's transition function for a state index and a symbol index.
string accepting
Holds the name of the accept state.
bool operator==(nfa const &n) const
Checks whether this RE describes the same regular language as another object.
string initial
Holds the name of the initial state.
gnfa & operator=(gnfa const &n)
Copy-assigns this GNFA by copying another one's private implementation object.
impl()
Constructs private implementation object for a GNFA accepting the empty language ∅.
Contains the reg::nfa class definition.
operation getOperation() const
Reports this RE's function.
state_vector splitTransition(std::string const &q, std::string const &p)
Splits a transition between two states, adding new states if needed.
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this NFA.
Represents generalized nondeterministic finite automata.
expression::exptr const & getTransition(string const &qLabel, string const &pLabel) const
Safely fetches a transition RE between two states.
std::vector< std::string > const & getStates() const
Fetches this DFA's set of states.
std::valarray< bool > const & delta_(size_t qi, char32_t u32symbol) const
Computes this NFA's transition function for a state index and a UTF-32-encoded symbol.
fabuilder & setAccepting(std::string const &state, bool accept)
Sets whether or not a state will be accepting within the prospective FA.
Contains the reg::gnfa class definition.
Constructs NFAs step by step.
state_vector getActiveStates() const
Reveals the names of this GNFA's non-initial, non-accepting states.
Where this library lives.
fabuilder & makeInitial(std::string const &state)
Resets the initial state for the prospective FA.
std::string const & getInitialState() const
Names this NFA's initial state.
string const & generateState(char prefix='q', char suffix='\0')
Generates a unique new state name with given prefix (and suffix).
unordered_map< string, unordered_map< string, expression::exptr > > transitions
Holds the transition table viz state × state → regular expression.
char32_t extractSymbol_() const
Reports this symbol expression's UTF-32-encoded symbol.
Private implementation details of GNFAs.
std::vector< std::string > const & getStates() const
Fetches this NFA's set of states in order of internal representation.
gnfa(dfa const &d)
Constructs a GNFA with the same states and transitions as a given DFA.
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.
fabuilder & addTransition_(std::string const &from, std::string const &to, char32_t u32symbol=U'\0')
Adds a transition to the prospective FA's state transition function.
static exptr const & spawnEmptySet()
Gives an RE representing the empty set ∅.
nfa buildNfa()
Builds an NFA as defined by previous operations.
Contains the reg::dfa class definition.
state_pair_vector getSplittableTransitions() const
Reveals this GNFA's splittable transitions.
std::vector< char32_t > const & getAlphabet_() const
Fetches this DFA's set of processable symbols.
Contains the reg::fabuilder 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.
void bypassTransition(std::string const &q, std::string const &p)
Removes a transition between two states and replaces it with equivalent ones, bypassing its beginning...
impl(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.