reglibcpp  1.3.0
(Naïve) C++ implementation of models for regular languages
nfa.cpp
Go to the documentation of this file.
1 #include "nfa.h"
3 using std::valarray;
4 using std::vector;
5 using std::string;
6 using std::make_unique;
7 using std::make_pair;
8 using std::u32string;
9 
10 using std::move;
11 
12 #include <unordered_set>
13 using std::unordered_set;
14 
15 #include <unordered_map>
16 using std::unordered_map;
17 
18 #include <algorithm>
19 using std::find;
20 
21 #include <iterator>
22 
23 #include "dfa.h"
24 #include "expression.h"
25 
26 namespace reg {
27 
29 struct nfa::pImpl {
30  std::shared_ptr<dfa const> equivalent;
31  valarray<bool> accepting;
32  vector<char32_t> alphabet;
33  vector<string> utf8Alphabet;
34  vector<valarray<bool>> mutable epsClosures;
35  vector<string> labels;
36  vector<vector<valarray<bool>>> transitions;
37 
39  pImpl() :
40  equivalent(),
41  accepting(),
42  alphabet(1, U'\0'),
43  utf8Alphabet(1, ""),
44  epsClosures(),
45  labels(),
46  transitions() {}
47 
49  pImpl(vector<char32_t>& alphabet, vector<vector<valarray<bool>>>& transitions,
50  vector<string>& labels, valarray<bool>& acceptingStates) :
51  accepting(move(acceptingStates)),
52  alphabet(move(alphabet)),
53  labels(move(labels)),
54  transitions(move(transitions)) {
55  utf8Alphabet.reserve(this->alphabet.size());
56  for (char32_t symbol : this->alphabet) {
57  if (symbol == U'\0') {
58  utf8Alphabet.push_back("");
59  } else {
60  utf8Alphabet.push_back(converter.to_bytes(symbol));
61  }
62  }
63  epsClosures = vector<valarray<bool>>(pImpl::labels.size());
64  }
65 
67 
70  dfa const& getEquivalentDfa(nfa const* owner) {
71  if (!equivalent) {
72  equivalent.reset(new dfa(dfa::builder(*owner).minimize()));
73  }
74  return *equivalent;
75  }
76 };
77 
79 nfa::nfa() : p(new pImpl) {}
80 
82 nfa::nfa(vector<char32_t>& alphabet, vector<vector<valarray<bool>>>& transitions,
83  vector<string>& labels, valarray<bool>& acceptingStates) :
84  p(new pImpl(alphabet, transitions, labels, acceptingStates)) {}
85 
87 bool nfa::operator==(nfa const& n) const {
88  return p->getEquivalentDfa(this) == n.p->getEquivalentDfa(&n);
89 }
90 
92 bool nfa::operator!=(nfa const& n) const {
93  return p->getEquivalentDfa(this) != n.p->getEquivalentDfa(&n);
94 }
95 
97 
102 valarray<bool> const& nfa::delta(size_t q, char32_t symbol) const {
103  size_t i = index_of(p->alphabet, symbol);
104  if (i >= p->alphabet.size()) {
105  #ifdef __EXCEPTIONS
106  throw std::domain_error(
107  string(u8"δ is not defined for symbol ") + converter.to_bytes(symbol)
108  );
109  #endif
110  }
111  if (q >= p->labels.size()) {
112  #ifdef __EXCEPTIONS
113  throw std::out_of_range(
114  string("There is no state with index ").append(std::to_string(q))
115  );
116  #endif
117  }
118  return p->transitions[q][i];
119 }
120 
122 valarray<bool> const& nfa::delta(size_t q, string const& utf8Symbol) const {
123  return delta(q, converter.from_bytes(utf8Symbol)[0]);
124 }
125 
127 
132 valarray<bool> nfa::deltaHat(size_t q, std::u32string const& word) const {
133  valarray<bool> qs(p->labels.size());
134  qs[q] = true;
135  return deltaHat(qs, word);
136 }
137 
139 valarray<bool> nfa::deltaHat(size_t q, string const& utf8Word) const {
140  return deltaHat(q, converter.from_bytes(utf8Word));
141 }
142 
144 
149 valarray<bool> nfa::deltaHat(valarray<bool> const& qs, std::u32string const& word) const {
150  valarray<bool> ps = epsilonClosure(qs);
151  for (char32_t symbol : word) {
152  valarray<bool> reached(p->labels.size());
153  size_t qi(0);
154  for (bool qb : ps) {
155  if (qb) {
156  reached |= epsilonClosure(delta(qi, symbol));
157  }
158  qi++;
159  }
160  ps = move(reached);
161  }
162  return ps;
163 }
164 
166 valarray<bool> nfa::deltaHat(valarray<bool> const& qs, string const& utf8Word) const {
167  return deltaHat(qs, converter.from_bytes(utf8Word));
168 }
169 
171 
183 u32string nfa::getShortestWord() const {
184  if (p->accepting[0]) {
185  return U"";
186  }
187  unordered_map<size_t, u32string> shortestWords(p->labels.size());
188  shortestWords.emplace(0, U"");
189  while (true) {
190  for (auto const& stateWord : shortestWords) {
191  for (auto symbol : p->alphabet) {
192  valarray<bool> reached = deltaHat(stateWord.first, u32string(!!symbol, symbol));
193  u32string shWord = stateWord.second + u32string(!!symbol, symbol);
194  for (size_t q = 0; q < reached.size(); q++) { if (reached[q]) {
195  if (p->accepting[q]) {
196  return shWord;
197  }
198  if (shortestWords.find(q) == shortestWords.end()) {
199  shortestWords.emplace(q, shWord);
200  }
201  }}
202  }
203  }
204  }
205 }
206 
208 string nfa::getShortestUtf8Word() const {
209  return converter.to_bytes(getShortestWord());
210 }
211 
213 
217 valarray<bool> const& nfa::epsilonClosure(size_t q) const {
218  if (p->epsClosures[q].size() == 0) {
219  p->epsClosures[q].resize(p->labels.size());
220  p->epsClosures[q][q] = true;
221  int growth(1);
222  while (growth > 0) {
223  growth = 0;
224  valarray<bool> old(p->epsClosures[q]);
225  size_t qi(0);
226  for (bool qb : old) {
227  if (qb) {
228  size_t pi(0);
229  for (bool pb : p->transitions[qi][0]) {
230  if (pb) {
231  if (!p->epsClosures[q][pi]) {
232  growth++;
233  p->epsClosures[q][pi] = true;
234  }
235  }
236  pi++;
237  } // going through the true bools in transitions[qi][0]
238  }
239  qi++;
240  } // going through the true bools in old
241  }
242  }
243  return p->epsClosures[q];
244 }
245 
247 
251 valarray<bool> nfa::epsilonClosure(valarray<bool> const& qs) const {
252  valarray<bool> closure(p->labels.size());
253  size_t qi(0);
254  for (bool qb : qs) {
255  if (qb) {
256  closure |= epsilonClosure(qi);
257  }
258  qi++;
259  } // going through the true bools in qs
260  return closure;
261 }
262 
264 
268 string const& nfa::getLabelOf(size_t q) const {
269  return p->labels[q];
270 }
271 
273 
277 string nfa::getLabelOf(valarray<bool> const& qs) const {
278  string label;
279  size_t qi(0);
280  for (bool qb : qs) {
281  if (qb) {
282  label = label.append(1, label.length() == 0 ? '{' : ',');
283  label = label.append(p->labels[qi]);
284  }
285  qi++;
286  }
287  if (label.length() == 0) {
288  return string("{}");
289  } else {
290  return label.append(1, '}');
291  }
292 }
293 
295 
298 vector<char32_t> const& nfa::getAlphabet() const {
299  return p->alphabet;
300 }
301 
303 
306 vector<string> const& nfa::getUtf8Alphabet() const {
307  return p->utf8Alphabet;
308 }
309 
311 
314 size_t nfa::getNumberOfStates() const {
315  return p->labels.size();
316 }
317 
319 
323 bool nfa::isAccepting(size_t q) const {
324  return p->accepting[q];
325 }
326 
328 
332 bool nfa::hasAccepting(valarray<bool> const& qs) const {
333  for (size_t q = 0; q < getNumberOfStates(); q++) {
334  if (qs[q] && p->accepting[q]) {
335  return true;
336  }
337  }
338  return false;
339 }
340 
342 
349 nfa::builder nfa::unite(nfa const& n1, nfa const& n2) {
350  return builder(n1).unite(n2);
351 }
352 
354 
361 nfa::builder nfa::intersect(nfa const& n1, nfa const& n2) {
362  return builder(n1).intersect(n2);
363 }
364 
366 
373 nfa::builder nfa::subtract(nfa const& n1, nfa const& n2) {
374  dfa::builder b2(n2);
375  for (auto symbol : n1.getAlphabet()) {
376  b2.addSymbol(symbol);
377  }
378  b2.complement().minimize();
379  return builder(n1).intersect(builder(b2.build()).build());
380 }
381 
383 
391  return nfa::builder(dfa::builder(n).complement().minimize().build());
392 }
393 
395 nfa::nfa(nfa const& n) : p(new pImpl(*(n.p))) {}
396 
398 
399 nfa::nfa(nfa&& n) : p(new pImpl) {p.swap(n.p);}
400 
402 nfa::nfa(nfa::builder& b) : nfa(b.build()) {}
403 
405 nfa::nfa(dfa const& n) : nfa(builder(n).build()) {}
406 
408 nfa& nfa::operator=(nfa const& n) {
409  if (this != &n) {
410  p.reset(new pImpl(*(n.p)));
411  }
412  return *this;
413 }
414 
416 
418  if (this != &n) {
419  p.reset(new pImpl);
420  p.swap(n.p);
421  }
422  return *this;
423 }
424 
425 nfa::~nfa() = default;
426 
427 using Ntransitionmap = unordered_map<string, unordered_map<char32_t, unordered_set<string>>>;
428 
431  string initial;
432  unordered_set<string> acceptingStates;
433  unordered_set<char32_t> alphabet;
434  Ntransitionmap transitions;
436 
438  pImpl() = default;
440 
443  string& initial,
444  unordered_set<string>& acceptingStates,
445  unordered_set<char32_t>& alphabet,
446  Ntransitionmap& transitions
447  ) :
448  initial(move(initial)),
450  alphabet(move(alphabet)),
451  transitions(move(transitions)) {}
452 };
453 
456 
458 nfa::builder::builder(nfa const& nfa) : p(new pImpl) {
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 }
480 
482 
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 }
498 
500 nfa::builder::builder(builder const& b) : p(new pImpl(*(b.p))) {}
501 
503 
504 nfa::builder::builder(builder&& b) : p(new pImpl) {p.swap(b.p);}
505 
508  if (this != &b) {
509  p.reset(new pImpl(*(b.p)));
510  }
511  return *this;
512 }
513 
515 
517  if (this != &b) {
518  p.reset(new pImpl);
519  p.swap(b.p);
520  }
521  return *this;
522 }
523 
525 
530  p->alphabet.insert(symbol);
531  return *this;
532 }
533 
535 nfa::builder& nfa::builder::addSymbol(string const& utf8Symbol) {
536  return addSymbol(converter.from_bytes(utf8Symbol)[0]);
537 }
538 
540 
545 nfa::builder& nfa::builder::setAccepting(string const& state, bool accept) {
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 }
557 
559 
564  p->initial = state;
565  p->transitions[state];
566  return *this;
567 }
568 
570 
576 nfa::builder& nfa::builder::addTransition(string const& from, string const& to, char32_t symbol) {
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 }
585 
587 nfa::builder& nfa::builder::addTransition(string const& from, string const& to, string const& utf8Symbol) {
588  return addTransition(from, to, converter.from_bytes(utf8Symbol)[0]);
589 }
590 
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 }
627 
629 
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 }
686 
688 
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 }
766 
768 
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 }
814 
815 nfa::builder::~builder() = default;
816 } // namespace reg
bool isAccepting(size_t q) const
Tests whether a state is an accept state within this DFA.
Definition: dfa.cpp:319
Ntransitionmap transitions
Transition function (state × symbol → set of states) of the prospective NFA.
Definition: nfa.cpp:434
nfa build()
Builds the NFA, as defined by previous operations.
Definition: nfa.cpp:771
static nfa::builder complement(nfa const &n)
Creates a builder for an NFA accepting the complement of the language of an NFA.
Definition: nfa.cpp:390
std::string getShortestUtf8Word() const
Same as above for a UTF-8-encoded word, INCLUDING POTENTIAL INFINITE LOOP.
Definition: nfa.cpp:208
size_t delta(size_t q, char32_t symbol) const
Computes this DFA's transition function for a state and a symbol.
Definition: dfa.cpp:203
Represents nondeterministic finite automata with ε-moves.
Definition: nfa.h:22
std::vector< char32_t > const & getAlphabet() const
Fetches this NFA's set of processable symbols.
Definition: nfa.cpp:298
std::string const & getLabelOf(size_t q) const
Puts a name to an index.
Definition: nfa.cpp:268
Represents deterministic finite automata.
Definition: dfa.h:26
std::vector< std::string > const & getUtf8Alphabet() const
Fetches this NFA's set of processable symbols as UTF-8-encoded strings.
Definition: nfa.cpp:306
vector< vector< valarray< bool > > > transitions
Stores the transition function as a table viz state index × symbol index → list of bools with true a...
Definition: nfa.cpp:36
std::valarray< bool > deltaHat(size_t q, std::u32string const &word) const
Computes this NFA's transition function recursively for a string of symbols, starting in a specified ...
Definition: nfa.cpp:132
Constructs NFAs step by step.
Definition: nfa.h:62
builder & minimize()
Convenience method for chaining purge and merge to achieve proper minimization.
Definition: dfa.cpp:773
bool operator==(nfa const &n) const
Tests whether this NFA accepts exactly the same language as another one.
Definition: nfa.cpp:87
pImpl()
Constructs private implementation object for an NFA accepting the empty language ∅.
Definition: nfa.cpp:39
vector< string > labels
Stores the names of states.
Definition: nfa.cpp:35
bool isAccepting(size_t q) const
Tests whether a state is an accept state within this NFA.
Definition: nfa.cpp:323
static nfa::builder intersect(nfa const &n1, nfa const &n2)
Creates a builder for an NFA accepting the intersection of the languages of two NFAs.
Definition: nfa.cpp:361
builder & unite(nfa const &other)
Makes the prospective NFA also accept every word of another NFA&#39;s language.
Definition: nfa.cpp:636
nfa & operator=(nfa const &n)
Copy-assigns this NFA by copying another one's private implementation object.
Definition: nfa.cpp:408
std::vector< char32_t > const & getAlphabet() const
Fetches this DFA's set of processable symbols.
Definition: dfa.cpp:294
string initial
Name of the prospective NFA&#39;s initial state.
Definition: nfa.cpp:431
bool operator!=(nfa const &n) const
Tests whether this NFA doesn't accept the same language as another one.
Definition: nfa.cpp:92
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 & normalizeStateNames(std::string const &prefix)
Reduces the prospective NFA&#39;s state names to consecutive numbers, prefixed with a given string...
Definition: nfa.cpp:592
Contains the reg::nfa class definition.
valarray< bool > accepting
A true value marks an index as belonging to an accept state.
Definition: nfa.cpp:31
Contains the reg::expression class defintion.
vector< char32_t > alphabet
Represents the set of processable symbols.
Definition: nfa.cpp:32
std::u32string getShortestWord() const
Searches the shortest UTF-32-encoded word accepted by this NFA.
Definition: nfa.cpp:183
static nfa::builder unite(nfa const &n1, nfa const &n2)
Creates a builder for an NFA accepting the union of the languages of two NFAs.
Definition: nfa.cpp:349
builder & complement()
Inverts the prospective DFA&#39;s language with respect to all possible strings over its alphabet...
Definition: dfa.cpp:919
Private implementation details of NFAs.
Definition: nfa.cpp:29
unordered_set< char32_t > alphabet
Set of symbols processable by the prospective NFA.
Definition: nfa.cpp:433
Constructs DFAs step by step.
Definition: dfa.h:60
vector< valarray< bool > > epsClosures
Cache for every state&#39;s ε-closures.
Definition: nfa.cpp:34
size_t getNumberOfStates() const
Counts this DFA's states.
Definition: dfa.cpp:310
builder & makeInitial(std::string const &state)
Resets the initial state for the prospective NFA.
Definition: nfa.cpp:563
vector< string > utf8Alphabet
Represents the set of processable symbols as UTF-8-encoded strings.
Definition: nfa.cpp:33
builder & intersect(nfa const &other)
Makes the prospective NFA accept only words accepted also by another NFA.
Definition: nfa.cpp:694
Private implementation details of NFA builders.
Definition: nfa.cpp:430
std::shared_ptr< dfa const > equivalent
Stores a minimal DFA accepting the same language as this object&#39;s NFA.
Definition: nfa.cpp:30
size_t getNumberOfStates() const
Counts this NFA's states.
Definition: nfa.cpp:314
static nfa::builder subtract(nfa const &n1, nfa const &n2)
Creates a builder for an NFA accepting the set difference of the languages of two NFAs...
Definition: nfa.cpp:373
pImpl(string &initial, unordered_set< string > &acceptingStates, unordered_set< char32_t > &alphabet, Ntransitionmap &transitions)
Constructs private implementation object with provided members.
Definition: nfa.cpp:442
pImpl(vector< char32_t > &alphabet, vector< vector< valarray< bool >>> &transitions, vector< string > &labels, valarray< bool > &acceptingStates)
Constructs private implementation object with provided members and empty ε-closure cache...
Definition: nfa.cpp:49
dfa const & getEquivalentDfa(nfa const *owner)
Returns the equivalent DFA safely, constructing it if it wasn't already.
Definition: nfa.cpp:70
bool hasAccepting(std::valarray< bool > const &qs) const
Tests whether a set of states contains an accept state within this NFA.
Definition: nfa.cpp:332
Definition: dfa.cpp:29
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
nfa()
Constructs an NFA accepting the empty language ∅.
Definition: nfa.cpp:79
builder & operator=(builder const &b)
Copy-assigns a builder by copying another one's private implementation object.
Definition: nfa.cpp:507
unordered_set< string > acceptingStates
Set of names of the prospective NFA&#39;s accept states.
Definition: nfa.cpp:432
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::string const & getLabelOf(size_t q) const
Puts a name to an index.
Definition: dfa.cpp:286
std::valarray< bool > const & delta(size_t q, char32_t symbol) const
Computes this NFA's transition function for a state and a symbol.
Definition: nfa.cpp:102
dfa build()
Builds the DFA, as defined by previous operations, including completion.
Definition: dfa.cpp:964
pImpl()=default
Constructs empty private implementation object.
std::valarray< bool > const & epsilonClosure(size_t q) const
Computes a state's ε-closure.
Definition: nfa.cpp:217
Contains the reg::dfa class definition.
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
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective DFA's alphabet.
Definition: dfa.cpp:587
builder()
Constructs a blank builder object.
Definition: nfa.cpp:455