cfl_regular.cpp
Go to the documentation of this file.
1 /** @file cfl_regular.cpp
2 
3 Operations on regular languages.
4 See [Cassandras and Lafortune. Introduction to Discrete Event Systems] for an
5 introduction to regular language operations.
6 Operations are always performed on language(s) marked by the passed generator(s),
7 resulting in the language(s) marked by the resulting generator(s).
8 Only if mentioned extra, the same is done for the involved generated (prefix-closed)
9 languages.
10 
11 */
12 
13 /* FAU Discrete Event Systems Library (libfaudes)
14 
15 Copyright (C) 2006 Bernd Opitz
16 Copyright (C) 2008 Sebstian Perk
17 Exclusive copyright is granted to Klaus Schmidt
18 
19 This library is free software; you can redistribute it and/or
20 modify it under the terms of the GNU Lesser General Public
21 License as published by the Free Software Foundation; either
22 version 2.1 of the License, or (at your option) any later version.
23 
24 This library is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 Lesser General Public License for more details.
28 
29 You should have received a copy of the GNU Lesser General Public
30 License along with this library; if not, write to the Free Software
31 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
32 
33 
34 #include "cfl_regular.h"
35 #include "cfl_determin.h"
36 
37 
38 /* turn on debugging for this file */
39 //#undef FD_DF
40 //#define FD_DF(a) FD_WARN(a);
41 
42 namespace faudes {
43 
44 // LanguageUnionNonDet(rGen1, rGen2, rResGen)
45 void LanguageUnionNonDet(const Generator& rGen1, const Generator& rGen2,
46  Generator& rResGen) {
47 
48  FD_DF("LanguageUnionNonDet("<< rGen1.Name()
49  << "," << rGen2.Name() << ")");
50 
51  // are state names enabled?
52  bool stateNamesEnabled=rResGen.StateNamesEnabled();
53 
54  // use pointer pResGen to result rResGen; if rResGen is identical to
55  // one of the parameters, allocate temporary object and copy back later
56  Generator* pResGen = &rResGen;
57  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
58  pResGen= rResGen.New();
59  }
60 
61  // prepare result
62  pResGen->Clear();
63 
64  // union of alphabets
65  pResGen->InjectAlphabet(rGen1.Alphabet()+rGen2.Alphabet());
66 
67  // Maps from states of rGen1 and rGen2 to states of ResGen
68  std::map<Idx,Idx> Gen1StatesMap;
69  std::map<Idx,Idx> Gen2StatesMap;
70 
71  // "union" of states: insert states representing the states of rGen1 and rGen2
72  StateSet::Iterator sit;
73  for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
74  if (stateNamesEnabled) {
75  Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
76  }
77  else {
78  Gen1StatesMap[*sit] = pResGen->InsState();
79  }
80  }
81  for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
82  if (stateNamesEnabled) {
83  Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
84  }
85  else {
86  Gen2StatesMap[*sit] = pResGen->InsState();
87  }
88  }
89 
90  // "union" of transition relations
92  for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit) {
93  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
94  }
95  for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit) {
96  pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
97  }
98 
99  // "union" of init states
100  for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
101  pResGen->SetInitState(Gen1StatesMap[*sit]);
102  }
103  for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit) {
104  pResGen->SetInitState(Gen2StatesMap[*sit]);
105  }
106 
107  // "union" of marked states
108  for (sit = rGen1.MarkedStatesBegin(); sit != rGen1.MarkedStatesEnd(); ++sit) {
109  pResGen->SetMarkedState(Gen1StatesMap[*sit]);
110  }
111  for (sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
112  pResGen->SetMarkedState(Gen2StatesMap[*sit]);
113  }
114 
115  // set name of result
116  pResGen->Name(CollapsString("UnionNonDet("+rGen1.Name()+","+rGen2.Name()+")"));
117 
118  // if necessary, move pResGen to rResGen
119  if(pResGen != &rResGen) {
120  pResGen->Move(rResGen);
121  delete pResGen;
122  }
123 
124 }
125 
126 // LanguageUnion(rGen1, rGen2, rResGen)
127 void LanguageUnion(const Generator& rGen1, const Generator& rGen2,
128  Generator& rResGen) {
129 
130  FD_DF("LanguageUnion("<< rGen1.Name()
131  << "," << rGen2.Name() << ")");
132 
133  // fix name
134  std::string name1 = rGen1.Name();
135  std::string name2 = rGen2.Name();
136 
137  // avoid copy
138  Generator* pTempGen = rResGen.New();
139 
140  // perform nondeterministic language union
141  LanguageUnionNonDet(rGen1, rGen2, *pTempGen);
142 
143  // make deterministic
144  Deterministic(*pTempGen, rResGen);
145 
146  // dispose temp
147  delete pTempGen;
148 
149  // set name of result
150  rResGen.Name(CollapsString("Union("+name1+","+name2+")"));
151 
152 }
153 
154 // LanguageUnion(rGenVec, rResGen)
155 void LanguageUnion(const GeneratorVector& rGenVec, Generator& rResGen) {
156 
157  // ignore empty
158  if(rGenVec.Size()==0) {
159  return;
160  }
161 
162  // copy one
163  if(rGenVec.Size()==1) {
164  rResGen=rGenVec.At(0);
165  return;
166  }
167 
168  // avoid final copy
169  Generator* pTempGen = rResGen.New();
170 
171  // run union on others
172  LanguageUnionNonDet(rGenVec.At(0),rGenVec.At(1),*pTempGen);
173  for(GeneratorVector::Position i=2; i<rGenVec.Size(); i++)
174  LanguageUnionNonDet(rGenVec.At(i),*pTempGen,*pTempGen);
175 
176  // make deterministic
177  Deterministic(*pTempGen, rResGen);
178 
179  // dispose temp
180  delete pTempGen;
181 
182  // set name of result
183  rResGen.Name(CollapsString("Union(...)"));
184 }
185 
186 
187 // LanguageIntersection(rGen1, rGen2, rResGen)
188 void LanguageIntersection(const Generator& rGen1, const Generator& rGen2,
189  Generator& rResGen) {
190  FD_DF("LanguageIntersection("<< rGen1.Name() << "," << rGen2.Name() << ")");
191 
192  // fix name
193  std::string name1 = rGen1.Name();
194  std::string name2 = rGen2.Name();
195 
196  // the product of rGen1 and rGen2 implements the language intersection
197  Product(rGen1, rGen2, rResGen);
198  rResGen.Name(CollapsString("Intersection("+name1+","+name2+")"));
199  FD_DF("LanguageIntersection("<< rGen1.Name() << "," << rGen2.Name() << "): done");
200 
201 }
202 
203 
204 // LanguageIntersection(rGenVec, rResGen)
205 void LanguageIntersection(const GeneratorVector& rGenVec, Generator& rResGen)
206 {
207 
208  // ignore empty
209  if(rGenVec.Size()==0) {
210  return;
211  }
212 
213  // copy one
214  if(rGenVec.Size()==1) {
215  rResGen=rGenVec.At(0);
216  return;
217  }
218 
219  // run product on others
220  LanguageIntersection(rGenVec.At(0),rGenVec.At(1),rResGen);
221  for(GeneratorVector::Position i=2; i<rGenVec.Size(); i++)
222  LanguageIntersection(rGenVec.At(i),rResGen,rResGen);
223 }
224 
225 
226 // EmptyLanguageIntersection(rGen1, rGen2)
227 bool EmptyLanguageIntersection(const Generator& rGen1, const Generator& rGen2) {
228  FD_DF("EmptyLanguageIntersection("<< rGen1.Name()
229  << "," << rGen2.Name() << ")");
230 
231  // not tested for non-det automata
232  bool g1_det = rGen1.IsDeterministic();
233  bool g2_det = rGen2.IsDeterministic();
234  if( (!g1_det) || (!g2_det)) {
235  std::stringstream errstr;
236  errstr << "EmptyLanguageIntersection has not been tested for nondeterministic generators";
237  throw Exception("EmptyLanguageIntersection", errstr.str(), 201);
238  }
239 
240  // Perform product and break when a marking is reached simultaneously)
241 
242  // todo stack
243  std::stack< std::pair<Idx,Idx> > todo;
244  std::set< std::pair<Idx,Idx> > done;
245  // iterate variables
246  std::pair<Idx,Idx> currentstates, newstates;
247  StateSet::Iterator lit1, lit2;
248  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
249  // convenience
250  const StateSet& mark1 = rGen1.MarkedStates();
251  const StateSet& mark2 = rGen2.MarkedStates();
252  // restrict search to coaccessible states
253  StateSet coac1 = rGen1.CoaccessibleSet();
254  StateSet coac2 = rGen2.CoaccessibleSet();
255 
256  // push all combinations of coaccessible initial states on todo stack
257  FD_DF("EmptyLanguageIntersection: push all combinations of initial states to todo:");
258  StateSet init1 = coac1 * rGen1.InitStates();
259  StateSet init2 = coac2 * rGen2.InitStates();
260  for (lit1 = init1.Begin(); lit1 != init1.End(); ++lit1) {
261  for (lit2 = init2.Begin(); lit2 != init2.End(); ++lit2) {
262  currentstates = std::make_pair(*lit1, *lit2);
263  todo.push(currentstates);
264  }
265  }
266 
267  // process todo stack
268  bool empty = true;
269  FD_DF("EmptyLanguageIntersection: processing reachable states:");
270  while (!todo.empty()) {
271  // allow for user interrupt
272  // LoopCallback();
273  // allow for user interrupt, incl progress report
274  FD_WPC(done.size(),done.size()+todo.size(),"Product(): processing");
275  // get next reachable state from todo stack
276  currentstates = todo.top();
277  todo.pop();
278  done.insert(currentstates);
279  //FD_DF("EmptyLanguageIntersection: processing " << currentstates.first << "|" << currentstates.second);
280  // test for sync acceptance (do this here to include initial states)
281  if(mark1.Exists(currentstates.first) && mark2.Exists(currentstates.second)) {
282  empty=false;
283  break;
284  }
285  // iterate over all rGen1/rGen2 transitions
286  tit1 = rGen1.TransRelBegin(currentstates.first);
287  tit1_end = rGen1.TransRelEnd(currentstates.first);
288  tit2 = rGen2.TransRelBegin(currentstates.second);
289  tit2_end = rGen2.TransRelEnd(currentstates.second);
290  while((tit1 != tit1_end) && (tit2 != tit2_end)) {
291  // shared event
292  if(tit1->Ev == tit2->Ev) {
293  // push new state
294  newstates = std::make_pair(tit1->X2, tit2->X2);
295  if(done.find(newstates)==done.end())
296  if(coac1.Exists(newstates.first))
297  if(coac2.Exists(newstates.second))
298  todo.push(newstates);
299  // increment transition
300  ++tit1;
301  ++tit2;
302  }
303  // try resync tit1
304  else if (tit1->Ev < tit2->Ev) {
305  ++tit1;
306  }
307  // try resync tit2
308  else if (tit1->Ev > tit2->Ev) {
309  ++tit2;
310  }
311  }
312  }
313 
314 #ifdef FAUDES_CODE
315  // Alternative test for validation
316  Generator ProductGen;
317  ProductGen.StateNamesEnabled(false);
318  Product(rGen1, rGen2, ProductGen);
319  bool altempty = IsEmptyLanguage(ProductGen);
320  if(empty != altempty) {
321  rGen1.Write();
322  rGen2.Write();
323  FD_ERR("EmptyLanguageIntersection(): ERROR -- ref result: " << altempty);
324  }
325 #endif
326 
327  // done
328  return empty;
329 }
330 
331 // LanguageDisjoint(rGen1, rGen2)
332 bool LanguageDisjoint(const Generator& rGen1, const Generator& rGen2) {
333  FD_DF("LanguageDisjoint("<< rGen1.Name()
334  << "," << rGen2.Name() << ")");
335  return EmptyLanguageIntersection(rGen1,rGen2);
336 }
337 
338 // Automaton(rGen)
339 void Automaton(Generator& rGen, const EventSet& rAlphabet) {
340  FD_DF("Automaton("<< rGen.Name() << "," << rAlphabet.Name() << ")");
341 
342  TransSet::Iterator tit;
343  EventSet::Iterator eit;
344  StateSet::Iterator sit;
345 
346  // for correct result, rGen has to be deterministic!
347 #ifdef FAUDES_CHECKED
348  if ( !(rGen.IsDeterministic()) ) {
349  FD_WARN("Automaton(): nondeterministic parameter " << rGen.Name() <<".");
350  }
351 #endif
352 
353  // prepare result
354  rGen.Name(CollapsString("Automaton(" + rGen.Name() + "," + rAlphabet.Name() + ")"));
355 
356  // extend rGen.Alphabet() by rAlphabet
357  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
358 
359  // trim (this used to be coaccessible only until 2024)
360  rGen.Trim();
361 
362  // introduce a dump state (unmarked)
363  Idx dump;
364  if (rGen.StateNamesEnabled()) {
365  std::string dumpstr=rGen.UniqueStateName("dump");
366  dump = rGen.InsState(dumpstr);
367  } else {
368  dump = rGen.InsState();
369  }
370  for(eit=rGen.AlphabetBegin();eit!=rGen.AlphabetEnd();++eit)
371  rGen.SetTransition(dump,*eit,dump);
372  bool dumpReached=false; // record, whether dump state is indeed used
373 
374  // if there is no initial state, the dump state becomes the initial state
375  if(rGen.InitStates().Empty()){
376  rGen.SetInitState(dump);
377  dumpReached=true;
378  }
379 
380  // introduce transitions to dumpstate (reference implementation)
381  /*
382  for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
383  for (eit = rGen.Alphabet().Begin(); eit != rGen.Alphabet().End(); ++eit) {
384  // If no transition is defined for this state and event, insert respective
385  // transition to dump state (note that dump state itself is also treated here
386  // and thus provided with selfloops)
387  if (rGen.TransRelBegin(*sit, *eit) == rGen.TransRelEnd(*sit, *eit)) {
388  rGen.SetTransition(*sit, *eit, dump);
389  // indicate that dumstate was reached
390  if(*sit!=dump) dumpReached=true;
391  }
392  }
393  }
394  */
395 
396 
397  // we can do faster ... but is this worth it?
398  Idx cs=0, ce=0;
399  tit=rGen.TransRelBegin();
400  sit=rGen.StatesBegin();
401  for(;sit!=rGen.StatesEnd();++sit) {
402  FD_DF("Automaton: processing state " << *sit);
403  cs=*sit;
404  for(;tit!=rGen.TransRelEnd();++tit)
405  if(tit->X1 >= cs) break;
406  bool fina= (tit!=rGen.TransRelEnd());
407  bool finb= false;
408  if(fina) finb = (tit->X1 == cs);
409  if(!finb) {
410  FD_DF("Automaton: completing state");
411  for(eit=rGen.AlphabetBegin();eit!=rGen.AlphabetEnd();++eit)
412  rGen.SetTransition(cs,*eit,dump);
413  dumpReached=true;
414  continue;
415  }
416  eit=rGen.AlphabetBegin();
417  while(tit!=rGen.TransRelEnd()) {
418  ce=*eit;
419  FD_DF("Automaton: processing " << tit->Str() << " awaiting " << ce);
420  while(ce<tit->Ev) {
421  FD_DF("Automaton: add " << cs << "-(" << ce << ")->");
422  rGen.SetTransition(cs,ce,dump);
423  dumpReached=true;
424  ++eit;
425  ce=*eit;
426  }
427  bool fin1=false;
428  while(tit!=rGen.TransRelEnd()) {
429  ++tit;
430  if(tit->X1!=cs) {fin1=true; break;}
431  if(tit->Ev!=ce) break;
432  FD_DF("Automaton: skip " << tit->Str());
433  }
434  bool fin2= (tit==rGen.TransRelEnd());
435  ++eit;
436  if(fin1 || fin2) {
437  while(eit != rGen.AlphabetEnd()) {
438  FD_DF("Automaton: fin " << cs << "-(" << *eit << ")->");
439  rGen.SetTransition(cs,*eit,dump);
440  dumpReached=true;
441  ++eit;
442  }
443  }
444  if(fin1||fin2) break;
445  }
446  }
447 
448  // if no transition was introduced (except for selfloops), remove dump state
449  if(!dumpReached)
450  rGen.DelState(dump);
451 }
452 
453 // Automaton(rGen)
454 void Automaton(Generator& rGen) {
455  FD_DF("Automaton("<< rGen.Name() << ")");
456  std::string name=rGen.Name();
457  Automaton(rGen,rGen.Alphabet());
458  rGen.Name(CollapsString("Automaton(" + name + ")"));
459 }
460 
461 // LanguageComplement(rGen,rAlphabet)
462 void LanguageComplement(Generator& rGen, const EventSet& rAlphabet) {
463  FD_DF("LanguageComplement("<< rGen.Name() << "," << rAlphabet.Name() << ")");
464 
465  // fix name
466  std::string name = rGen.Name();
467 
468  // convert to automaton (avoiding statename "dump")
469  bool stateNamesEnabled=rGen.StateNamesEnabled();
470  rGen.StateNamesEnabled(false);
471  Automaton(rGen,rAlphabet);
472  rGen.StateNamesEnabled(stateNamesEnabled);
473 
474  // invert marking
475  rGen.InjectMarkedStates(rGen.States() - rGen.MarkedStates());
476 
477  // set name
478  rGen.Name(CollapsString("Complement(" + name + "," + rAlphabet.Name() + ")"));
479 }
480 
481 // LanguageComplement(rGen)
483  FD_DF("LanguageComplement("<< rGen.Name() << ")");
484  std::string name=rGen.Name();
485  LanguageComplement(rGen,rGen.Alphabet());
486  rGen.Name(CollapsString("Complement(" + name + ")"));
487  return;
488 }
489 
490 // language complement, uniform api
491 void LanguageComplement(const Generator& rGen, Generator& rRes) {
492  rRes=rGen;
493  LanguageComplement(rRes);
494 }
495 
496 
497 // language complement, uniform api
498 void LanguageComplement(const Generator& rGen, const EventSet& rSigma, Generator& rRes) {
499  rRes=rGen;
500  LanguageComplement(rRes,rSigma);
501 }
502 
503 
504 
505 
506 //LanguageDifference(rGen1, rGen2, rResGen)
508  const Generator& rGen1,
509  const Generator& rGen2,
510  Generator& rResGen) {
511 
512  FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << ")");
513 
514  // incl. all-empty case
515  if(IsEmptyLanguage(rGen2)) {
516  rResGen.Assign(rGen1);
517  rResGen.Name(CollapsString("LanguageDifference(" + rGen1.Name() + "," + rGen2.Name() + ")"));
518  return;
519  }
520 
521  // use pointer pResGen to result rResGen
522  Generator* pResGen = &rResGen;
523  if(&rResGen == &rGen1 || &rResGen== &rGen2) {
524  pResGen = rResGen.New();
525  }
526 
527  // due to the use of LanguageComplement(), rGen2 has to be deterministic
528  #ifdef FAUDES_CHECKED
529  if(!(rGen2.IsDeterministic())){
530  std::stringstream errstr;
531  errstr << "Nondeterministic parameter " << rGen2.Name() << ".";
532  throw Exception("LanguageDifference()", errstr.str(), 101);
533  }
534  #endif
535 
536  // prepare result
537  pResGen->Clear();
538 
539  // calculate "Lm1-Lm2" by building the intersection of Lm1 with the complement of Lm2
540  // for correct result, complement has to be computed wrt the alphabet of Lm1 (!)
541 
542  *pResGen=rGen2;
543  LanguageComplement(*pResGen,rGen1.Alphabet());
544  LanguageIntersection(rGen1, *pResGen, *pResGen);
545 
546  FD_DF("LanguageDifference(...): stage 2");
547 
548  // if necessary, move pResGen to rResGen
549  if(pResGen != &rResGen) {
550  pResGen->Move(rResGen);
551  delete pResGen;
552  }
553 
554  FD_DF("LanguageDifference(...): done");
555  return;
556 }
557 
558 // LanguageConcatenateNonDet(rGen1, rGen2, rResGen)
559 void LanguageConcatenateNonDet(const Generator& rGen1, const Generator& rGen2,
560  Generator& rResGen) {
561  FD_DF("LanguageConcatenateNonDet(" << rGen1.Name() << "," << rGen2.Name() << ")");
562 
563  // are state names enabled in result?
564  bool stateNamesEnabled=rResGen.StateNamesEnabled();
565 
566  // use pointer pResGen to result rResGen
567  Generator* pResGen = &rResGen;
568  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
569  pResGen= rResGen.New();
570  }
571 
572  // prepare result
573  pResGen->Clear();
574 
575  // union of alphabets
576  pResGen->InjectAlphabet(rGen1.Alphabet() + rGen2.Alphabet());
577 
578  // Maps from states of rGen1 and rGen2 to states of ResGen
579  std::map<Idx,Idx> Gen1StatesMap;
580  std::map<Idx,Idx> Gen2StatesMap;
581 
582  // helpers
583  StateSet::Iterator sit;
584  TransSet::Iterator tit;
585 
586  // "union" of states: insert states representing the states of rGen1 and rGen2
587  for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
588  if (stateNamesEnabled) {
589  Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
590  } else {
591  Gen1StatesMap[*sit] = pResGen->InsState();
592  }
593  }
594  for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
595  if (stateNamesEnabled) {
596  Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
597  } else {
598  Gen2StatesMap[*sit] = pResGen->InsState();
599  }
600  }
601 
602  // "union" transitions: insert all rGen1 transitions
603  for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
604  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
605 
606  // "union" transitions: insert all rGen2 transitions
607  for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit)
608  pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
609 
610 
611  // initial state bug (detected by Tomas Masopust, fix by Klaus Schmidt)
612  // 1) copy all transitions to the result, clear initial/marked status
613  // 2) all initial states of G1 become initial states in the result
614  // 3) if L1 contains the empty string, also all initial states of G2 become initial states
615  // in the result
616  // 4) transition leading to a marked state in G1 also become transitions to all
617  // initial states of G2
618  // 5) marked states of G2 become marked in the result
619 
620 
621  // test whether L1 includes the empty string
622  bool concatenateEpsilon1=false;
623  for(sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
624  if(rGen1.ExistsMarkedState(*sit)) {
625  concatenateEpsilon1=true;
626  break;
627  }
628  }
629 
630  // initial states of G1 become initial states in the result
631  for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit)
632  pResGen->SetInitState(Gen1StatesMap[*sit]);
633 
634  // if L1 contains the emtystring, G2 initial states become initial states in the result
635  if(concatenateEpsilon1)
636  for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
637  pResGen->SetInitState(Gen2StatesMap[*sit]);
638 
639  // any G1 transition to a marked state must also lead to all initial states of G2
640  for(tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
641  if(rGen1.ExistsMarkedState(tit->X2))
642  for(sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
643  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen2StatesMap[*sit]);
644 
645  // set pResGen marked states corresponding to rGen2 marked states using Gen2StatesMap
646  for(sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
647  pResGen->SetMarkedState(Gen2StatesMap[*sit]);
648  }
649 
650  // remove blocking states as they provide no useful meaning.
651  pResGen->Trim();
652  pResGen->Name("ConcatenateNonDet("+rGen1.Name()+","+rGen2.Name()+")");
653 
654  // if necessary, move pResGen to rResGen
655  if(pResGen != &rResGen) {
656  pResGen->Move(rResGen);
657  delete pResGen;
658  }
659 
660 }
661 
662 // LanguageConcatenate(rGen1, rGen2, rResGen)
663 void LanguageConcatenate(const Generator& rGen1, const Generator& rGen2,
664  Generator& rResGen) {
665 
666  FD_DF("LanguageConcatenate("<< rGen1.Name()
667  << "," << rGen2.Name() << ")");
668 
669  // perform nondeterministic language concatenation
670  LanguageConcatenateNonDet(rGen1, rGen2, rResGen);
671 
672  // make deterministic if necessary
673  if(!(rResGen.IsDeterministic())){
674  Deterministic(rResGen, rResGen);
675  }
676 
677  // set name of result
678  rResGen.Name("Concatenate("+rGen1.Name()+","+rGen2.Name()+")");
679 
680  return;
681 }
682 
683 // FullLanguage(rAlphabet, rResGen)
684 void FullLanguage(const EventSet& rAlphabet, Generator& rResGen) {
685  FD_DF("FullLanguage("<< rAlphabet.Name()
686  << "," << rResGen.Name() << ")");
687 
688  // prepare result
689  rResGen.Clear();
690 
691  // helpers
692  Idx state;
693  EventSet::Iterator evit;
694 
695  // alphabet
696  rResGen.InjectAlphabet(rAlphabet);
697 
698  // insert marked initial state
699  if(rResGen.StateNamesEnabled()){
700  state = rResGen.InsInitState("1");
701  } else{
702  state = rResGen.InsInitState();
703  }
704  rResGen.SetMarkedState(state);
705 
706  // create selfloop for each event
707  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
708  rResGen.SetTransition(state, *evit, state);
709  }
710 
711  // set name of result
712  rResGen.Name("FullLanguage("+rAlphabet.Name()+")");
713 
714  return;
715 }
716 
717 // AlphabetLanguage(rAlphabet, rResGen)
718 void AlphabetLanguage(const EventSet& rAlphabet, Generator& rResGen) {
719  FD_DF("AlphabetLanguage("<< rAlphabet.Name()
720  << "," << rResGen.Name() << ")");
721 
722  // prepare result
723  rResGen.Clear();
724 
725  // set name of result
726  rResGen.Name("AlphabetLanguage("+rAlphabet.Name()+")");
727 
728  // if alphabet is empty, leave generator empty
729  if(rAlphabet.Empty()){
730  FD_WARN("AlphabetLanguage: empty alphabet.");
731  return;
732  }
733 
734  // helpers
735  Idx istate, mstate;
736  EventSet::Iterator evit;
737 
738  // alphabet
739  rResGen.InjectAlphabet(rAlphabet);
740 
741  // insert one initial state and one marked state
742  if(rResGen.StateNamesEnabled()){
743  istate = rResGen.InsInitState("1");
744  mstate = rResGen.InsMarkedState("2");
745  }
746  else{
747  istate = rResGen.InsInitState();
748  mstate = rResGen.InsMarkedState();
749  }
750 
751  // for each event from rAlphabet, inserted transition leading from init state to marked state
752  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
753  rResGen.SetTransition(istate, *evit, mstate);
754  }
755 
756  return;
757 }
758 
759 // EmptyStringLanguage(rAlphabet, rResGen)
760 void EmptyStringLanguage(const EventSet& rAlphabet, Generator& rResGen) {
761  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
762  << "," << rResGen.Name() << ")");
763 
764  // prepare result
765  rResGen.Clear();
766 
767  // helpers
768  Idx state;
769 
770  // alphabet
771  rResGen.InjectAlphabet(rAlphabet);
772 
773  // insert marked initial state
774  if(rResGen.StateNamesEnabled()){
775  state = rResGen.InsInitState("1");
776  }
777  else{
778  state = rResGen.InsInitState();
779  }
780  rResGen.SetMarkedState(state);
781 
782  // set name of result
783  rResGen.Name("EmptyStringLanguage("+rAlphabet.Name()+")");
784 
785  return;
786 }
787 
788 // EmptyLanguage(rAlphabet, rResGen)
789 void EmptyLanguage(const EventSet& rAlphabet, Generator& rResGen) {
790  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
791  << "," << rResGen.Name() << ")");
792 
793  // prepare result
794  rResGen.Clear();
795 
796  // set alphabet
797  rResGen.InjectAlphabet(rAlphabet);
798 
799  // set name of result
800  rResGen.Name("EmptyLanguage("+rAlphabet.Name()+")");
801 
802  return;
803 }
804 
805 // EmptyLanguage(rGen)
806 bool IsEmptyLanguage(const Generator& rGen) {
807  // case a) check if set of marked or initial states is empty
808  if(rGen.MarkedStatesSize()==0) return true;
809  if(rGen.InitStatesSize()==0) return true;
810  // case b) check if no marked state is accessible (reachable)
811  return (rGen.AccessibleSet()*rGen.MarkedStates()).Empty();
812 }
813 
814 // LanguageInclusion(rGen1, rGen2)
815 bool LanguageInclusion(const Generator& rGen1, const Generator& rGen2) {
816 
817  FD_DF("LanguageInclusion("<< rGen1.Name() << "," << rGen2.Name() << ")");
818 
819  // check if there is no string in Lm1 that is not in Lm2, which means Lm1<=Lm2
820  Generator NotrGen2=rGen2;
821  NotrGen2.StateNamesEnabled(false);
822  // note: complement w.r.t. union of alphabets to ensure that elementwise
823  // inclusion of Lm1 in Lm2 is tested
824  LanguageComplement(NotrGen2 , rGen1.Alphabet()+rGen2.Alphabet());
825  return EmptyLanguageIntersection(rGen1,NotrGen2);
826 }
827 
828 // LanguageEquality(rGen1, rGen2)
829 bool LanguageEquality(const Generator& rGen1, const Generator& rGen2) {
830 
831  FD_DF("LanguageEquality("<< rGen1.Name() << "," << rGen2.Name() << ")");
832 
833  // Check for equality by testing mutual inclusion
834  return LanguageInclusion(rGen1,rGen2) && LanguageInclusion(rGen2,rGen1);
835 }
836 
837 // KleeneClosure(rGen)
839 
840  FD_DF("KleeneClosure("<< rGen.Name() << ")");
841 
842  // fix name
843  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
844 
845  // The Kleene Closure of the empty set is the empty set
846  if(IsEmptyLanguage(rGen)){
847  rGen.Clear();
848  rGen.Name(name);
849  return;
850  }
851 
852  // run nondet version
853  KleeneClosureNonDet(rGen);
854  Deterministic(rGen, rGen);
855 
856  // set name
857  rGen.Name(name);
858 }
859 
860 // KleeneClosure(rGen, rResGen)
861 void KleeneClosure(const Generator& rGen, Generator& rResGen) {
862 
863  FD_DF("KleeneClosure("<< rGen.Name() << ", ... )");
864 
865  // if arg and result match, call respective version
866  if(&rGen==&rResGen) {
867  KleeneClosure(rResGen);
868  return;
869  }
870 
871  // fix name
872  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
873 
874  // The Kleene Closure of the empty set is the empty set
875  if(IsEmptyLanguage(rGen)){
876  rResGen.Clear();
877  rResGen.Name(name);
878  return;
879  }
880 
881  // run nondet version with intermediate result
882  Generator* pgen=rGen.Copy();
883  KleeneClosureNonDet(*pgen);
884  Deterministic(*pgen, rResGen);
885  delete pgen;
886 
887  // set name
888  rResGen.Name(name);
889 }
890 
891 // KleeneClosureNonDet(rGen)
893 
894  FD_DF("KleeneClosureNonDet("<< rGen.Name() << ")");
895 
896  // set name
897  rGen.Name(CollapsString("KleeneClosureNonDet("+ rGen.Name() + ")"));
898 
899  // make accessible (relevant)
900  rGen.Accessible();
901 
902  // test for empty language
903  if(rGen.MarkedStatesSize()==0) {
904  rGen.Clear();
905  return;
906  }
907 
908  // helpers
909  TransSet::Iterator tit;
910  TransSet TransToInsert;
911 
912  // initial state bug (detected by Tomas Masopust, fixes proposed by Klaus Schmidt and Florian Frohn)
913  // 1. prepare the generator to have a unique initial state
914  // 2. if the initial state fails to be marked, introduce an alternative marked initial state.
915  // 3. equip the markded initial state with the same transitions as the original initial state
916  UniqueInit(rGen);
917  Idx istate = *rGen.InitStatesBegin();
918  Idx imstate = istate;
919  if(!rGen.ExistsMarkedState(imstate)) {
920  imstate=rGen.InsInitState();
921  rGen.SetMarkedState(imstate);
922  for(tit = rGen.TransRelBegin(istate); tit != rGen.TransRelEnd(istate); ++tit) {
923  TransToInsert.Insert(imstate, tit->Ev, tit->X2);
924  }
925  for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
926  rGen.SetTransition(*tit);
927  }
928  TransToInsert.Clear();
929  rGen.ClrInitState(istate);
930  }
931  rGen.Accessible(); // cosmetic
932 
933 
934  // for all transitions leading from a state x1 to a marked state: insert a transition
935  // with the same event that leads to the unique marked initial state.
936  for(tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
937  if(rGen.ExistsMarkedState(tit->X2)) {
938  if(!(rGen.ExistsTransition(tit->X1, tit->Ev, imstate)) ){
939  TransToInsert.Insert(tit->X1, tit->Ev, imstate);
940  }
941  }
942  }
943  for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
944  rGen.SetTransition(*tit);
945  }
946 
947 }
948 
949 // PrefixClosure(rGen)
951 
952  FD_DF("PrefixClosure("<< rGen.Name() << ")");
953 
954  // fix name
955  std::string name=CollapsString("PrefixClosure("+ rGen.Name() + ")");
956 
957  // remove all states that do net represent prefixes of marked strings
958  rGen.Coaccessible();
959 
960  // mark all remaining states
961  rGen.InjectMarkedStates(rGen.States());
962 
963  // set name
964  rGen.Name(name);
965 
966 }
967 
968 // IsPrefixClosed
969 bool IsPrefixClosed(const Generator& rGen) {
970 
971  // figure relevant states
972  StateSet relevant = rGen.AccessibleSet() * rGen.CoaccessibleSet();
973 
974  // test
975  return relevant <= rGen.MarkedStates();
976 
977 }
978 
979 // IsNonblocking
980 bool IsNonblocking(const Generator& rGen) {
981 
982  // test
983  return rGen.AccessibleSet() <= rGen.CoaccessibleSet();
984 
985 }
986 
987 // IsNonblocking
988 bool IsNonblocking(const Generator& rGen1, const Generator& rGen2) {
989 
990  // build composition
991  Generator parallel;
992  parallel.StateNamesEnabled(false);
993  Parallel(rGen1,rGen2,parallel);
994 
995  // test (parallel returns an accessible generator).
996  return parallel.States() <= parallel.CoaccessibleSet();
997 
998 }
999 
1000 
1001 
1002 // SelfLoop(rGen,rAlphabet)
1003 void SelfLoop(Generator& rGen,const EventSet& rAlphabet) {
1004 
1005  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << ")");
1006 
1007  // fix name
1008  std::string name = CollapsString("SelfLoop(" + rGen.Name() + "," + rAlphabet.Name() + ")");
1009  // extend alphabet of rGen
1010  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1011 
1012  //helpers
1013  EventSet::Iterator evit,evbegin,evend;
1014  evbegin = rAlphabet.Begin();
1015  evend = rAlphabet.End();
1016  StateSet::Iterator sit;
1017 
1018  // iterate over all states and insert selfloop for each event of rAlphabet
1019  for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
1020  for(evit = evbegin; evit != evend; ++evit){
1021  rGen.SetTransition(*sit, *evit, *sit);
1022  }
1023  }
1024 
1025  // set name
1026  rGen.Name(name);
1027 }
1028 
1029 // SelfLoopMarkedStates(rGen,rAlphabet)
1030 void SelfLoopMarkedStates(Generator& rGen,const EventSet& rAlphabet) {
1031 
1032  FD_DF("SelfLoopMarkedStates(" << rGen.Name() << "," << rAlphabet.Name() << ")");
1033 
1034  // fix name
1035  std::string name = CollapsString("SelfLoopMarkedStates(" + rGen.Name()
1036  + "," + rAlphabet.Name() + ")");
1037 
1038  // extend alphabet of rGen
1039  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1040 
1041  //helpers
1042  EventSet::Iterator evit,evbegin,evend;
1043  evbegin = rAlphabet.Begin();
1044  evend = rAlphabet.End();
1045  StateSet::Iterator sit;
1046 
1047  // iterate over all marked states and insert selfloop for each event of rAlphabet
1048  for (sit = rGen.MarkedStatesBegin(); sit != rGen.MarkedStatesEnd(); ++sit) {
1049  for(evit = evbegin; evit != evend; ++evit){
1050  rGen.SetTransition(*sit, *evit, *sit);
1051  }
1052  }
1053 
1054  // set name
1055  rGen.Name(name);
1056 }
1057 
1058 // SelfLoop(rGen,rAlphabet,rStates)
1059 void SelfLoop(Generator& rGen,const EventSet& rAlphabet,const StateSet& rStates) {
1060 
1061  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << "," << rStates.Name() << ")");
1062 
1063  // fix name
1064  std::string name = CollapsString("SelfLoop(" + rGen.Name()
1065  + "," + rAlphabet.Name() + "," + rStates.Name() + ")");
1066 
1067  // exception: rStates must be states of rGen
1068 #ifdef FAUDES_CHECKED
1069  if( !(rStates <= rGen.States()) ){
1070  std::stringstream errstr;
1071  errstr << "State set " << rStates.Name() <<
1072  " has to be included in state set of "<< rGen.Name() << ".";
1073  throw Exception("SelfLoop()", errstr.str(), 100);
1074  }
1075 #endif
1076 
1077  // extend alphabet of rGen
1078  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1079 
1080  //helpers
1081  EventSet::Iterator evit,evbegin,evend;
1082  evbegin = rAlphabet.Begin();
1083  evend = rAlphabet.End();
1084  StateSet::Iterator sit;
1085 
1086  // iterate over all marked states and insert selfloop for each event of rAlphabet
1087  for (sit = rStates.Begin(); sit != rStates.End(); ++sit) {
1088  for(evit = evbegin; evit != evend; ++evit){
1089  rGen.SetTransition(*sit, *evit, *sit);
1090  }
1091  }
1092 
1093  // set name
1094  rGen.Name(name);
1095 }
1096 
1097 
1098 } // namespace faudes
1099 
1100 #undef Product //see define above for comment
#define FD_WPC(cntnow, contdone, message)
Application callback: optional write progress report to console or application, incl count
#define FD_WARN(message)
Debug: always report warnings.
#define FD_DF(message)
Debug: optional report on user functions.
#define FD_ERR(message)
Debug: report more errors with file/line info.
powersetset construction
Operations on regular languages.
Faudes exception class.
Set of indices.
Definition: cfl_indexset.h:78
Set of indices with symbolic names.
Definition: cfl_nameset.h:69
std::vector< int >::size_type Position
convenience typedef for positions
virtual const T & At(const Position &pos) const
Access element.
Iterator Begin(void) const
Iterator to begin of set.
Iterator End(void) const
Iterator to end of set.
bool Insert(const Transition &rTransition)
Add a Transition.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
void Write(const Type *pContext=0) const
Write configuration data to console.
Definition: cfl_types.cpp:139
Idx Size(void) const
Get size of vector.
Base class of all FAUDES generators.
StateSet::Iterator StatesBegin(void) const
Iterator to Begin() of state set.
StateSet::Iterator InitStatesBegin(void) const
Iterator to Begin() of mInitStates.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
const StateSet & MarkedStates(void) const
Return const ref of marked states.
const EventSet & Alphabet(void) const
Return const reference to alphabet.
Idx InsMarkedState(void)
Create new anonymous state and set as marked state.
virtual void Move(vGenerator &rGen)
Destructive copy to other vGenerator.
virtual vGenerator & Assign(const Type &rSrc)
Copy from other faudes type.
virtual vGenerator * Copy(void) const
Construct copy on heap.
const StateSet & InitStates(void) const
Const ref to initial states.
TransSet::Iterator TransRelBegin(void) const
Iterator to Begin() of transition relation.
bool Accessible(void)
Make generator accessible.
bool Trim(void)
Make generator trim.
Idx InitStatesSize(void) const
Get number of initial states.
EventSet::Iterator AlphabetBegin(void) const
Iterator to Begin() of alphabet.
virtual vGenerator * New(void) const
Construct on heap.
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
Test for transition given by x1, ev, x2.
void InjectMarkedStates(const StateSet &rNewMarkedStates)
Replace mMarkedStates with StateSet given as parameter without consistency checks.
Idx MarkedStatesSize(void) const
Get number of marked states.
void SetInitState(Idx index)
Set an existing state as initial state by index.
StateSet AccessibleSet(void) const
Compute set of accessible states.
StateSet::Iterator MarkedStatesBegin(void) const
Iterator to Begin() of mMarkedStates.
bool Coaccessible(void)
Make generator Coaccessible.
std::string StateName(Idx index) const
State name lookup.
void Name(const std::string &rName)
Set the generator's name.
bool DelState(Idx index)
Delete a state from generator by index.
StateSet::Iterator StatesEnd(void) const
Iterator to End() of state set.
void ClrInitState(Idx index)
Unset an existing state as initial state by index.
TransSet::Iterator TransRelEnd(void) const
Iterator to End() of transition relation.
bool IsDeterministic(void) const
Check if generator is deterministic.
StateSet::Iterator MarkedStatesEnd(void) const
Iterator to End() of mMarkedStates.
Idx InsState(void)
Add new anonymous state to generator.
void SetMarkedState(Idx index)
Set an existing state as marked state by index.
Idx InsInitState(void)
Create new anonymous state and set as initial state.
bool StateNamesEnabled(void) const
Whether libFAUEDS functions are requested to generate state names.
StateSet::Iterator InitStatesEnd(void) const
Iterator to End() of mInitStates.
EventSet::Iterator AlphabetEnd(void) const
Iterator to End() of alphabet.
StateSet CoaccessibleSet(void) const
Compute set of Coaccessible states.
virtual void Clear(void)
Clear generator data.
bool ExistsMarkedState(Idx index) const
Test existence of state in mMarkedStates.
std::string UniqueStateName(const std::string &rName) const
Create a new unique symbolic state name.
const StateSet & States(void) const
Return reference to state set.
void InjectAlphabet(const EventSet &rNewalphabet)
Set mpAlphabet without consistency check.
bool Empty(void) const
Test whether if the TBaseSet is Empty.
Definition: cfl_baseset.h:1824
bool Exists(const T &rElem) const
Test existence of element.
Definition: cfl_baseset.h:2115
virtual void Clear(void)
Clear all set.
Definition: cfl_baseset.h:1902
Iterator End(void) const
Iterator to the end of set.
Definition: cfl_baseset.h:1896
Iterator Begin(void) const
Iterator to the begin of set.
Definition: cfl_baseset.h:1891
const std::string & Name(void) const
Return name of TBaseSet.
Definition: cfl_baseset.h:1755
bool EmptyLanguageIntersection(const Generator &rGen1, const Generator &rGen2)
Test for empty language intersection (same as Disjoind()).
void FullLanguage(const EventSet &rAlphabet, Generator &rResGen)
Full Language, L(G)=Lm(G)=Sigma*.
void LanguageUnion(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language union, deterministic version.
void LanguageConcatenateNonDet(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language concatenation, nondeterministic version.
void SelfLoop(Generator &rGen, const EventSet &rAlphabet)
Self-loop all states.
bool LanguageDisjoint(const Generator &rGen1, const Generator &rGen2)
Test whether two languages are disjoint.
bool LanguageInclusion(const Generator &rGen1, const Generator &rGen2)
Test language inclusion, Lm1<=Lm2.
void UniqueInit(Generator &rGen)
Make initial states unique.
void KleeneClosure(Generator &rGen)
Kleene Closure.
void PrefixClosure(Generator &rGen)
Prefix Closure.
void Product(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Product composition.
void Deterministic(const Generator &rGen, Generator &rResGen)
Make generator deterministic.
void LanguageUnionNonDet(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language union, nondeterministic version.
Definition: cfl_regular.cpp:45
void Automaton(Generator &rGen, const EventSet &rAlphabet)
Convert generator to automaton wrt specified alphabet.
void AlphabetLanguage(const EventSet &rAlphabet, Generator &rResGen)
Alphabet Language, L(G)=Lm(G)=Sigma.
void LanguageConcatenate(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language concatenation, deterministic version.
bool IsEmptyLanguage(const Generator &rGen)
Test for Empty language Lm(G)=={}.
bool LanguageEquality(const Generator &rGen1, const Generator &rGen2)
Language equality, Lm1==Lm2.
void LanguageDifference(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language difference (set-theoretic difference).
void LanguageIntersection(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Language intersection.
bool IsPrefixClosed(const Generator &rGen)
Test for prefix closed marked language.
void EmptyLanguage(const EventSet &rAlphabet, Generator &rResGen)
Empty language Lm(G)={}.
void Parallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Parallel composition.
void LanguageComplement(Generator &rGen, const EventSet &rAlphabet)
Language complement wrt specified alphabet.
void EmptyStringLanguage(const EventSet &rAlphabet, Generator &rResGen)
Empty string language, L(G)=Lm(G)={epsilon}.
void KleeneClosureNonDet(Generator &rGen)
Kleene Closure, nondeterministic version.
void SelfLoopMarkedStates(Generator &rGen, const EventSet &rAlphabet)
Self-loop all marked states.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
bool IsNonblocking(const GeneratorVector &rGvec)
std::string CollapsString(const std::string &rString, unsigned int len)
Limit length of string, return head and tail of string.
Definition: cfl_helper.cpp:91

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen