reglibcpp  2.0.0
A C++ implementation of models for regular languages
fabuilder.cpp
Go to the documentation of this file.
1 // Copyright 2017, 2018 Tom Kranz
2 //
3 // This file is part of reglibcpp.
4 //
5 // reglibcpp is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // reglibcpp is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with reglibcpp. If not, see <https://www.gnu.org/licenses/>.
17 
19 #include "fabuilder.h"
20 
21 #include <forward_list>
22 #include <unordered_map>
23 
24 #include "utils.h"
25 
26 using std::forward_list;
27 using std::string;
28 using std::u32string;
29 using std::unordered_map;
30 using std::unordered_set;
31 using std::valarray;
32 using std::vector;
33 
34 using std::move;
35 
36 namespace reg {
37 
40  string const* initial = nullptr;
48 
54 
56 
57  string const* findStatePointer(string const& state) {
58  return &(transitions.emplace(state, alphabet.size()).first->first);
59  }
60 
62 
63  string const* findStatePointer(string&& state) {
64  return &(transitions.emplace(move(state), alphabet.size()).first->first);
65  }
66 
68  bool isDeterministic() {
69  for (auto const& from : transitions) {
70  for (auto const& via : from.second) {
71  if ((via.first == U'\0' && !via.second.empty()) ||
72  via.second.size() > 1) {
73  return false;
74  }
75  }
76  }
77  return true;
78  }
79 
81  bool isTrashState(string const* q) const {
82  if (acceptingStates.count(q)) {
83  return false;
84  }
85  auto const& from = transitions.at(*q);
86  for (auto const& via : from) {
87  if (via.second.size() > 1 ||
88  (via.second.size() == 1 && !via.second.count(q))) {
89  return false;
90  }
91  }
92  return true;
93  }
94 
96  string const* generateNewState() {
97  size_t q(0);
98  string const* newStateP = nullptr;
99  while (newStateP == nullptr) {
100  auto newStateIns =
101  transitions.emplace("q" + std::to_string(q++), alphabet.size());
102  if (newStateIns.second) {
103  newStateP = &(newStateIns.first->first);
104  }
105  }
106  if (transitions.size() == 1) {
107  initial = newStateP;
108  }
109  return newStateP;
110  }
111 
113  impl() = default;
114 
117  impl(impl const& other)
118  : alphabet(other.alphabet),
119  transitions(other.transitions.size()),
120  acceptingStates(other.acceptingStates.size()) {
121  for (auto const& from : other.transitions) {
122  auto newFrom = transitions.emplace(from.first, from.second.size()).first;
123  auto& newVias = newFrom->second;
124  for (auto const& via : from.second) {
125  auto& newTos =
126  newVias.emplace(via.first, via.second.size()).first->second;
127  for (string const* to : via.second) {
128  newTos.emplace(findStatePointer(*to));
129  }
130  }
131  if (other.acceptingStates.count(&(from.first))) {
132  acceptingStates.emplace(&(newFrom->first));
133  }
134  }
135  initial = findStatePointer(*(other.initial));
136  }
137 
139  impl(nfa const& nfa)
140  : alphabet(nfa.getAlphabet_().begin(), nfa.getAlphabet_().end()),
141  transitions(nfa.getStates().size()),
142  acceptingStates(nfa.getStates().size()) {
143  auto const& alphabetV = nfa.getAlphabet_();
144  auto const& statesV = nfa.getStates();
146  for (size_t qi = 0; qi < statesV.size(); qi++) {
147  auto qIt = transitions.emplace(statesV[qi], alphabetV.size()).first;
148  for (size_t si = 0; si < alphabetV.size(); si++) {
149  auto const& pis = nfa.delta(qi, si);
150  auto sIt = qIt->second.emplace(alphabetV[si], statesV.size()).first;
151  for (size_t pi = 0; pi < pis.size(); pi++) {
152  if (pis[pi]) {
153  sIt->second.emplace(findStatePointer(statesV[pi]));
154  }
155  }
156  }
157  if (nfa.isAccepting(qi)) {
158  acceptingStates.emplace(&(qIt->first));
159  }
160  }
161  }
162 
164  impl(dfa const& dfa)
165  : alphabet(dfa.getAlphabet_().begin(), dfa.getAlphabet_().end()),
166  transitions(dfa.getStates().size()),
167  acceptingStates(dfa.getStates().size()) {
168  auto const& alphabetV = dfa.getAlphabet_();
169  auto const& statesV = dfa.getStates();
171  for (size_t qi = 0; qi < statesV.size(); qi++) {
172  auto qIt = transitions.emplace(statesV[qi], alphabetV.size()).first;
173  for (size_t si = 0; si < alphabetV.size(); si++) {
174  size_t pi = dfa.delta(qi, si);
175  auto sIt = qIt->second.emplace(alphabetV[si], statesV.size()).first;
176  sIt->second.emplace(findStatePointer(statesV[pi]));
177  }
178  if (dfa.isAccepting(qi)) {
179  acceptingStates.emplace(&(qIt->first));
180  }
181  }
182  }
183 };
184 
186 fabuilder::fabuilder() : pim(new impl) {}
187 
190 fabuilder::fabuilder(nfa const& nfa) : pim(new impl(nfa)) {}
191 
194 
198 fabuilder::fabuilder(dfa const& dfa) : pim(new impl(dfa)) {}
199 
202 fabuilder::fabuilder(fabuilder const& b) : pim(new impl(*(b.pim))) {}
203 
206 
207 fabuilder::fabuilder(fabuilder&& b) : pim(new impl) { pim.swap(b.pim); }
208 
209 fabuilder::~fabuilder() = default;
210 
214  if (this != &b) {
215  pim.reset(new impl(*(b.pim)));
216  }
217  return *this;
218 }
219 
222 
224  if (this != &b) {
225  pim.reset(new impl());
226  pim.swap(b.pim);
227  }
228  return *this;
229 }
230 
232 
238 fabuilder& fabuilder::setAccepting(std::string const& state, bool accept) {
239  string const* stateP = pim->findStatePointer(state);
240  if (pim->transitions.size() == 1) {
241  pim->initial = stateP;
242  }
243  if (accept) {
244  pim->acceptingStates.emplace(stateP);
245  } else {
246  pim->acceptingStates.erase(stateP);
247  }
248  return *this;
249 }
250 
252 
257  pim->initial = pim->findStatePointer(state);
258  return *this;
259 }
260 
262 
267  return addSymbol_(converter.from_bytes(symbol)[0]);
268 }
269 
271 
282  std::string const& to,
283  std::string const& symbol) {
284  return addTransition_(from, to, converter.from_bytes(symbol)[0]);
285 }
286 
288 
292 fabuilder& fabuilder::addSymbol_(char32_t u32symbol) {
293  pim->alphabet.emplace(u32symbol);
294  return *this;
295 }
296 
298 
309  std::string const& to,
310  char32_t u32symbol) {
311  auto fromIt = pim->transitions.emplace(from, pim->alphabet.size()).first;
312  if (pim->transitions.size() == 1) {
313  pim->initial = &(fromIt->first);
314  }
315  string const* toP = pim->findStatePointer(to);
316  auto u32symbolIt = fromIt->second.emplace(u32symbol, 1).first;
317  u32symbolIt->second.emplace(toP);
318  addSymbol_(u32symbol);
319  return *this;
320 }
321 
324 
330  nfa nfa = buildNfa();
331  pim->transitions.clear();
332  pim->acceptingStates.clear();
333  pim->alphabet.erase(U'\0');
336  size_t stackSize(1);
337  pim->initial = pim->findStatePointer(nfa.to_string(stack.front()));
338  while (stackSize) {
339  valarray<bool> current(move(stack.front()));
340  stackSize--, stack.pop_front();
341  auto currentIt =
342  pim->transitions.emplace(nfa.to_string(current), pim->alphabet.size())
343  .first;
344  for (char32_t symbol : pim->alphabet) {
345  valarray<bool> next(nfa.deltaHat_(current, u32string(1, symbol)));
346  currentIt->second[symbol].emplace(
347  pim->findStatePointer(nfa.to_string(next)));
348  auto equalToNext = [&](valarray<bool> const& ref) -> bool {
349  return (next == ref).min() == true;
350  };
351  if (!equalToNext(current) &&
352  none_of(stack.begin(), stack.end(), equalToNext) &&
353  none_of(done.begin(), done.end(), equalToNext)) {
354  stack.push_front(next);
355  stackSize++;
356  }
357  }
358  if (nfa.isAccepting(current)) {
359  pim->acceptingStates.emplace(&(currentIt->first));
360  }
361  done.insert(current);
362  }
363  return *this;
364 }
365 
368 
377  bool trashUsed(false);
378  string const* trashState = [&] {
379  for (auto const& entry : pim->transitions) {
380  if (pim->isTrashState(&entry.first)) {
381  trashUsed = true;
382  return &entry.first;
383  }
384  }
385  return pim->generateNewState();
386  }();
387  for (auto& from : pim->transitions) {
388  for (char32_t symbol : pim->alphabet) {
389  if (symbol == U'\0') {
390  from.second.erase(symbol);
391  } else {
392  auto& via = from.second[symbol];
393  if (via.empty()) {
394  via.insert(trashState);
395  trashUsed |= (&from.first != trashState);
396  }
397  }
398  }
399  }
400  if (!trashUsed) {
401  pim->transitions.erase(*trashState);
402  }
403  pim->alphabet.erase(U'\0');
404  return *this;
405 }
406 
410 
433  if (pim->isDeterministic()) {
434  complete();
435  } else {
436  purge();
437  if (pim->isDeterministic()) {
438  complete();
439  } else if (force) {
440  powerset();
441  } else {
442  throw nondeterminism_exception();
443  }
444  }
445  vector<vector<size_t>> tTable(pim->transitions.size());
446  valarray<bool> accepting(false, pim->transitions.size());
447  vector<char32_t> sortedAlphabet(pim->alphabet.begin(), pim->alphabet.end());
448  std::sort(sortedAlphabet.begin(), sortedAlphabet.end());
449  vector<string const*> orderedStates;
450  orderedStates.reserve(pim->transitions.size());
451  orderedStates.push_back(pim->initial);
452  for (auto const& entry : pim->transitions) {
453  if (&entry.first != pim->initial) {
454  orderedStates.push_back(&entry.first);
455  }
456  }
457  for (size_t qi(0); qi < orderedStates.size(); qi++) {
458  string const* q(orderedStates[qi]);
459  accepting[qi] = pim->acceptingStates.count(q);
460  for (size_t si(0); si < sortedAlphabet.size(); si++) {
461  tTable[qi].push_back(index_of(
462  orderedStates, *(pim->transitions[*q][sortedAlphabet[si]].begin())));
463  }
464  }
465  auto equivalences = dfa::indistinguishableStates(tTable, accepting);
466  for (size_t q(0); q < orderedStates.size(); q++) {
467  for (size_t first(0); first < equivalences[q].size(); first++) {
468  if (equivalences[q][first] && q > first) {
469  string const* superfluous(orderedStates[q]);
470  string const* remaining(orderedStates[first]);
471  pim->acceptingStates.erase(superfluous);
472  pim->transitions.erase(*superfluous);
473  for (auto& from : pim->transitions) {
474  for (auto& via : from.second) {
475  auto supIt = via.second.find(superfluous);
476  if (supIt != via.second.end()) {
477  via.second.erase(supIt);
478  via.second.insert(remaining);
479  }
480  }
481  }
482  break;
483  }
484  }
485  }
486  return *this;
487 }
488 
491 
501  unordered_set<string const*> reachable(&(pim->initial), &(pim->initial) + 1);
502  unordered_set<string const*> newReachable(reachable);
503  while (newReachable.size() > 0) {
504  unordered_set<string const*> oldReachable(move(newReachable));
505  newReachable.clear();
506  for (string const* reachableState : oldReachable) {
507  for (auto const& via : pim->transitions[*reachableState]) {
508  for (auto reachedState : via.second) {
509  if (reachable.insert(reachedState).second) {
510  newReachable.insert(reachedState);
511  }
512  }
513  }
514  }
515  }
516  for (auto it = pim->transitions.begin(); it != pim->transitions.end();) {
517  if (!reachable.count(&(it->first))) {
518  pim->acceptingStates.erase(&(it->first));
519  it = pim->transitions.erase(it);
520  } else {
521  it++;
522  }
523  }
524  unordered_set<string const*> producing(pim->acceptingStates);
525  unordered_set<string const*> newProducing(producing);
526  while (newProducing.size() > 0) {
527  unordered_set<string const*> oldProducing(move(newProducing));
528  newProducing.clear();
529  for (auto const& from : pim->transitions) {
530  for (auto const& via : from.second) {
531  for (auto target : via.second) {
532  if (producing.count(target)) {
533  if (producing.insert(&(from.first)).second) {
534  newProducing.insert(&(from.first));
535  }
536  break;
537  }
538  }
539  }
540  }
541  }
542  for (auto it = pim->transitions.begin(); it != pim->transitions.end();) {
543  if (!producing.count(&(it->first)) && &(it->first) != pim->initial) {
544  pim->acceptingStates.erase(&(it->first));
545  for (auto& from : pim->transitions) {
546  for (auto& via : from.second) {
547  via.second.erase(&(it->first));
548  }
549  }
550  it = pim->transitions.erase(it);
551  } else {
552  it++;
553  }
554  }
555  return *this;
556 }
557 
560 
570 fabuilder& fabuilder::minimize(bool force) { return merge(force).purge(); }
571 
573 
583  if (!pim->transitions.empty()) {
584  auto const& oAlph = other.getAlphabet_();
585  for (char32_t symbol : oAlph) {
586  addSymbol_(symbol);
587  }
588  size_t trash =
589  other.getStates().size() * !!(pim->alphabet.size() - oAlph.size());
590  complete();
591  vector<string const*> stateNames;
592  stateNames.reserve(pim->transitions.size());
593  stateNames.push_back(pim->initial);
594  for (auto const& fromVia : pim->transitions) {
595  if (&(fromVia.first) != pim->initial) {
596  stateNames.push_back(&(fromVia.first));
597  }
598  }
600  newTr(stateNames.size() * (other.getStates().size() + !!trash));
601  unordered_set<string const*> newAcc(stateNames.size() *
602  (other.getStates().size() + !!trash));
604  stateNames.size());
605  for (size_t q = 0; q < stateNames.size(); q++) {
606  for (size_t qq = 0; qq < other.getStates().size() + !!trash; qq++) {
607  string potentialName = *stateNames[q];
608  if (qq < other.getStates().size()) {
609  potentialName.append(other.getStates()[qq]);
610  }
611  while (newTr.count(potentialName)) {
612  potentialName.append("_");
613  }
614  auto nameIt =
615  newTr.emplace(move(potentialName), pim->alphabet.size()).first;
616  pairToName.emplace(q, 1).first->second.emplace(qq, &(nameIt->first));
617  if (pim->acceptingStates.count(stateNames[q]) ||
618  (qq < other.getStates().size() && other.isAccepting(qq))) {
619  newAcc.insert(&(nameIt->first));
620  }
621  }
622  }
623  valarray<bool> empty(other.getStates().size());
624  for (char32_t symbol : pim->alphabet) {
625  for (size_t q = 0; q < stateNames.size(); q++) {
626  auto const& viaTo = pim->transitions[*stateNames[q]][symbol];
627  for (size_t qq = 0; qq < other.getStates().size() + !!trash; qq++) {
628  for (string const* pLabel : viaTo) {
629  size_t p = index_of(stateNames, pLabel);
630  valarray<bool> const* pps;
631  try {
632  pps = &other.delta_(qq, symbol);
633  } catch (std::logic_error e) {
634  pps = &empty;
635  }
636  if (!pps->max()) {
637  newTr[*(pairToName[q][qq])][symbol].emplace(pairToName[p][trash]);
638  } else {
639  for (size_t pp = 0; pp < other.getStates().size(); pp++) {
640  if ((*pps)[pp]) {
641  newTr[*(pairToName[q][qq])][symbol].emplace(
642  pairToName[p][pp]);
643  }
644  }
645  }
646  }
647  }
648  }
649  }
650  pim->transitions = move(newTr);
651  pim->acceptingStates = move(newAcc);
652  pim->initial = pairToName[0][0];
653  } else {
654  pim->alphabet.insert(other.getAlphabet_().begin(),
655  other.getAlphabet_().end());
656  makeInitial(other.getInitialState());
657  for (size_t q = 0; q < other.getStates().size(); ++q) {
658  for (size_t si = 0; si < other.getAlphabet_().size(); si++) {
659  auto const& reached = other.delta(q, si);
660  for (size_t p = 0; p < other.getStates().size(); p++) {
661  if (reached[q]) {
662  addTransition_(other.getStates()[q], other.getStates()[p],
663  other.getAlphabet_()[si]);
664  }
665  }
666  }
667  setAccepting(other.getStates()[q], other.isAccepting(q));
668  }
669  }
670  return *this;
671 }
672 
674 
684  if (!pim->transitions.empty()) {
685  vector<string const*> stateNames;
686  stateNames.reserve(pim->transitions.size());
687  stateNames.emplace_back(pim->initial);
688  for (auto const& fromTo : pim->transitions) {
689  if (&(fromTo.first) != pim->initial) {
690  stateNames.emplace_back(&(fromTo.first));
691  }
692  }
693  auto const& oAlph = other.getAlphabet_();
694  size_t commonSymbols = 0;
695  for (char32_t symbol : pim->alphabet) {
696  if (index_of(oAlph, symbol) < oAlph.size()) {
697  commonSymbols++;
698  } else {
699  for (auto& fromVia : pim->transitions) {
700  fromVia.second.erase(symbol);
701  }
702  }
703  }
704  pim->alphabet.insert(oAlph.begin(), oAlph.end());
706  newTr(stateNames.size() * other.getStates().size());
707  unordered_set<string const*> newAcc(stateNames.size() *
708  other.getStates().size());
710  stateNames.size() * other.getStates().size());
711  for (size_t q = 0; q < stateNames.size(); q++) {
712  for (size_t qq = 0; qq < other.getStates().size(); qq++) {
713  string potentialName = *stateNames[q] + other.getStates()[qq];
714  while (newTr.count(potentialName)) {
715  potentialName.append("_");
716  }
717  auto nameIt = newTr.emplace(move(potentialName), commonSymbols).first;
718  pairToName.emplace(q, 1).first->second.emplace(qq, &(nameIt->first));
719  if (pim->acceptingStates.count(stateNames[q]) &&
720  other.isAccepting(qq)) {
721  newAcc.emplace(&(nameIt->first));
722  }
723  }
724  pim->transitions[*stateNames[q]][U'\0'].emplace(stateNames[q]);
725  // Needed due to the equivalence of standing still to “taking” an
726  // ε-transition.
727  }
728  for (size_t q = 0; q < stateNames.size(); q++) {
729  auto const& viaTos = pim->transitions[*stateNames[q]];
730  for (auto const& viaTo : viaTos) {
731  for (size_t qq = 0; qq < other.getStates().size(); qq++) {
732  valarray<bool> const& reached = other.delta_(qq, viaTo.first);
733  for (string const* to : viaTo.second) {
734  size_t p = index_of(stateNames, to);
735  for (size_t pp = 0; pp < reached.size(); pp++) {
736  if (reached[pp] || (pp == qq && viaTo.first == U'\0')) {
737  // Needed due to the equivalence of standing still to “taking”
738  // an ε-transition.
739  newTr[*(pairToName[q][qq])][viaTo.first].insert(
740  &(newTr.find(*(pairToName[p][pp]))->first));
741  }
742  }
743  }
744  }
745  }
746  }
747  for (auto& fromVia : newTr) {
748  auto const& from = fromVia.first;
749  auto to = fromVia.second.find(U'\0');
750  to->second.erase(&from);
751  if (to->second.empty()) {
752  fromVia.second.erase(to);
753  }
754  }
755  pim->transitions = move(newTr);
756  pim->acceptingStates = move(newAcc);
757  pim->initial = pim->findStatePointer(*(pairToName[0][0]));
758  }
759  return *this;
760 }
761 
764 
781  if (pim->isDeterministic()) {
782  complete();
783  } else {
784  purge();
785  if (pim->isDeterministic()) {
786  complete();
787  } else if (force) {
788  powerset();
789  } else {
790  throw nondeterminism_exception();
791  }
792  }
793  for (auto const& fromVia : pim->transitions) {
794  if (!pim->acceptingStates.erase(&(fromVia.first))) {
795  pim->acceptingStates.insert(&(fromVia.first));
796  }
797  }
798  return *this;
799 }
800 
803 
808  if (!pim->transitions.empty()) {
809  vector<string const*> stateNames;
810  stateNames.reserve(pim->transitions.size());
811  stateNames.push_back(pim->initial);
812  for (auto const& fromTo : pim->transitions) {
813  if (&(fromTo.first) != pim->initial) {
814  stateNames.push_back(&(fromTo.first));
815  }
816  }
818  newTr(pim->transitions.size());
819  unordered_set<string const*> newAcc(pim->acceptingStates.size());
820  string const* newInitial;
821  for (size_t q = 0; q < stateNames.size(); q++) {
822  auto const& vias = pim->transitions[*stateNames[q]];
823  auto newIt = newTr.emplace(prefix + std::to_string(q), vias.size()).first;
824  string const* newQ = &(newIt->first);
825  auto& newVias = newIt->second;
826  for (auto const& viaTo : vias) {
827  auto& newTos =
828  newVias.emplace(viaTo.first, viaTo.second.size()).first->second;
829  for (size_t p = 0; p < stateNames.size(); p++) {
830  if (viaTo.second.count(stateNames[p])) {
831  newTos.emplace(
832  &(newTr
833  .emplace(
834  prefix + std::to_string(p),
835  pim->transitions[*stateNames[p]][viaTo.first].size())
836  .first->first));
837  }
838  }
839  }
840  if (pim->acceptingStates.count(stateNames[q])) {
841  newAcc.insert(newQ);
842  }
843  if (pim->initial == stateNames[q]) {
844  newInitial = newQ;
845  }
846  }
847  pim->initial = newInitial;
848  pim->transitions = move(newTr);
849  pim->acceptingStates = move(newAcc);
850  }
851  return *this;
852 }
853 
855 
860  if (pim->initial == nullptr) {
861  pim->initial = &(pim->transitions.emplace("", 0).first->first);
862  }
863  vector<char32_t> alphabetV(pim->alphabet.begin(), pim->alphabet.end());
864  if (!pim->alphabet.count(U'\0')) {
865  alphabetV.emplace_back(U'\0');
866  }
867  std::sort(alphabetV.begin(), alphabetV.end());
868  vector<string> labelV;
869  labelV.reserve(pim->transitions.size());
870  labelV.emplace_back(*pim->initial);
871  valarray<bool> acceptingV(pim->transitions.size());
872  acceptingV[0] = pim->acceptingStates.count(pim->initial);
873  for (auto const& entry : pim->transitions) {
874  if (&(entry.first) == pim->initial) {
875  continue;
876  }
877  acceptingV[labelV.size()] = pim->acceptingStates.count(&(entry.first));
878  labelV.emplace_back(entry.first);
879  }
880  vector<vector<valarray<bool>>> transitionV(
881  labelV.size(),
882  vector<valarray<bool>>(alphabetV.size(), valarray<bool>(labelV.size())));
883  for (size_t qi(0); qi < labelV.size(); qi++) {
884  auto const& fromQ = pim->transitions[labelV[qi]];
885  for (size_t si(0); si < alphabetV.size(); si++) {
886  auto viaIt = fromQ.find(alphabetV[si]);
887  if (viaIt == fromQ.end()) {
888  continue;
889  }
890  unordered_set<string const*> const& viaSymbol = viaIt->second;
891  for (size_t pi(0); pi < labelV.size(); pi++) {
892  transitionV[qi][si][pi] =
893  viaSymbol.count(pim->findStatePointer(labelV[pi]));
894  }
895  }
896  }
897  return {move(alphabetV), move(transitionV), move(labelV), move(acceptingV)};
898 }
899 
902 
921  if (pim->isDeterministic()) {
922  complete();
923  } else {
924  purge();
925  if (pim->isDeterministic()) {
926  complete();
927  } else if (force) {
928  powerset();
929  } else {
930  throw nondeterminism_exception();
931  }
932  }
933  if (pim->initial == nullptr) {
934  pim->initial = &(pim->transitions.emplace("", 0).first->first);
935  }
936  vector<char32_t> alphabetV(pim->alphabet.begin(), pim->alphabet.end());
937  std::sort(alphabetV.begin(), alphabetV.end());
938  vector<string> labelV;
939  labelV.reserve(pim->transitions.size());
940  labelV.emplace_back(*pim->initial);
941  valarray<bool> acceptingV(pim->transitions.size());
942  acceptingV[0] = pim->acceptingStates.count(pim->initial);
943  for (auto const& entry : pim->transitions) {
944  if (&(entry.first) == pim->initial) {
945  continue;
946  }
947  acceptingV[labelV.size()] = pim->acceptingStates.count(&(entry.first));
948  labelV.emplace_back(entry.first);
949  }
950  vector<vector<size_t>> transitionV(labelV.size(),
951  vector<size_t>(alphabetV.size()));
952  for (size_t qi(0); qi < labelV.size(); qi++) {
953  auto const& fromQ = pim->transitions[labelV[qi]];
954  for (size_t si(0); si < alphabetV.size(); si++) {
955  auto viaIt = fromQ.find(alphabetV[si]);
956  if (viaIt == fromQ.end() || viaIt->second.empty()) {
957  continue;
958  }
959  unordered_set<string const*> const& viaSymbol = viaIt->second;
960  transitionV[qi][si] = index_of(labelV, **viaSymbol.begin());
961  }
962  }
963  return {move(alphabetV), move(transitionV), move(labelV), move(acceptingV)};
964 }
965 
966 } // namespace reg
std::string const & getInitialState() const
Names this DFA's initial state.
Definition: dfa.cpp:391
impl(impl const &other)
Copies a private implementation object by copying all non-pointer data verbatim and reconstructing po...
Definition: fabuilder.cpp:117
fabuilder & operator=(fabuilder const &b)
Copy-assigns a builder by copying another one's private implementation object.
Definition: fabuilder.cpp:213
fabuilder & addSymbol(std::string const &symbol)
Adds a symbol to the prospective FA's alphabet.
Definition: fabuilder.cpp:266
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this DFA.
Definition: dfa.cpp:420
unordered_set< char32_t > alphabet
Set of symbols processable by the prospective FA.
Definition: fabuilder.cpp:42
Represents nondeterministic finite automata with ε-moves.
Definition: nfa.h:38
unordered_map< string, unordered_map< char32_t, unordered_set< string const * > > > transitions
Transition function (state × symbol → set of states) of the prospective NFA.
Definition: fabuilder.cpp:45
impl(nfa const &nfa)
Constructs a private implementation object for fabuilder(nfa const&).
Definition: fabuilder.cpp:139
Represents deterministic finite automata.
Definition: dfa.h:41
fabuilder & intersect(nfa const &other)
Makes the prospective FA accept only words accepted also by another FA.
Definition: fabuilder.cpp:683
bool isDeterministic()
Checks for nondeterministic transitions.
Definition: fabuilder.cpp:68
std::vector< char32_t > const & getAlphabet_() const
Fetches this NFA's set of processable symbols.
Definition: nfa.cpp:598
std::string to_string(std::valarray< bool > const &qs) const
Puts a name to a set of indices.
Definition: nfa.cpp:506
fabuilder & addTransition(std::string const &from, std::string const &to, std::string const &symbol="")
Adds a transition to the prospective FA's state transition function.
Definition: fabuilder.cpp:281
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:215
fabuilder & complete()
Totalizes a partial transition function by pointing any undefined transitions towards a trash state...
Definition: fabuilder.cpp:376
Contains utility classes, objects and functions used throughout the library.
impl(dfa const &dfa)
Constructs a private implementation object for fabuilder(dfa const&).
Definition: fabuilder.cpp:164
fabuilder & purge()
Purges the prospective FA of unreachable and non-producing states, possibly completing minimization...
Definition: fabuilder.cpp:500
size_t index_of(C const &container, 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: utils.h:43
fabuilder & minimize(bool force=false)
Convenience method for chaining purge and merge to achieve proper DFA minimization.
Definition: fabuilder.cpp:570
impl()=default
Constructs empty private implementation object.
dfa buildDfa(bool force=false)
Builds a DFA as defined by previous operations, including completion.
Definition: fabuilder.cpp:920
bool isTrashState(string const *q) const
Tests whether all of a state's outgoing transitions point to itself.
Definition: fabuilder.cpp:81
bool isAccepting(size_t qi) const
Tests whether a state is an accept state within this NFA.
Definition: nfa.cpp:613
string const * initial
Points to the initial state within transitions.
Definition: fabuilder.cpp:40
std::vector< std::string > const & getStates() const
Fetches this DFA's set of states.
Definition: dfa.cpp:398
string const * generateNewState()
Generates a uniquely named new state and adds it to the set of states.
Definition: fabuilder.cpp:96
Private implementation details of FA builders.
Definition: fabuilder.cpp:39
std::wstring_convert< std::codecvt_utf8< char32_t >, char32_t > converter
Converts between UTF-8-encoded and UTF-32-encoded strings.
Definition: utils.h:52
fabuilder & addSymbol_(char32_t u32symbol)
Adds a symbol to the prospective FA's alphabet.
Definition: fabuilder.cpp:292
fabuilder & unite(nfa const &other)
Makes the prospective FA also accept every word of another FA&#39;s language.
Definition: fabuilder.cpp:582
fabuilder & normalizeStateNames(std::string const &prefix)
Reduces the prospective FA&#39;s state names to consecutive numbers, prefixed with a given string...
Definition: fabuilder.cpp:807
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.
Definition: nfa.cpp:170
fabuilder & setAccepting(std::string const &state, bool accept)
Sets whether or not a state will be accepting within the prospective FA.
Definition: fabuilder.cpp:238
unordered_set< string const * > acceptingStates
Set of pointers to accept states within transitions.
Definition: fabuilder.cpp:52
Signals that an operation requires full determinism and that no powerset construction was forced...
Definition: fabuilder.h:64
fabuilder()
Constructs a blank builder object.
Definition: fabuilder.cpp:186
Constructs NFAs step by step.
Definition: fabuilder.h:31
fabuilder & powerset()
Converts the builder's prospective NFA into a DFA via powerset construction.
Definition: fabuilder.cpp:329
static std::vector< std::valarray< bool > > indistinguishableStates(std::vector< std::vector< size_t >> const &transitions, std::valarray< bool > const &accepting)
Builds the table of indistinguishable states w.r.t. a transition function.
Definition: dfa.cpp:557
fabuilder & merge(bool force=false)
Merges the prospective DFA's indistinguishable states, allowing for minimization. ...
Definition: fabuilder.cpp:432
Where this library lives.
Definition: dfa.cpp:48
fabuilder & makeInitial(std::string const &state)
Resets the initial state for the prospective FA.
Definition: fabuilder.cpp:256
std::string const & getInitialState() const
Names this NFA's initial state.
Definition: nfa.cpp:567
string const * findStatePointer(string &&state)
Delivers a pointer towards one of transitions' keys.
Definition: fabuilder.cpp:63
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:146
std::valarray< bool > const & epsilonClosure(size_t qi) const
Computes a state's ε-closure.
Definition: nfa.cpp:418
string const * findStatePointer(string const &state)
Delivers a pointer towards one of transitions' keys.
Definition: fabuilder.cpp:57
std::vector< std::string > const & getStates() const
Fetches this NFA's set of states in order of internal representation.
Definition: nfa.cpp:574
std::valarray< bool > deltaHat_(size_t qi, std::u32string const &u32word) const
Computes this NFA's transition function recursively for a string of symbols, starting in a state spec...
Definition: nfa.cpp:250
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.
Definition: fabuilder.cpp:308
nfa buildNfa()
Builds an NFA as defined by previous operations.
Definition: fabuilder.cpp:859
std::vector< char32_t > const & getAlphabet_() const
Fetches this DFA's set of processable symbols.
Definition: dfa.cpp:405
Contains the reg::fabuilder class definition.
fabuilder & complement(bool force=false)
Inverts the prospective DFA&#39;s language with respect to all possible strings over its alphabet...
Definition: fabuilder.cpp:780