reglibcpp  1.3.0
(Naïve) C++ implementation of models for regular languages
Classes | Public Member Functions | List of all members
reg::nfa::builder Class Reference

Constructs NFAs step by step. More...

#include <nfa.h>

Classes

struct  pImpl
 Private implementation details of NFA builders. More...
 

Public Member Functions

 builder ()
 Constructs a blank builder object. More...
 
 builder (nfa const &nfa)
 Constructs a builder object with exactly the same states, symbols, transitions, initial state and accept states as a given NFA. More...
 
 builder (dfa const &dfa)
 Constructs a builder object with exactly the same states, symbols, transitions, initial state and accept states as a given DFA. More...
 
 builder (builder const &b)
 Copy-constructs a builder by copying another one's private implementation object. More...
 
 builder (builder &&b)
 Move-constructs a builder by stealing another one's private implementation object. More...
 
builderoperator= (builder const &b)
 Copy-assigns a builder by copying another one's private implementation object. More...
 
builderoperator= (builder &&b)
 Move-assigns a builder by stealing another one's private implementation object. More...
 
builderaddSymbol (char32_t symbol)
 Adds a symbol to the prospective NFA's alphabet. More...
 
builderaddSymbol (std::string const &utf8Symbol)
 Same as above for a UTF-8-encoded symbol. More...
 
buildersetAccepting (std::string const &state, bool accept)
 Sets whether or not a state will be accepting within the prospective NFA. More...
 
buildermakeInitial (std::string const &state)
 Resets the initial state for the prospective NFA. More...
 
builderaddTransition (std::string const &from, std::string const &to, char32_t symbol)
 Adds a transition for the prospective NFA. More...
 
builderaddTransition (std::string const &from, std::string const &to, std::string const &utf8Symbol)
 Same as above for a UTF-8-encoded symbol. More...
 
builderunite (nfa const &other)
 Makes the prospective NFA also accept every word of another NFA's language. More...
 
builderintersect (nfa const &other)
 Makes the prospective NFA accept only words accepted also by another NFA. More...
 
buildernormalizeStateNames (std::string const &prefix)
 Reduces the prospective NFA's state names to consecutive numbers, prefixed with a given string. More...
 
nfa build ()
 Builds the NFA, as defined by previous operations. More...
 

Detailed Description

Constructs NFAs step by step.

Any mention of a symbol or state will add them to the alphabet/set of states. The first state mentioned will be designated initial state.

Definition at line 62 of file nfa.h.

Constructor & Destructor Documentation

◆ builder() [1/5]

reg::nfa::builder::builder ( )

Constructs a blank builder object.

Definition at line 455 of file nfa.cpp.

455 : p(new pImpl) {}

◆ builder() [2/5]

reg::nfa::builder::builder ( nfa const &  nfa)

Constructs a builder object with exactly the same states, symbols, transitions, initial state and accept states as a given NFA.

Definition at line 458 of file nfa.cpp.

458  : p(new pImpl) {
459  makeInitial(nfa.getLabelOf(0));
460  for (char32_t symbol : nfa.getAlphabet()) {
461  addSymbol(symbol);
462  }
463  for (size_t qi = 0; qi < nfa.p->labels.size(); ++qi) {
464  string const& qLabel = nfa.getLabelOf(qi);
465  for (char32_t symbol : p->alphabet) {
466  valarray<bool> ps = nfa.delta(qi, symbol);
467  size_t pi(0);
468  for (bool pb : ps) {
469  if (pb) {
470  addTransition(qLabel, nfa.getLabelOf(pi), symbol);
471  }
472  pi++;
473  }
474  }
475  if (nfa.isAccepting(qi)) {
476  setAccepting(qLabel, true);
477  }
478  }
479 }
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective NFA's alphabet.
Definition: nfa.cpp:529
builder & setAccepting(std::string const &state, bool accept)
Sets whether or not a state will be accepting within the prospective NFA.
Definition: nfa.cpp:545
builder & makeInitial(std::string const &state)
Resets the initial state for the prospective NFA.
Definition: nfa.cpp:563
nfa()
Constructs an NFA accepting the empty language ∅.
Definition: nfa.cpp:79
builder & addTransition(std::string const &from, std::string const &to, char32_t symbol)
Adds a transition for the prospective NFA.
Definition: nfa.cpp:576

◆ builder() [3/5]

reg::nfa::builder::builder ( dfa const &  dfa)

Constructs a builder object with exactly the same states, symbols, transitions, initial state and accept states as a given DFA.

Transition destinations will be converted to singleton sets of the respective reached states.

Definition at line 483 of file nfa.cpp.

483  {
484  string initial(dfa.getLabelOf(0));
485  unordered_set<string> acceptingStates;
486  unordered_set<char32_t> alphabet(dfa.getAlphabet().begin(), dfa.getAlphabet().end());
487  Ntransitionmap transitions;
488  for (size_t q(0); q < dfa.getNumberOfStates(); q++) {
489  for (char32_t symbol : alphabet) {
490  transitions[dfa.getLabelOf(q)][symbol].insert(dfa.getLabelOf(dfa.delta(q, symbol)));
491  }
492  if (dfa.isAccepting(q)) {
493  acceptingStates.insert(dfa.getLabelOf(q));
494  }
495  }
496  p = make_unique<pImpl>(initial, acceptingStates, alphabet, transitions);
497 }

◆ builder() [4/5]

reg::nfa::builder::builder ( builder const &  b)

Copy-constructs a builder by copying another one's private implementation object.

Definition at line 500 of file nfa.cpp.

500 : p(new pImpl(*(b.p))) {}

◆ builder() [5/5]

reg::nfa::builder::builder ( builder &&  b)

Move-constructs a builder by stealing another one's private implementation object.

The other builder will be blank afterwards.

Definition at line 504 of file nfa.cpp.

504 : p(new pImpl) {p.swap(b.p);}

Member Function Documentation

◆ addSymbol() [1/2]

nfa::builder & reg::nfa::builder::addSymbol ( char32_t  symbol)

Adds a symbol to the prospective NFA's alphabet.

Parameters
symbolthe symbol to add
Returns
reference to this object, for chaining operations

Definition at line 529 of file nfa.cpp.

529  {
530  p->alphabet.insert(symbol);
531  return *this;
532 }

◆ addSymbol() [2/2]

nfa::builder & reg::nfa::builder::addSymbol ( std::string const &  utf8Symbol)

Same as above for a UTF-8-encoded symbol.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Definition at line 535 of file nfa.cpp.

535  {
536  return addSymbol(converter.from_bytes(utf8Symbol)[0]);
537 }
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective NFA's alphabet.
Definition: nfa.cpp:529
std::wstring_convert< std::codecvt_utf8< char32_t >, char32_t > converter
Converts between UTF-8-encoded and UTF-32-encoded strings.
Definition: dfa.cpp:1001

◆ addTransition() [1/2]

nfa::builder & reg::nfa::builder::addTransition ( std::string const &  from,
std::string const &  to,
char32_t  symbol 
)

Adds a transition for the prospective NFA.

Parameters
fromthe starting state for the transition
tothe destination state for the transition
symbolthe symbol triggering the transition or \0 for an ε-transition
Returns
reference to this object, for chaining operations

Definition at line 576 of file nfa.cpp.

576  {
577  if (p->transitions.empty()) {
578  p->initial = from;
579  }
580  p->transitions[to];
581  p->transitions[from][symbol].insert(to);
582  addSymbol(symbol);
583  return *this;
584 }
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective NFA's alphabet.
Definition: nfa.cpp:529

◆ addTransition() [2/2]

nfa::builder & reg::nfa::builder::addTransition ( std::string const &  from,
std::string const &  to,
std::string const &  utf8Symbol 
)

Same as above for a UTF-8-encoded symbol.

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

Definition at line 587 of file nfa.cpp.

587  {
588  return addTransition(from, to, converter.from_bytes(utf8Symbol)[0]);
589 }
builder & addTransition(std::string const &from, std::string const &to, char32_t symbol)
Adds a transition for the prospective NFA.
Definition: nfa.cpp:576
std::wstring_convert< std::codecvt_utf8< char32_t >, char32_t > converter
Converts between UTF-8-encoded and UTF-32-encoded strings.
Definition: dfa.cpp:1001

◆ build()

nfa reg::nfa::builder::build ( )

Builds the NFA, as defined by previous operations.

Returns
an NFA object with exactly the states, alphabet and transitions that were defined

Definition at line 771 of file nfa.cpp.

771  {
772  p->alphabet.insert(U'\0');
773  vector<char32_t> alphabetV(p->alphabet.begin(), p->alphabet.end());
774  std::sort(alphabetV.begin(), alphabetV.end());
775  vector<string> labelV(p->transitions.size());
776  labelV[0] = p->initial;
777  valarray<bool> acceptingV(p->transitions.size());
778  acceptingV[0] = (p->acceptingStates.find(p->initial) != p->acceptingStates.end());
779  size_t i(1);
780  for (auto entry : p->transitions) {
781  if (entry.first == p->initial) {
782  continue;
783  }
784  labelV[i] = entry.first;
785  acceptingV[i++] = (
786  p->acceptingStates.find(entry.first) != p->acceptingStates.end()
787  );
788  }
789  vector<vector<valarray<bool>>> transitionV(
790  p->transitions.size(),
791  vector<valarray<bool>>(
792  p->alphabet.size()+1,
793  valarray<bool>(labelV.size())
794  )
795  );
796  unordered_set<string> emptySet;
797  size_t qi(0);
798  for (auto const& q : labelV) {
799  unordered_map<char32_t,unordered_set<string>> const& fromQ = p->transitions[q];
800  size_t si(0);
801  for (char32_t symbol : alphabetV) {
802  auto to = fromQ.find(symbol);
803  unordered_set<string> const& viaSymbol(to != fromQ.end() ? to->second : emptySet);
804  i = 0;
805  for (auto const& p : labelV) {
806  transitionV[qi][si][i++] = (viaSymbol.count(p) != 0);
807  }
808  si++;
809  }
810  qi++;
811  }
812  return {alphabetV, transitionV, labelV, acceptingV};
813 }

◆ intersect()

nfa::builder & reg::nfa::builder::intersect ( nfa const &  other)

Makes the prospective NFA accept only words accepted also by another NFA.

Concatenates the names of states defined so far with the other NFA's state names and resolves conflicts by appending _.

Parameters
otherthe NFA whose language should also be accepted
Returns
reference to this object, for chaining operations

Definition at line 694 of file nfa.cpp.

694  {
695  if (!p->transitions.empty()) {
696  vector<string> stateNames;
697  stateNames.reserve(p->transitions.size());
698  stateNames.push_back(p->initial);
699  for (auto const& fromTo : p->transitions) {
700  if (fromTo.first != p->initial) {
701  stateNames.push_back(fromTo.first);
702  }
703  }
704  auto const& oAlph = other.getAlphabet();
705  size_t commonSymbols = 0;
706  for (char32_t symbol : p->alphabet) {
707  if (index_of(oAlph, symbol) < oAlph.size()) {
708  commonSymbols++;
709  } else {
710  for (auto & fromVia : p->transitions) {
711  fromVia.second.erase(symbol);
712  }
713  }
714  }
715  p->alphabet.insert(oAlph.begin(), oAlph.end());
716  Ntransitionmap newTr(stateNames.size() * other.getNumberOfStates());
717  unordered_set<string> newAcc(stateNames.size() * other.getNumberOfStates());
718  unordered_map<size_t, unordered_map<size_t, string const*>> pairToName(stateNames.size() * other.getNumberOfStates());
719  for (size_t q = 0; q < stateNames.size(); q++) {
720  for (size_t qq = 0; qq < other.getNumberOfStates(); qq++) {
721  string potentialName = stateNames[q] + other.getLabelOf(qq);
722  for (auto nameIt = newTr.find(potentialName); nameIt != newTr.end(); nameIt = newTr.find(potentialName)) {
723  potentialName.append("_");
724  }
725  auto nameIt = newTr.emplace(potentialName, commonSymbols);
726  pairToName.emplace(q, 1).first->second.emplace(qq, &(nameIt.first->first));
727  if (p->acceptingStates.find(stateNames[q]) != p->acceptingStates.end() && other.isAccepting(qq)) {
728  newAcc.insert(potentialName);
729  }
730  }
731  p->transitions[stateNames[q]][U'\0'].insert(stateNames[q]);
732  // Needed due to the equivalence of standing still to “taking” an ε-transition.
733  }
734  for (size_t q = 0; q < stateNames.size(); q++) {
735  auto const& qLabel = stateNames[q];
736  auto const& viaTos = p->transitions[qLabel];
737  for (auto const& viaTo : viaTos) {
738  for (size_t qq = 0; qq < other.getNumberOfStates(); qq++) {
739  valarray<bool> const& reached = other.delta(qq, viaTo.first);
740  for (auto const& to : viaTo.second) {
741  size_t p = index_of(stateNames, to);
742  for (size_t pp = 0; pp < reached.size(); pp++) {
743  if (reached[pp] || (pp == qq && viaTo.first == U'\0')) {
744  // Needed due to the equivalence of standing still to “taking” an ε-transition.
745  newTr[*(pairToName[q][qq])][viaTo.first].insert(*(pairToName[p][pp]));
746  }
747  }
748  }
749  }
750  }
751  }
752  for (auto & fromVia : newTr) {
753  auto const& from = fromVia.first;
754  auto to = fromVia.second.find(U'\0');
755  to->second.erase(from);
756  if (to->second.empty()) {
757  fromVia.second.erase(to);
758  }
759  }
760  p->transitions = newTr;
761  p->acceptingStates = newAcc;
762  p->initial = *(pairToName[0][0]);
763  }
764  return *this;
765 }
size_t index_of(vector< T > const &vec, T const &element)
Basically Java&#39;s List interface&#39;s indexOf, but as a non-member function and returning the container&#39;s...
Definition: dfa.cpp:995

◆ makeInitial()

nfa::builder & reg::nfa::builder::makeInitial ( std::string const &  state)

Resets the initial state for the prospective NFA.

Parameters
statethe new initial state
Returns
reference to this object, for chaining operations

Definition at line 563 of file nfa.cpp.

563  {
564  p->initial = state;
565  p->transitions[state];
566  return *this;
567 }

◆ normalizeStateNames()

nfa::builder & reg::nfa::builder::normalizeStateNames ( std::string const &  prefix)

Reduces the prospective NFA's state names to consecutive numbers, prefixed with a given string.

Definition at line 592 of file nfa.cpp.

592  {
593  if (!p->transitions.empty()) {
594  vector<string> stateNames;
595  stateNames.reserve(p->transitions.size());
596  stateNames.push_back(p->initial);
597  for (auto const& fromTo : p->transitions) {
598  if (fromTo.first != p->initial) {
599  stateNames.push_back(fromTo.first);
600  }
601  }
602  Ntransitionmap newTr(p->transitions.size());
603  unordered_set<string> newAcc(p->acceptingStates.size());
604  for (size_t q = 0; q < stateNames.size(); q++) {
605  auto const& vias = p->transitions[stateNames[q]];
606  unordered_map<char32_t,unordered_set<string>> newVias(vias.size());
607  for (auto const& viaTo : vias) {
608  unordered_set<string> newTos(viaTo.second.size());
609  for (size_t p = 0; p < stateNames.size(); p++) {
610  if (viaTo.second.find(stateNames[p]) != viaTo.second.cend()) {
611  newTos.insert(string(prefix).append(std::to_string(p)));
612  }
613  }
614  newVias.insert(make_pair(viaTo.first, newTos));
615  }
616  newTr.insert(make_pair(string(prefix).append(std::to_string(q)), newVias));
617  if (p->acceptingStates.find(stateNames[q]) != p->acceptingStates.end()) {
618  newAcc.insert(string(prefix).append(std::to_string(q)));
619  }
620  }
621  p->initial = string(string(prefix).append("0"));
622  p->transitions = newTr;
623  p->acceptingStates = newAcc;
624  }
625  return *this;
626 }

◆ operator=() [1/2]

nfa::builder & reg::nfa::builder::operator= ( builder const &  b)

Copy-assigns a builder by copying another one's private implementation object.

Definition at line 507 of file nfa.cpp.

507  {
508  if (this != &b) {
509  p.reset(new pImpl(*(b.p)));
510  }
511  return *this;
512 }

◆ operator=() [2/2]

nfa::builder & reg::nfa::builder::operator= ( nfa::builder &&  b)

Move-assigns a builder by stealing another one's private implementation object.

The other builder will be blank afterwards.

Definition at line 516 of file nfa.cpp.

516  {
517  if (this != &b) {
518  p.reset(new pImpl);
519  p.swap(b.p);
520  }
521  return *this;
522 }

◆ setAccepting()

nfa::builder & reg::nfa::builder::setAccepting ( std::string const &  state,
bool  accept 
)

Sets whether or not a state will be accepting within the prospective NFA.

Parameters
statethe state's name
accepttrue if the state should be an accept state afterwards, false else
Returns
reference to this object, for chaining operations

Definition at line 545 of file nfa.cpp.

545  {
546  if (p->transitions.empty()) {
547  p->initial = state;
548  }
549  p->transitions[state];
550  if (accept) {
551  p->acceptingStates.insert(state);
552  } else {
553  p->acceptingStates.erase(state);
554  }
555  return *this;
556 }

◆ unite()

nfa::builder & reg::nfa::builder::unite ( nfa const &  other)

Makes the prospective NFA also accept every word of another NFA's language.

Prepends the names of states defined so far with a single 1 and the other NFA's state names with a single 2 and adds a new initial state with an ε transition to each of the other initial states.

Parameters
otherthe NFA whose language should also be accepted
Returns
reference to this object, for chaining operations

Definition at line 636 of file nfa.cpp.

636  {
637  string newInitial("q0");
638  if (!p->transitions.empty()) {
639  Ntransitionmap tempTr(p->transitions.size());
640  for (auto const& fromVia : p->transitions) {
641  unordered_map<char32_t,unordered_set<string>> tempVia(fromVia.second.size());
642  for (auto const& viaTo : fromVia.second) {
643  unordered_set<string> tempTo(viaTo.second.size());
644  for (auto const& to : viaTo.second) {
645  tempTo.insert(string(to.length() + 1, '1').replace(1, string::npos, to));
646  }
647  tempVia.insert(make_pair(viaTo.first, tempTo));
648  }
649  tempTr.insert(make_pair(string(fromVia.first.length() + 1, '1').replace(1, string::npos, fromVia.first), tempVia));
650  }
651  p->transitions = tempTr;
652  unordered_set<string> tempAcc(p->acceptingStates.size());
653  for (auto const& acc : p->acceptingStates) {
654  tempAcc.insert(string(acc.length() + 1, '1').replace(1, string::npos, acc));
655  }
656  p->acceptingStates = tempAcc;
657  p->initial = string(p->initial.length() + 1, '1').replace(1, string::npos, p->initial);
658  addTransition(newInitial, p->initial, U'\0');
659  }
660  makeInitial(newInitial);
661  auto & oAlphabet = other.getAlphabet();
662  p->alphabet.insert(oAlphabet.cbegin(), oAlphabet.cend());
663  for (size_t q = 0; q < other.getNumberOfStates(); q++) {
664  auto & qLabel = other.getLabelOf(q);
665  string newQLabel = string(qLabel.length() + 1, '2').replace(1, string::npos, qLabel);
666  unordered_map<char32_t,unordered_set<string>> tempVia(oAlphabet.size() + 1);
667  for (char32_t symbol : oAlphabet) {
668  valarray<bool> const& to = other.delta(q, symbol);
669  unordered_set<string> tempTo(other.getNumberOfStates());
670  for (size_t p = 0; p < other.getNumberOfStates(); p++) { if (to[p]) {
671  auto & pLabel = other.getLabelOf(p);
672  tempTo.insert(string(pLabel.length() + 1, '2').replace(1, string::npos, pLabel));
673  }}
674  tempVia.insert(make_pair(symbol, tempTo));
675  }
676  p->transitions.insert(make_pair(newQLabel, tempVia));
677  if (other.isAccepting(q)) {
678  p->acceptingStates.insert(newQLabel);
679  }
680  if (q == 0) {
681  addTransition(newInitial, newQLabel, U'\0');
682  }
683  }
684  return *this;
685 }
builder & makeInitial(std::string const &state)
Resets the initial state for the prospective NFA.
Definition: nfa.cpp:563
builder & addTransition(std::string const &from, std::string const &to, char32_t symbol)
Adds a transition for the prospective NFA.
Definition: nfa.cpp:576

The documentation for this class was generated from the following files: