reglibcpp  1.5.0
(Naïve) C++ implementation of models for regular languages
nfa.cpp
Go to the documentation of this file.
1 #include "nfa.h"
4 using std::valarray;
5 using std::vector;
7 using std::string;
8 using std::to_string;
9 using std::make_unique;
10 using std::make_pair;
11 using std::u32string;
12 
13 using std::move;
14 
15 #include <unordered_map>
16 using std::unordered_map;
17 
18 #include <algorithm>
19 using std::find;
20 using std::min;
21 
22 #include <iterator>
23 
24 #include "dfa.h"
25 #include "expression.h"
26 
27 namespace reg {
28 
30 struct nfa::pImpl {
38 
40  pImpl() :
41  equivalent(),
42  accepting(false, 1),
43  alphabet(1, U'\0'),
44  utf8Alphabet(1, ""),
45  epsClosures(1),
46  labels(1),
47  transitions(1, vector<valarray<bool>>(1, valarray<bool>(false, 1))) {}
48 
51  vector<string>& labels, valarray<bool>& acceptingStates) :
52  accepting(move(acceptingStates)),
53  alphabet(move(alphabet)),
54  labels(move(labels)),
55  transitions(move(transitions)) {
56  utf8Alphabet.reserve(this->alphabet.size());
57  for (char32_t symbol : this->alphabet) {
58  if (symbol == U'\0') {
59  utf8Alphabet.push_back("");
60  } else {
61  utf8Alphabet.push_back(converter.to_bytes(symbol));
62  }
63  }
65  }
66 
68 
71  dfa const& getEquivalentDfa(nfa const* owner) {
72  if (!equivalent) {
73  equivalent.reset(new dfa(dfa::builder(*owner).minimize()));
74  }
75  return *equivalent;
76  }
77 };
78 
80 nfa::nfa() : p(new pImpl) {}
81 
83 nfa::nfa(vector<char32_t>& alphabet, vector<vector<valarray<bool>>>& transitions,
84  vector<string>& labels, valarray<bool>& acceptingStates) :
85  p(new pImpl(alphabet, transitions, labels, acceptingStates)) {}
86 
88 bool nfa::operator==(nfa const& n) const {
89  return p->getEquivalentDfa(this) == n.p->getEquivalentDfa(&n);
90 }
91 
93 bool nfa::operator!=(nfa const& n) const {
94  return p->getEquivalentDfa(this) != n.p->getEquivalentDfa(&n);
95 }
96 
98 
105 valarray<bool> const& nfa::delta(size_t qi, size_t si) const {
106  if (si >= p->alphabet.size()) {
107  throw std::domain_error("There is no symbol with index " + to_string(si));
108  }
109  if (qi >= p->labels.size()) {
110  throw std::out_of_range("There is no state with index " + to_string(qi));
111  }
112  return p->transitions[qi][si];
113 }
114 
116 
123 valarray<bool> const& nfa::delta(size_t qi, char32_t symbol) const {
124  try {
125  return delta(qi, index_of(p->alphabet, symbol));
126  } catch (std::domain_error e) {
127  throw std::domain_error(u8"δ is not defined for symbol " + converter.to_bytes(symbol));
128  }
129 }
130 
132 valarray<bool> const& nfa::delta(size_t qi, string const& utf8Symbol) const {
133  return delta(qi, converter.from_bytes(utf8Symbol)[0]);
134 }
135 
137 
144 nfa::state_set nfa::delta(string const& q, char32_t symbol) const {
145  try {
146  return decodeSet(delta(index_of(getStates(), q), symbol));
147  } catch (std::out_of_range e) {
148  throw std::out_of_range("There is no state named " + q);
149  }
150 }
151 
153 nfa::state_set nfa::delta(string const& q, string const& utf8Symbol) const {
154  return delta(q, converter.from_bytes(utf8Symbol)[0]);
155 }
156 
158 
165 valarray<bool> nfa::deltaHat(size_t qi, u32string const& word) const {
166  if (qi >= p->labels.size()) {
167  throw std::out_of_range("There is no state with index " + to_string(qi));
168  }
169  valarray<bool> qs(p->labels.size());
170  qs[qi] = true;
171  return deltaHat(qs, word);
172 }
173 
175 valarray<bool> nfa::deltaHat(size_t qi, string const& utf8Word) const {
176  return deltaHat(qi, converter.from_bytes(utf8Word));
177 }
178 
180 
187 nfa::state_set nfa::deltaHat(string const& q, u32string const& word) const {
188  try {
189  return decodeSet(deltaHat(index_of(getStates(), q), word));
190  } catch (std::out_of_range e) {
191  throw std::out_of_range("There is no state named " + q);
192  }
193 }
194 
196 nfa::state_set nfa::deltaHat(string const& q, string const& utf8Word) const {
197  return deltaHat(q, converter.from_bytes(utf8Word));
198 }
199 
201 
207 valarray<bool> nfa::deltaHat(valarray<bool> const& qs, u32string const& word) const {
209  for (char32_t symbol : word) {
210  valarray<bool> reached(p->labels.size());
211  size_t qi(0);
212  for (bool qb : ps) {
213  if (qb) {
214  reached |= epsilonClosure(delta(qi, symbol));
215  }
216  qi++;
217  }
218  ps = move(reached);
219  }
220  return ps;
221 }
222 
224 valarray<bool> nfa::deltaHat(valarray<bool> const& qs, string const& utf8Word) const {
225  return deltaHat(qs, converter.from_bytes(utf8Word));
226 }
227 
229 
235 nfa::state_set nfa::deltaHat(nfa::state_set const& qs, u32string const& word) const {
236  return decodeSet(deltaHat(encodeSet(qs), word));
237 }
238 
240 nfa::state_set nfa::deltaHat(nfa::state_set const& qs, string const& utf8Word) const {
241  return deltaHat(qs, converter.from_bytes(utf8Word));
242 }
243 
245 
250  if (p->accepting[0]) {
251  return U"";
252  }
253  unordered_map<size_t, u32string> shortestWords(p->labels.size());
254  size_t oldSize = 0;
255  shortestWords.emplace(0, U"");
256  while (shortestWords.size() > oldSize) {
257  oldSize = shortestWords.size();
258  for (auto const& stateWord : shortestWords) {
259  for (auto symbol : p->alphabet) {
260  valarray<bool> reached = deltaHat(stateWord.first, u32string(!!symbol, symbol));
261  u32string shWord = stateWord.second + u32string(!!symbol, symbol);
262  for (size_t q = 0; q < reached.size(); q++) { if (reached[q]) {
263  if (p->accepting[q]) {
264  return shWord;
265  }
266  if (shortestWords.find(q) == shortestWords.end()) {
267  shortestWords.emplace(q, shWord);
268  }
269  }}
270  }
271  }
272  }
273  throw std::logic_error("This NFA doesn't accept any words!");
274 }
275 
277 string nfa::getShortestUtf8Word() const {
278  return converter.to_bytes(getShortestWord());
279 }
280 
282 
287 valarray<bool> const& nfa::epsilonClosure(size_t qi) const {
288  if (qi >= p->labels.size()) {
289  throw std::out_of_range(
290  string("There is no state with index ").append(std::to_string(qi))
291  );
292  }
293  if (p->epsClosures[qi].size() == 0) {
294  p->epsClosures[qi].resize(p->labels.size());
295  p->epsClosures[qi][qi] = true;
296  int growth(1);
297  while (growth > 0) {
298  growth = 0;
299  valarray<bool> old(p->epsClosures[qi]);
300  size_t qqi(0);
301  for (bool qqb : old) {
302  if (qqb) {
303  size_t pi(0);
304  for (bool pb : p->transitions[qqi][0]) {
305  if (pb) {
306  if (!p->epsClosures[qi][pi]) {
307  growth++;
308  p->epsClosures[qi][pi] = true;
309  }
310  }
311  pi++;
312  } // going through the true bools in transitions[qqi][0]
313  }
314  qqi++;
315  } // going through the true bools in old
316  }
317  }
318  return p->epsClosures[qi];
319 }
320 
322 
327 nfa::state_set nfa::epsilonClosure(string const& q) const {
328  try {
330  } catch (std::out_of_range e) {
331  throw std::out_of_range("There is no state named " + q);
332  }
333 }
334 
336 
341  valarray<bool> closure(p->labels.size());
342  size_t range = min(qs.size(), getNumberOfStates());
343  for (size_t q = 0; q < range; q++) {
344  if (qs[q]) {
345  closure |= epsilonClosure(q);
346  }
347  }
348  return closure;
349 }
350 
352 
357  return decodeSet(epsilonClosure(encodeSet(qs)));
358 }
359 
361 
366 string const& nfa::getLabelOf(size_t qi) const {
367  return p->labels.at(qi);
368 }
369 
371 
375 string nfa::getLabelOf(valarray<bool> const& qs) const {
376  string label;
377  size_t range = min(qs.size(), getNumberOfStates());
378  for (size_t q = 0; q < range; q++) {
379  if (qs[q]) {
380  label = label.append(1, label.length() == 0 ? '{' : ',');
381  label = label.append(p->labels.at(q));
382  }
383  }
384  if (label.length() == 0) {
385  return string("{}");
386  } else {
387  return label.append(1, '}');
388  }
389 }
390 
392 
396 string nfa::getLabelOf(nfa::state_set const& qs) const {
397  return getLabelOf(encodeSet(qs));
398 }
399 
401 
406  state_set states;
407  states.reserve(getNumberOfStates());
408  size_t range = min(qs.size(), getNumberOfStates());
409  for (size_t q = 0; q < range; q++) {
410  if (qs[q]) {
411  states.emplace(getStates()[q]);
412  }
413  }
414  return states;
415 }
416 
418 
424  for (size_t qi = 0; qi < getNumberOfStates(); qi++) {
425  states[qi] = qs.count(getStates()[qi]);
426  }
427  return states;
428 }
429 
431 
434 string const& nfa::getInitialState() const {
435  return getStates()[0];
436 }
437 
439 
443  return p->labels;
444 }
445 
447 
451  return state_set(getStates().begin(), getStates().end());
452 }
453 
455 
459  return valarray<bool>(true, getNumberOfStates());
460 }
461 
463 
467  return p->alphabet;
468 }
469 
471 
475  return p->utf8Alphabet;
476 }
477 
479 
482 size_t nfa::getNumberOfStates() const {
483  return getStates().size();
484 }
485 
487 
490 size_t nfa::getNumberOfSymbols() const {
491  return getAlphabet().size();
492 }
493 
495 
500 bool nfa::isAccepting(size_t qi) const {
501  if (qi >= p->labels.size()) {
502  throw std::out_of_range(
503  string("There is no state with index ").append(std::to_string(qi))
504  );
505  }
506  return p->accepting[qi];
507 }
508 
510 
515 bool nfa::isAccepting(string const& q) const {
516  try {
517  return isAccepting(index_of(getStates(), q));
518  } catch (std::out_of_range e) {
519  throw std::out_of_range("There is no state named " + q);
520  }
521 }
522 
524 
528 bool nfa::hasAccepting(valarray<bool> const& qs) const {
529  size_t range = min(qs.size(), getNumberOfStates());
530  for (size_t q = 0; q < range; q++) {
531  if (qs[q] && p->accepting[q]) {
532  return true;
533  }
534  }
535  return false;
536 }
537 
539 
543 bool nfa::hasAccepting(nfa::state_set const& qs) const {
544  for (size_t qi = 0; qi < getNumberOfStates(); qi++) {
545  if (p->accepting[qi] && qs.count(getStates()[qi])) {
546  return true;
547  }
548  }
549  return false;
550 }
551 
553 
559  return n.getShortestWord();
560 }
561 
563 string findShortestUtf8Word(nfa const& n) {
564  return n.getShortestUtf8Word();
565 }
566 
568 
575 nfa::builder nfa::unite(nfa const& n1, nfa const& n2) {
576  return builder(n1).unite(n2);
577 }
578 
580 
587 nfa::builder nfa::intersect(nfa const& n1, nfa const& n2) {
588  return builder(n1).intersect(n2);
589 }
590 
592 
599 nfa::builder nfa::subtract(nfa const& n1, nfa const& n2) {
600  dfa::builder b2(n2);
601  for (auto symbol : n1.getAlphabet()) {
602  b2.addSymbol(symbol);
603  }
604  b2.complement().minimize();
605  return builder(n1).intersect(builder(b2.build()).build());
606 }
607 
609 
617  return nfa::builder(dfa::builder(n).complement().minimize().build());
618 }
619 
621 nfa::nfa(nfa const& n) : p(new pImpl(*(n.p))) {}
622 
624 
625 nfa::nfa(nfa&& n) : p(new pImpl) {p.swap(n.p);}
626 
628 nfa::nfa(nfa::builder& b) : nfa(b.build()) {}
629 
631 nfa::nfa(dfa const& d) : nfa(builder(d).build()) {}
632 
634 nfa& nfa::operator=(nfa const& n) {
635  if (this != &n) {
636  p.reset(new pImpl(*(n.p)));
637  }
638  return *this;
639 }
640 
642 
644  if (this != &n) {
645  p.reset(new pImpl);
646  p.swap(n.p);
647  }
648  return *this;
649 }
650 
651 nfa::~nfa() = default;
652 
655 
658  string initial;
663 
665  pImpl() = default;
667 
670  string& initial,
674  ) :
675  initial(move(initial)),
677  alphabet(move(alphabet)),
678  transitions(move(transitions)) {}
679 };
680 
683 
685 nfa::builder::builder(nfa const& nfa) : p(new pImpl) {
687  for (char32_t symbol : nfa.getAlphabet()) {
688  addSymbol(symbol);
689  }
690  for (size_t qi = 0; qi < nfa.p->labels.size(); ++qi) {
691  string const& qLabel = nfa.getLabelOf(qi);
692  for (char32_t symbol : p->alphabet) {
693  valarray<bool> ps = nfa.delta(qi, symbol);
694  size_t pi(0);
695  for (bool pb : ps) {
696  if (pb) {
697  addTransition(qLabel, nfa.getLabelOf(pi), symbol);
698  }
699  pi++;
700  }
701  }
702  if (nfa.isAccepting(qi)) {
703  setAccepting(qLabel, true);
704  }
705  }
706 }
707 
709 
711  string initial(dfa.getLabelOf(0));
712  unordered_set<string> acceptingStates;
713  unordered_set<char32_t> alphabet(dfa.getAlphabet().begin(), dfa.getAlphabet().end());
714  Ntransitionmap transitions;
715  transitions[initial];
716  for (size_t q(0); q < dfa.getNumberOfStates(); q++) {
717  for (char32_t symbol : alphabet) {
718  transitions[dfa.getLabelOf(q)][symbol].insert(dfa.getLabelOf(dfa.delta(q, symbol)));
719  }
720  if (dfa.isAccepting(q)) {
721  acceptingStates.insert(dfa.getLabelOf(q));
722  }
723  }
724  p = make_unique<pImpl>(initial, acceptingStates, alphabet, transitions);
725 }
726 
728 nfa::builder::builder(builder const& b) : p(new pImpl(*(b.p))) {}
729 
731 
732 nfa::builder::builder(builder&& b) : p(new pImpl) {p.swap(b.p);}
733 
736  if (this != &b) {
737  p.reset(new pImpl(*(b.p)));
738  }
739  return *this;
740 }
741 
743 
745  if (this != &b) {
746  p.reset(new pImpl);
747  p.swap(b.p);
748  }
749  return *this;
750 }
751 
753 
758  p->alphabet.insert(symbol);
759  return *this;
760 }
761 
763 nfa::builder& nfa::builder::addSymbol(string const& utf8Symbol) {
764  return addSymbol(converter.from_bytes(utf8Symbol)[0]);
765 }
766 
768 
773 nfa::builder& nfa::builder::setAccepting(string const& state, bool accept) {
774  if (p->transitions.empty()) {
775  p->initial = state;
776  }
777  p->transitions[state];
778  if (accept) {
779  p->acceptingStates.insert(state);
780  } else {
781  p->acceptingStates.erase(state);
782  }
783  return *this;
784 }
785 
787 
792  p->initial = state;
793  p->transitions[state];
794  return *this;
795 }
796 
798 
804 nfa::builder& nfa::builder::addTransition(string const& from, string const& to, char32_t symbol) {
805  if (p->transitions.empty()) {
806  p->initial = from;
807  }
808  p->transitions[to];
809  p->transitions[from][symbol].insert(to);
810  addSymbol(symbol);
811  return *this;
812 }
813 
815 nfa::builder& nfa::builder::addTransition(string const& from, string const& to, string const& utf8Symbol) {
816  return addTransition(from, to, converter.from_bytes(utf8Symbol)[0]);
817 }
818 
821  if (!p->transitions.empty()) {
822  vector<string> stateNames;
823  stateNames.reserve(p->transitions.size());
824  stateNames.push_back(p->initial);
825  for (auto const& fromTo : p->transitions) {
826  if (fromTo.first != p->initial) {
827  stateNames.push_back(fromTo.first);
828  }
829  }
830  Ntransitionmap newTr(p->transitions.size());
831  unordered_set<string> newAcc(p->acceptingStates.size());
832  for (size_t q = 0; q < stateNames.size(); q++) {
833  auto const& vias = p->transitions[stateNames[q]];
834  unordered_map<char32_t,unordered_set<string>> newVias(vias.size());
835  for (auto const& viaTo : vias) {
836  unordered_set<string> newTos(viaTo.second.size());
837  for (size_t p = 0; p < stateNames.size(); p++) {
838  if (viaTo.second.find(stateNames[p]) != viaTo.second.cend()) {
839  newTos.insert(string(prefix).append(std::to_string(p)));
840  }
841  }
842  newVias.insert(make_pair(viaTo.first, newTos));
843  }
844  newTr.insert(make_pair(string(prefix).append(std::to_string(q)), newVias));
845  if (p->acceptingStates.find(stateNames[q]) != p->acceptingStates.end()) {
846  newAcc.insert(string(prefix).append(std::to_string(q)));
847  }
848  }
849  p->initial = string(string(prefix).append("0"));
850  p->transitions = newTr;
851  p->acceptingStates = newAcc;
852  }
853  return *this;
854 }
855 
857 
865  string newInitial("q0");
866  if (!p->transitions.empty()) {
867  Ntransitionmap tempTr(p->transitions.size());
868  for (auto const& fromVia : p->transitions) {
869  unordered_map<char32_t,unordered_set<string>> tempVia(fromVia.second.size());
870  for (auto const& viaTo : fromVia.second) {
871  unordered_set<string> tempTo(viaTo.second.size());
872  for (auto const& to : viaTo.second) {
873  tempTo.insert(string(to.length() + 1, '1').replace(1, string::npos, to));
874  }
875  tempVia.insert(make_pair(viaTo.first, tempTo));
876  }
877  tempTr.insert(make_pair(string(fromVia.first.length() + 1, '1').replace(1, string::npos, fromVia.first), tempVia));
878  }
879  p->transitions = tempTr;
880  unordered_set<string> tempAcc(p->acceptingStates.size());
881  for (auto const& acc : p->acceptingStates) {
882  tempAcc.insert(string(acc.length() + 1, '1').replace(1, string::npos, acc));
883  }
884  p->acceptingStates = tempAcc;
885  p->initial = string(p->initial.length() + 1, '1').replace(1, string::npos, p->initial);
886  addTransition(newInitial, p->initial, U'\0');
887  }
888  makeInitial(newInitial);
889  auto & oAlphabet = other.getAlphabet();
890  p->alphabet.insert(oAlphabet.cbegin(), oAlphabet.cend());
891  for (size_t q = 0; q < other.getNumberOfStates(); q++) {
892  auto & qLabel = other.getLabelOf(q);
893  string newQLabel = string(qLabel.length() + 1, '2').replace(1, string::npos, qLabel);
894  unordered_map<char32_t,unordered_set<string>> tempVia(oAlphabet.size() + 1);
895  for (char32_t symbol : oAlphabet) {
896  valarray<bool> const& to = other.delta(q, symbol);
898  for (size_t p = 0; p < other.getNumberOfStates(); p++) { if (to[p]) {
899  auto & pLabel = other.getLabelOf(p);
900  tempTo.insert(string(pLabel.length() + 1, '2').replace(1, string::npos, pLabel));
901  }}
902  tempVia.insert(make_pair(symbol, tempTo));
903  }
904  p->transitions.insert(make_pair(newQLabel, tempVia));
905  if (other.isAccepting(q)) {
906  p->acceptingStates.insert(newQLabel);
907  }
908  if (q == 0) {
909  addTransition(newInitial, newQLabel, U'\0');
910  }
911  }
912  return *this;
913 }
914 
916 
923  if (!p->transitions.empty()) {
924  vector<string> stateNames;
925  stateNames.reserve(p->transitions.size());
926  stateNames.push_back(p->initial);
927  for (auto const& fromTo : p->transitions) {
928  if (fromTo.first != p->initial) {
929  stateNames.push_back(fromTo.first);
930  }
931  }
932  auto const& oAlph = other.getAlphabet();
933  size_t commonSymbols = 0;
934  for (char32_t symbol : p->alphabet) {
935  if (index_of(oAlph, symbol) < oAlph.size()) {
936  commonSymbols++;
937  } else {
938  for (auto & fromVia : p->transitions) {
939  fromVia.second.erase(symbol);
940  }
941  }
942  }
943  p->alphabet.insert(oAlph.begin(), oAlph.end());
944  Ntransitionmap newTr(stateNames.size() * other.getNumberOfStates());
945  unordered_set<string> newAcc(stateNames.size() * other.getNumberOfStates());
946  unordered_map<size_t, unordered_map<size_t, string const*>> pairToName(stateNames.size() * other.getNumberOfStates());
947  for (size_t q = 0; q < stateNames.size(); q++) {
948  for (size_t qq = 0; qq < other.getNumberOfStates(); qq++) {
949  string potentialName = stateNames[q] + other.getLabelOf(qq);
950  for (auto nameIt = newTr.find(potentialName); nameIt != newTr.end(); nameIt = newTr.find(potentialName)) {
951  potentialName.append("_");
952  }
953  auto nameIt = newTr.emplace(potentialName, commonSymbols);
954  pairToName.emplace(q, 1).first->second.emplace(qq, &(nameIt.first->first));
955  if (p->acceptingStates.find(stateNames[q]) != p->acceptingStates.end() && other.isAccepting(qq)) {
956  newAcc.insert(potentialName);
957  }
958  }
959  p->transitions[stateNames[q]][U'\0'].insert(stateNames[q]);
960  // Needed due to the equivalence of standing still to “taking” an ε-transition.
961  }
962  for (size_t q = 0; q < stateNames.size(); q++) {
963  auto const& qLabel = stateNames[q];
964  auto const& viaTos = p->transitions[qLabel];
965  for (auto const& viaTo : viaTos) {
966  for (size_t qq = 0; qq < other.getNumberOfStates(); qq++) {
967  valarray<bool> const& reached = other.delta(qq, viaTo.first);
968  for (auto const& to : viaTo.second) {
969  size_t p = index_of(stateNames, to);
970  for (size_t pp = 0; pp < reached.size(); pp++) {
971  if (reached[pp] || (pp == qq && viaTo.first == U'\0')) {
972  // Needed due to the equivalence of standing still to “taking” an ε-transition.
973  newTr[*(pairToName[q][qq])][viaTo.first].insert(*(pairToName[p][pp]));
974  }
975  }
976  }
977  }
978  }
979  }
980  for (auto & fromVia : newTr) {
981  auto const& from = fromVia.first;
982  auto to = fromVia.second.find(U'\0');
983  to->second.erase(from);
984  if (to->second.empty()) {
985  fromVia.second.erase(to);
986  }
987  }
988  p->transitions = newTr;
989  p->acceptingStates = newAcc;
990  p->initial = *(pairToName[0][0]);
991  }
992  return *this;
993 }
994 
996 
1000  p->transitions[p->initial];
1001  p->alphabet.insert(U'\0');
1002  vector<char32_t> alphabetV(p->alphabet.begin(), p->alphabet.end());
1003  std::sort(alphabetV.begin(), alphabetV.end());
1004  vector<string> labelV(p->transitions.size());
1005  labelV[0] = p->initial;
1006  valarray<bool> acceptingV(p->transitions.size());
1007  acceptingV[0] = (p->acceptingStates.find(p->initial) != p->acceptingStates.end());
1008  size_t i(1);
1009  for (auto entry : p->transitions) {
1010  if (entry.first == p->initial) {
1011  continue;
1012  }
1013  labelV[i] = entry.first;
1014  acceptingV[i++] = (
1015  p->acceptingStates.find(entry.first) != p->acceptingStates.end()
1016  );
1017  }
1018  vector<vector<valarray<bool>>> transitionV(
1019  p->transitions.size(),
1021  p->alphabet.size()+1,
1022  valarray<bool>(labelV.size())
1023  )
1024  );
1025  unordered_set<string> emptySet;
1026  size_t qi(0);
1027  for (auto const& q : labelV) {
1028  unordered_map<char32_t,unordered_set<string>> const& fromQ = p->transitions[q];
1029  size_t si(0);
1030  for (char32_t symbol : alphabetV) {
1031  auto to = fromQ.find(symbol);
1032  unordered_set<string> const& viaSymbol(to != fromQ.end() ? to->second : emptySet);
1033  i = 0;
1034  for (auto const& p : labelV) {
1035  transitionV[qi][si][i++] = (viaSymbol.count(p) != 0);
1036  }
1037  si++;
1038  }
1039  qi++;
1040  }
1041  return {alphabetV, transitionV, labelV, acceptingV};
1042 }
1043 
1044 nfa::builder::~builder() = default;
1045 } // namespace reg
Ntransitionmap transitions
Transition function (state × symbol → set of states) of the prospective NFA.
Definition: nfa.cpp:661
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this DFA.
Definition: dfa.cpp:415
nfa build()
Builds the NFA, as defined by previous operations.
Definition: nfa.cpp:999
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:616
std::string getShortestUtf8Word() const
Same as above for a UTF-8-encoded word.
Definition: nfa.cpp:277
size_t getNumberOfSymbols() const
Counts this NFA's alphabet symbols.
Definition: nfa.cpp:490
Represents nondeterministic finite automata with ε-moves.
Definition: nfa.h:25
std::vector< char32_t > const & getAlphabet() const
Fetches this NFA's set of processable symbols.
Definition: nfa.cpp:466
std::string const & getLabelOf(size_t q) const
Puts a name to an index.
Definition: nfa.cpp:366
Represents deterministic finite automata.
Definition: dfa.h:27
std::vector< std::string > const & getUtf8Alphabet() const
Fetches this NFA's set of processable symbols as UTF-8-encoded strings.
Definition: nfa.cpp:474
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:37
Constructs NFAs step by step.
Definition: nfa.h:88
std::wstring_convert< std::codecvt_utf8< char32_t >, char32_t > converter
Converts between UTF-8-encoded and UTF-32-encoded strings.
Definition: dfa.cpp:1088
builder & minimize()
Convenience method for chaining purge and merge to achieve proper minimization.
Definition: dfa.cpp:858
bool operator==(nfa const &n) const
Tests whether this NFA accepts exactly the same language as another one.
Definition: nfa.cpp:88
pImpl()
Constructs private implementation object for an NFA accepting the empty language ∅.
Definition: nfa.cpp:40
vector< string > labels
Stores the names of states.
Definition: nfa.cpp:36
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:587
builder & unite(nfa const &other)
Makes the prospective NFA also accept every word of another NFA&#39;s language.
Definition: nfa.cpp:864
size_t delta(size_t qi, size_t si) const
Computes this DFA's transition function for a state index and a symbol index.
Definition: dfa.cpp:227
nfa & operator=(nfa const &n)
Copy-assigns this NFA by copying another one's private implementation object.
Definition: nfa.cpp:634
std::vector< char32_t > const & getAlphabet() const
Fetches this DFA's set of processable symbols.
Definition: dfa.cpp:381
string initial
Name of the prospective NFA&#39;s initial state.
Definition: nfa.cpp:658
std::valarray< bool > encodeSet(state_set const &qs) const
Translates a set of states from set to bool representation.
Definition: nfa.cpp:422
bool operator!=(nfa const &n) const
Tests whether this NFA doesn't accept the same language as another one.
Definition: nfa.cpp:93
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective NFA's alphabet.
Definition: nfa.cpp:757
state_set getStatesSet() const
Fetches this NFA's set of states as a set of (references to) strings.
Definition: nfa.cpp:450
builder & setAccepting(std::string const &state, bool accept)
Sets whether or not a state will be accepting within the prospective NFA.
Definition: nfa.cpp:773
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:820
Contains the reg::nfa class definition.
valarray< bool > accepting
A true value marks an index as belonging to an accept state.
Definition: nfa.cpp:32
Contains the reg::expression class defintion.
vector< char32_t > alphabet
Represents the set of processable symbols.
Definition: nfa.cpp:33
state_set decodeSet(std::valarray< bool > const &qs) const
Translates a set of states from bool to set representation.
Definition: nfa.cpp:405
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this NFA.
Definition: nfa.cpp:500
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:1080
std::u32string getShortestWord() const
Searches the shortest UTF-32-encoded word accepted by this NFA.
Definition: nfa.cpp:249
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:575
builder & complement()
Inverts the prospective DFA&#39;s language with respect to all possible strings over its alphabet...
Definition: dfa.cpp:1004
Private implementation details of NFAs.
Definition: nfa.cpp:30
std::unordered_set< std::reference_wrapper< std::string const >, hash_reference_string_const, equal_to_reference_string_const > state_set
Nicer name for sets of names of states. Should store references to names in getStates.
Definition: nfa.h:28
unordered_set< char32_t > alphabet
Set of symbols processable by the prospective NFA.
Definition: nfa.cpp:660
Constructs DFAs step by step.
Definition: dfa.h:70
vector< valarray< bool > > epsClosures
Cache for every state&#39;s ε-closures.
Definition: nfa.cpp:35
size_t getNumberOfStates() const
Counts this DFA's states.
Definition: dfa.cpp:397
builder & makeInitial(std::string const &state)
Resets the initial state for the prospective NFA.
Definition: nfa.cpp:791
vector< string > utf8Alphabet
Represents the set of processable symbols as UTF-8-encoded strings.
Definition: nfa.cpp:34
builder & intersect(nfa const &other)
Makes the prospective NFA accept only words accepted also by another NFA.
Definition: nfa.cpp:922
Private implementation details of NFA builders.
Definition: nfa.cpp:657
std::shared_ptr< dfa const > equivalent
Stores a minimal DFA accepting the same language as this object&#39;s NFA.
Definition: nfa.cpp:31
size_t getNumberOfStates() const
Counts this NFA's states.
Definition: nfa.cpp:482
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:599
pImpl(string &initial, unordered_set< string > &acceptingStates, unordered_set< char32_t > &alphabet, Ntransitionmap &transitions)
Constructs private implementation object with provided members.
Definition: nfa.cpp:669
std::valarray< bool > getStatesBools() const
Fetches this NFA's set of states encoded as an array of bools.
Definition: nfa.cpp:458
std::valarray< bool > deltaHat(size_t qi, std::u32string const &word) const
Computes this NFA's transition function recursively for a string of symbols, starting in a state spec...
Definition: nfa.cpp:165
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:50
dfa const & getEquivalentDfa(nfa const *owner)
Returns the equivalent DFA safely, constructing it if it wasn't already.
Definition: nfa.cpp:71
bool hasAccepting(std::valarray< bool > const &qs) const
Tests whether a set of states contains an accept state within this NFA.
Definition: nfa.cpp:528
Where this library lives.
Definition: dfa.cpp:51
nfa()
Constructs an NFA accepting the empty language ∅.
Definition: nfa.cpp:80
string findShortestUtf8Word(dfa const &d)
Same as above for a UTF-8-encoded word.
Definition: dfa.cpp:447
builder & operator=(builder const &b)
Copy-assigns a builder by copying another one's private implementation object.
Definition: nfa.cpp:735
std::string const & getInitialState() const
Names this NFA's initial state.
Definition: nfa.cpp:434
u32string findShortestWord(dfa const &d)
Searches the shortest UTF-32-encoded word accepted by a given DFA.
Definition: dfa.cpp:442
unordered_set< string > acceptingStates
Set of names of the prospective NFA&#39;s accept states.
Definition: nfa.cpp:659
builder & addTransition(std::string const &from, std::string const &to, char32_t symbol)
Adds a transition for the prospective NFA.
Definition: nfa.cpp:804
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.
Definition: nfa.cpp:105
dfa build()
Builds the DFA, as defined by previous operations, including completion.
Definition: dfa.cpp:1049
std::string const & getLabelOf(size_t qi) const
Puts a name to an index.
Definition: dfa.cpp:357
std::valarray< bool > const & epsilonClosure(size_t qi) const
Computes a state's ε-closure.
Definition: nfa.cpp:287
std::vector< std::string > const & getStates() const
Fetches this NFA's set of states in order of internal representation.
Definition: nfa.cpp:442
pImpl()=default
Constructs empty private implementation object.
Contains the reg::dfa class definition.
builder & addSymbol(char32_t symbol)
Adds a symbol to the prospective DFA's alphabet.
Definition: dfa.cpp:672
builder()
Constructs a blank builder object.
Definition: nfa.cpp:682