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  // iterrate transrel to find current state cs
405  for(;tit!=rGen.TransRelEnd();++tit)
406  if(tit->X1 >= cs) break;
407  bool found= false;
408  if(tit!=rGen.TransRelEnd())
409  if(tit->X1 == cs) found=true;
410  // current state not found, so all transitions to go to dump
411  if(!found) {
412  FD_DF("Automaton: state not found, all transitions go to dump");
413  for(eit=rGen.AlphabetBegin();eit!=rGen.AlphabetEnd();++eit)
414  rGen.SetTransition(cs,*eit,dump);
415  if(cs!=dump) dumpReached=true;
416  continue;
417  }
418  // current state found, search for enabled events
419  eit=rGen.AlphabetBegin();
420  while(tit!=rGen.TransRelEnd()) {
421  // event to resolve
422  ce=*eit;
423  FD_DF("Automaton: processing " << tit->Str() << " awaiting " << ce);
424  while(eit!=rGen.AlphabetEnd()) {
425  ce=*eit;
426  if(ce==tit->Ev) break;
427  // add missing transition to dump
428  FD_DF("Automaton: add " << cs << "-(" << ce << ")->dump");
429  rGen.SetTransition(cs,ce,dump);
430  if(cs!=dump) dumpReached=true;
431  // look for next event
432  ++eit;
433  }
434  // all events resolved, go for next state
435  if(eit==rGen.AlphabetEnd()) break;
436  // all events up to ce have been resolved
437  // test whether we have more transitions for the current state
438  bool fin=false;
439  while(tit!=rGen.TransRelEnd()) {
440  ++tit;
441  if(tit==rGen.TransRelEnd()) {fin=true; break;}
442  if(tit->X1!=cs) {fin=true; break;}
443  if(tit->Ev!=ce) break;
444  FD_DF("Automaton: skip " << tit->Str());
445  }
446  // there are more transitions to consider, so resolve the next event
447  if(!fin) {
448  ++eit;
449  continue;
450  }
451  // we did ran out transitions, so complete this state
452  ++eit;
453  while(eit != rGen.AlphabetEnd()) {
454  FD_DF("Automaton: fin " << cs << "-(" << *eit << ")->dump");
455  rGen.SetTransition(cs,*eit,dump);
456  if(cs!=dump) dumpReached=true;
457  ++eit;
458  }
459  break;
460  }
461  }
462 
463  // if no transition was introduced (except for selfloops), remove dump state
464  if(!dumpReached)
465  rGen.DelState(dump);
466 }
467 
468 // Automaton(rGen)
469 void Automaton(Generator& rGen) {
470  FD_DF("Automaton("<< rGen.Name() << ")");
471  std::string name=rGen.Name();
472  Automaton(rGen,rGen.Alphabet());
473  rGen.Name(CollapsString("Automaton(" + name + ")"));
474 }
475 
476 // LanguageComplement(rGen,rAlphabet)
477 void LanguageComplement(Generator& rGen, const EventSet& rAlphabet) {
478  FD_DF("LanguageComplement("<< rGen.Name() << "," << rAlphabet.Name() << ")");
479 
480  // fix name
481  std::string name = rGen.Name();
482 
483  // convert to automaton (avoiding statename "dump")
484  bool stateNamesEnabled=rGen.StateNamesEnabled();
485  rGen.StateNamesEnabled(false);
486  Automaton(rGen,rAlphabet);
487  rGen.StateNamesEnabled(stateNamesEnabled);
488 
489  // invert marking
490  rGen.InjectMarkedStates(rGen.States() - rGen.MarkedStates());
491 
492  // set name
493  rGen.Name(CollapsString("Complement(" + name + "," + rAlphabet.Name() + ")"));
494 }
495 
496 // LanguageComplement(rGen)
498  FD_DF("LanguageComplement("<< rGen.Name() << ")");
499  std::string name=rGen.Name();
500  LanguageComplement(rGen,rGen.Alphabet());
501  rGen.Name(CollapsString("Complement(" + name + ")"));
502  return;
503 }
504 
505 // language complement, uniform api
506 void LanguageComplement(const Generator& rGen, Generator& rRes) {
507  rRes=rGen;
508  LanguageComplement(rRes);
509 }
510 
511 
512 // language complement, uniform api
513 void LanguageComplement(const Generator& rGen, const EventSet& rSigma, Generator& rRes) {
514  rRes=rGen;
515  LanguageComplement(rRes,rSigma);
516 }
517 
518 
519 
520 
521 //LanguageDifference(rGen1, rGen2, rResGen)
523  const Generator& rGen1,
524  const Generator& rGen2,
525  Generator& rResGen) {
526 
527  FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << ")");
528 
529  // incl. all-empty case
530  if(IsEmptyLanguage(rGen2)) {
531  rResGen.Assign(rGen1);
532  rResGen.Name(CollapsString("LanguageDifference(" + rGen1.Name() + "," + rGen2.Name() + ")"));
533  return;
534  }
535 
536  // use pointer pResGen to result rResGen
537  Generator* pResGen = &rResGen;
538  if(&rResGen == &rGen1 || &rResGen== &rGen2) {
539  pResGen = rResGen.New();
540  }
541 
542  // due to the use of LanguageComplement(), rGen2 has to be deterministic
543  #ifdef FAUDES_CHECKED
544  if(!(rGen2.IsDeterministic())){
545  std::stringstream errstr;
546  errstr << "Nondeterministic parameter " << rGen2.Name() << ".";
547  throw Exception("LanguageDifference()", errstr.str(), 101);
548  }
549  #endif
550 
551  // prepare result
552  pResGen->Clear();
553 
554  // calculate "Lm1-Lm2" by building the intersection of Lm1 with the complement of Lm2
555  // for correct result, complement has to be computed wrt the alphabet of Lm1 (!)
556 
557  *pResGen=rGen2;
558  LanguageComplement(*pResGen,rGen1.Alphabet());
559  LanguageIntersection(rGen1, *pResGen, *pResGen);
560 
561  FD_DF("LanguageDifference(...): stage 2");
562 
563  // if necessary, move pResGen to rResGen
564  if(pResGen != &rResGen) {
565  pResGen->Move(rResGen);
566  delete pResGen;
567  }
568 
569  FD_DF("LanguageDifference(...): done");
570  return;
571 }
572 
573 // LanguageConcatenateNonDet(rGen1, rGen2, rResGen)
574 void LanguageConcatenateNonDet(const Generator& rGen1, const Generator& rGen2,
575  Generator& rResGen) {
576  FD_DF("LanguageConcatenateNonDet(" << rGen1.Name() << "," << rGen2.Name() << ")");
577 
578  // are state names enabled in result?
579  bool stateNamesEnabled=rResGen.StateNamesEnabled();
580 
581  // use pointer pResGen to result rResGen
582  Generator* pResGen = &rResGen;
583  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
584  pResGen= rResGen.New();
585  }
586 
587  // prepare result
588  pResGen->Clear();
589 
590  // union of alphabets
591  pResGen->InjectAlphabet(rGen1.Alphabet() + rGen2.Alphabet());
592 
593  // Maps from states of rGen1 and rGen2 to states of ResGen
594  std::map<Idx,Idx> Gen1StatesMap;
595  std::map<Idx,Idx> Gen2StatesMap;
596 
597  // helpers
598  StateSet::Iterator sit;
599  TransSet::Iterator tit;
600 
601  // "union" of states: insert states representing the states of rGen1 and rGen2
602  for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
603  if (stateNamesEnabled) {
604  Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
605  } else {
606  Gen1StatesMap[*sit] = pResGen->InsState();
607  }
608  }
609  for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
610  if (stateNamesEnabled) {
611  Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
612  } else {
613  Gen2StatesMap[*sit] = pResGen->InsState();
614  }
615  }
616 
617  // "union" transitions: insert all rGen1 transitions
618  for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
619  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
620 
621  // "union" transitions: insert all rGen2 transitions
622  for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit)
623  pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
624 
625 
626  // initial state bug (detected by Tomas Masopust, fix by Klaus Schmidt)
627  // 1) copy all transitions to the result, clear initial/marked status
628  // 2) all initial states of G1 become initial states in the result
629  // 3) if L1 contains the empty string, also all initial states of G2 become initial states
630  // in the result
631  // 4) transition leading to a marked state in G1 also become transitions to all
632  // initial states of G2
633  // 5) marked states of G2 become marked in the result
634 
635 
636  // test whether L1 includes the empty string
637  bool concatenateEpsilon1=false;
638  for(sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
639  if(rGen1.ExistsMarkedState(*sit)) {
640  concatenateEpsilon1=true;
641  break;
642  }
643  }
644 
645  // initial states of G1 become initial states in the result
646  for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit)
647  pResGen->SetInitState(Gen1StatesMap[*sit]);
648 
649  // if L1 contains the emtystring, G2 initial states become initial states in the result
650  if(concatenateEpsilon1)
651  for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
652  pResGen->SetInitState(Gen2StatesMap[*sit]);
653 
654  // any G1 transition to a marked state must also lead to all initial states of G2
655  for(tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
656  if(rGen1.ExistsMarkedState(tit->X2))
657  for(sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
658  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen2StatesMap[*sit]);
659 
660  // set pResGen marked states corresponding to rGen2 marked states using Gen2StatesMap
661  for(sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
662  pResGen->SetMarkedState(Gen2StatesMap[*sit]);
663  }
664 
665  // remove blocking states as they provide no useful meaning.
666  pResGen->Trim();
667  pResGen->Name("ConcatenateNonDet("+rGen1.Name()+","+rGen2.Name()+")");
668 
669  // if necessary, move pResGen to rResGen
670  if(pResGen != &rResGen) {
671  pResGen->Move(rResGen);
672  delete pResGen;
673  }
674 
675 }
676 
677 // LanguageConcatenate(rGen1, rGen2, rResGen)
678 void LanguageConcatenate(const Generator& rGen1, const Generator& rGen2,
679  Generator& rResGen) {
680 
681  FD_DF("LanguageConcatenate("<< rGen1.Name()
682  << "," << rGen2.Name() << ")");
683 
684  // perform nondeterministic language concatenation
685  LanguageConcatenateNonDet(rGen1, rGen2, rResGen);
686 
687  // make deterministic if necessary
688  if(!(rResGen.IsDeterministic())){
689  Deterministic(rResGen, rResGen);
690  }
691 
692  // set name of result
693  rResGen.Name("Concatenate("+rGen1.Name()+","+rGen2.Name()+")");
694 
695  return;
696 }
697 
698 // FullLanguage(rAlphabet, rResGen)
699 void FullLanguage(const EventSet& rAlphabet, Generator& rResGen) {
700  FD_DF("FullLanguage("<< rAlphabet.Name()
701  << "," << rResGen.Name() << ")");
702 
703  // prepare result
704  rResGen.Clear();
705 
706  // helpers
707  Idx state;
708  EventSet::Iterator evit;
709 
710  // alphabet
711  rResGen.InjectAlphabet(rAlphabet);
712 
713  // insert marked initial state
714  if(rResGen.StateNamesEnabled()){
715  state = rResGen.InsInitState("1");
716  } else{
717  state = rResGen.InsInitState();
718  }
719  rResGen.SetMarkedState(state);
720 
721  // create selfloop for each event
722  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
723  rResGen.SetTransition(state, *evit, state);
724  }
725 
726  // set name of result
727  rResGen.Name("FullLanguage("+rAlphabet.Name()+")");
728 
729  return;
730 }
731 
732 // AlphabetLanguage(rAlphabet, rResGen)
733 void AlphabetLanguage(const EventSet& rAlphabet, Generator& rResGen) {
734  FD_DF("AlphabetLanguage("<< rAlphabet.Name()
735  << "," << rResGen.Name() << ")");
736 
737  // prepare result
738  rResGen.Clear();
739 
740  // set name of result
741  rResGen.Name("AlphabetLanguage("+rAlphabet.Name()+")");
742 
743  // if alphabet is empty, leave generator empty
744  if(rAlphabet.Empty()){
745  FD_WARN("AlphabetLanguage: empty alphabet.");
746  return;
747  }
748 
749  // helpers
750  Idx istate, mstate;
751  EventSet::Iterator evit;
752 
753  // alphabet
754  rResGen.InjectAlphabet(rAlphabet);
755 
756  // insert one initial state and one marked state
757  if(rResGen.StateNamesEnabled()){
758  istate = rResGen.InsInitState("1");
759  mstate = rResGen.InsMarkedState("2");
760  }
761  else{
762  istate = rResGen.InsInitState();
763  mstate = rResGen.InsMarkedState();
764  }
765 
766  // for each event from rAlphabet, inserted transition leading from init state to marked state
767  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
768  rResGen.SetTransition(istate, *evit, mstate);
769  }
770 
771  return;
772 }
773 
774 // EmptyStringLanguage(rAlphabet, rResGen)
775 void EmptyStringLanguage(const EventSet& rAlphabet, Generator& rResGen) {
776  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
777  << "," << rResGen.Name() << ")");
778 
779  // prepare result
780  rResGen.Clear();
781 
782  // helpers
783  Idx state;
784 
785  // alphabet
786  rResGen.InjectAlphabet(rAlphabet);
787 
788  // insert marked initial state
789  if(rResGen.StateNamesEnabled()){
790  state = rResGen.InsInitState("1");
791  }
792  else{
793  state = rResGen.InsInitState();
794  }
795  rResGen.SetMarkedState(state);
796 
797  // set name of result
798  rResGen.Name("EmptyStringLanguage("+rAlphabet.Name()+")");
799 
800  return;
801 }
802 
803 // EmptyLanguage(rAlphabet, rResGen)
804 void EmptyLanguage(const EventSet& rAlphabet, Generator& rResGen) {
805  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
806  << "," << rResGen.Name() << ")");
807 
808  // prepare result
809  rResGen.Clear();
810 
811  // set alphabet
812  rResGen.InjectAlphabet(rAlphabet);
813 
814  // set name of result
815  rResGen.Name("EmptyLanguage("+rAlphabet.Name()+")");
816 
817  return;
818 }
819 
820 // EmptyLanguage(rGen)
821 bool IsEmptyLanguage(const Generator& rGen) {
822  // case a) check if set of marked or initial states is empty
823  if(rGen.MarkedStatesSize()==0) return true;
824  if(rGen.InitStatesSize()==0) return true;
825  // case b) check if no marked state is accessible (reachable)
826  return (rGen.AccessibleSet()*rGen.MarkedStates()).Empty();
827 }
828 
829 // LanguageInclusion(rGen1, rGen2)
830 bool LanguageInclusion(const Generator& rGen1, const Generator& rGen2) {
831 
832  FD_DF("LanguageInclusion("<< rGen1.Name() << "," << rGen2.Name() << ")");
833 
834  // check if there is no string in Lm1 that is not in Lm2, which means Lm1<=Lm2
835  Generator NotrGen2=rGen2;
836  NotrGen2.StateNamesEnabled(false);
837  // note: complement w.r.t. union of alphabets to ensure that elementwise
838  // inclusion of Lm1 in Lm2 is tested
839  LanguageComplement(NotrGen2 , rGen1.Alphabet()+rGen2.Alphabet());
840  return EmptyLanguageIntersection(rGen1,NotrGen2);
841 }
842 
843 // LanguageEquality(rGen1, rGen2)
844 bool LanguageEquality(const Generator& rGen1, const Generator& rGen2) {
845 
846  FD_DF("LanguageEquality("<< rGen1.Name() << "," << rGen2.Name() << ")");
847 
848  // Check for equality by testing mutual inclusion
849  return LanguageInclusion(rGen1,rGen2) && LanguageInclusion(rGen2,rGen1);
850 }
851 
852 // KleeneClosure(rGen)
854 
855  FD_DF("KleeneClosure("<< rGen.Name() << ")");
856 
857  // fix name
858  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
859 
860  // The Kleene Closure of the empty set is the empty set
861  if(IsEmptyLanguage(rGen)){
862  rGen.Clear();
863  rGen.Name(name);
864  return;
865  }
866 
867  // run nondet version
868  KleeneClosureNonDet(rGen);
869  Deterministic(rGen, rGen);
870 
871  // set name
872  rGen.Name(name);
873 }
874 
875 // KleeneClosure(rGen, rResGen)
876 void KleeneClosure(const Generator& rGen, Generator& rResGen) {
877 
878  FD_DF("KleeneClosure("<< rGen.Name() << ", ... )");
879 
880  // if arg and result match, call respective version
881  if(&rGen==&rResGen) {
882  KleeneClosure(rResGen);
883  return;
884  }
885 
886  // fix name
887  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
888 
889  // The Kleene Closure of the empty set is the empty set
890  if(IsEmptyLanguage(rGen)){
891  rResGen.Clear();
892  rResGen.Name(name);
893  return;
894  }
895 
896  // run nondet version with intermediate result
897  Generator* pgen=rGen.Copy();
898  KleeneClosureNonDet(*pgen);
899  Deterministic(*pgen, rResGen);
900  delete pgen;
901 
902  // set name
903  rResGen.Name(name);
904 }
905 
906 // KleeneClosureNonDet(rGen)
908 
909  FD_DF("KleeneClosureNonDet("<< rGen.Name() << ")");
910 
911  // set name
912  rGen.Name(CollapsString("KleeneClosureNonDet("+ rGen.Name() + ")"));
913 
914  // make accessible (relevant)
915  rGen.Accessible();
916 
917  // test for empty language
918  if(rGen.MarkedStatesSize()==0) {
919  rGen.Clear();
920  return;
921  }
922 
923  // helpers
924  TransSet::Iterator tit;
925  TransSet TransToInsert;
926 
927  // initial state bug (detected by Tomas Masopust, fixes proposed by Klaus Schmidt and Florian Frohn)
928  // 1. prepare the generator to have a unique initial state
929  // 2. if the initial state fails to be marked, introduce an alternative marked initial state.
930  // 3. equip the markded initial state with the same transitions as the original initial state
931  UniqueInit(rGen);
932  Idx istate = *rGen.InitStatesBegin();
933  Idx imstate = istate;
934  if(!rGen.ExistsMarkedState(imstate)) {
935  imstate=rGen.InsInitState();
936  rGen.SetMarkedState(imstate);
937  for(tit = rGen.TransRelBegin(istate); tit != rGen.TransRelEnd(istate); ++tit) {
938  TransToInsert.Insert(imstate, tit->Ev, tit->X2);
939  }
940  for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
941  rGen.SetTransition(*tit);
942  }
943  TransToInsert.Clear();
944  rGen.ClrInitState(istate);
945  }
946  rGen.Accessible(); // cosmetic
947 
948 
949  // for all transitions leading from a state x1 to a marked state: insert a transition
950  // with the same event that leads to the unique marked initial state.
951  for(tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
952  if(rGen.ExistsMarkedState(tit->X2)) {
953  if(!(rGen.ExistsTransition(tit->X1, tit->Ev, imstate)) ){
954  TransToInsert.Insert(tit->X1, tit->Ev, imstate);
955  }
956  }
957  }
958  for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
959  rGen.SetTransition(*tit);
960  }
961 
962 }
963 
964 // PrefixClosure(rGen)
966 
967  FD_DF("PrefixClosure("<< rGen.Name() << ")");
968 
969  // fix name
970  std::string name=CollapsString("PrefixClosure("+ rGen.Name() + ")");
971 
972  // remove all states that do net represent prefixes of marked strings
973  rGen.Coaccessible();
974 
975  // mark all remaining states
976  rGen.InjectMarkedStates(rGen.States());
977 
978  // set name
979  rGen.Name(name);
980 
981 }
982 
983 // IsPrefixClosed
984 bool IsPrefixClosed(const Generator& rGen) {
985 
986  // figure relevant states
987  StateSet relevant = rGen.AccessibleSet() * rGen.CoaccessibleSet();
988 
989  // test
990  return relevant <= rGen.MarkedStates();
991 
992 }
993 
994 // IsNonblocking
995 bool IsNonblocking(const Generator& rGen) {
996 
997  // test
998  return rGen.AccessibleSet() <= rGen.CoaccessibleSet();
999 
1000 }
1001 
1002 // IsNonblocking
1003 bool IsNonblocking(const Generator& rGen1, const Generator& rGen2) {
1004 
1005  // build composition
1006  Generator parallel;
1007  parallel.StateNamesEnabled(false);
1008  Parallel(rGen1,rGen2,parallel);
1009 
1010  // test (parallel returns an accessible generator).
1011  return parallel.States() <= parallel.CoaccessibleSet();
1012 
1013 }
1014 
1015 
1016 
1017 // SelfLoop(rGen,rAlphabet)
1018 void SelfLoop(Generator& rGen,const EventSet& rAlphabet) {
1019 
1020  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << ")");
1021 
1022  // fix name
1023  std::string name = CollapsString("SelfLoop(" + rGen.Name() + "," + rAlphabet.Name() + ")");
1024  // extend alphabet of rGen
1025  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1026 
1027  //helpers
1028  EventSet::Iterator evit,evbegin,evend;
1029  evbegin = rAlphabet.Begin();
1030  evend = rAlphabet.End();
1031  StateSet::Iterator sit;
1032 
1033  // iterate over all states and insert selfloop for each event of rAlphabet
1034  for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
1035  for(evit = evbegin; evit != evend; ++evit){
1036  rGen.SetTransition(*sit, *evit, *sit);
1037  }
1038  }
1039 
1040  // set name
1041  rGen.Name(name);
1042 }
1043 
1044 // SelfLoopMarkedStates(rGen,rAlphabet)
1045 void SelfLoopMarkedStates(Generator& rGen,const EventSet& rAlphabet) {
1046 
1047  FD_DF("SelfLoopMarkedStates(" << rGen.Name() << "," << rAlphabet.Name() << ")");
1048 
1049  // fix name
1050  std::string name = CollapsString("SelfLoopMarkedStates(" + rGen.Name()
1051  + "," + rAlphabet.Name() + ")");
1052 
1053  // extend alphabet of rGen
1054  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1055 
1056  //helpers
1057  EventSet::Iterator evit,evbegin,evend;
1058  evbegin = rAlphabet.Begin();
1059  evend = rAlphabet.End();
1060  StateSet::Iterator sit;
1061 
1062  // iterate over all marked states and insert selfloop for each event of rAlphabet
1063  for (sit = rGen.MarkedStatesBegin(); sit != rGen.MarkedStatesEnd(); ++sit) {
1064  for(evit = evbegin; evit != evend; ++evit){
1065  rGen.SetTransition(*sit, *evit, *sit);
1066  }
1067  }
1068 
1069  // set name
1070  rGen.Name(name);
1071 }
1072 
1073 // SelfLoop(rGen,rAlphabet,rStates)
1074 void SelfLoop(Generator& rGen,const EventSet& rAlphabet,const StateSet& rStates) {
1075 
1076  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << "," << rStates.Name() << ")");
1077 
1078  // fix name
1079  std::string name = CollapsString("SelfLoop(" + rGen.Name()
1080  + "," + rAlphabet.Name() + "," + rStates.Name() + ")");
1081 
1082  // exception: rStates must be states of rGen
1083 #ifdef FAUDES_CHECKED
1084  if( !(rStates <= rGen.States()) ){
1085  std::stringstream errstr;
1086  errstr << "State set " << rStates.Name() <<
1087  " has to be included in state set of "<< rGen.Name() << ".";
1088  throw Exception("SelfLoop()", errstr.str(), 100);
1089  }
1090 #endif
1091 
1092  // extend alphabet of rGen
1093  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1094 
1095  //helpers
1096  EventSet::Iterator evit,evbegin,evend;
1097  evbegin = rAlphabet.Begin();
1098  evend = rAlphabet.End();
1099  StateSet::Iterator sit;
1100 
1101  // iterate over all marked states and insert selfloop for each event of rAlphabet
1102  for (sit = rStates.Begin(); sit != rStates.End(); ++sit) {
1103  for(evit = evbegin; evit != evend; ++evit){
1104  rGen.SetTransition(*sit, *evit, *sit);
1105  }
1106  }
1107 
1108  // set name
1109  rGen.Name(name);
1110 }
1111 
1112 
1113 } // namespace faudes
1114 
1115 #undef Product //see define above for comment
#define FD_WPC(cntnow, contdone, message)
#define FD_WARN(message)
#define FD_DF(message)
#define FD_ERR(message)
std::vector< int >::size_type Position
virtual const T & At(const Position &pos) const
Iterator Begin(void) const
Iterator End(void) const
bool Insert(const Transition &rTransition)
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
void Write(const Type *pContext=0) const
Definition: cfl_types.cpp:140
Idx Size(void) const
StateSet::Iterator StatesBegin(void) const
StateSet::Iterator InitStatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
virtual void Move(vGenerator &rGen)
virtual vGenerator & Assign(const Type &rSrc)
virtual vGenerator * Copy(void) const
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
Idx InitStatesSize(void) const
EventSet::Iterator AlphabetBegin(void) const
virtual vGenerator * New(void) const
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
void InjectMarkedStates(const StateSet &rNewMarkedStates)
Idx MarkedStatesSize(void) const
void SetInitState(Idx index)
StateSet AccessibleSet(void) const
StateSet::Iterator MarkedStatesBegin(void) const
std::string StateName(Idx index) const
void Name(const std::string &rName)
bool DelState(Idx index)
StateSet::Iterator StatesEnd(void) const
void ClrInitState(Idx index)
TransSet::Iterator TransRelEnd(void) const
bool IsDeterministic(void) const
StateSet::Iterator MarkedStatesEnd(void) const
void SetMarkedState(Idx index)
bool StateNamesEnabled(void) const
StateSet::Iterator InitStatesEnd(void) const
EventSet::Iterator AlphabetEnd(void) const
StateSet CoaccessibleSet(void) const
virtual void Clear(void)
bool ExistsMarkedState(Idx index) const
std::string UniqueStateName(const std::string &rName) const
const StateSet & States(void) const
void InjectAlphabet(const EventSet &rNewalphabet)
bool Empty(void) const
Definition: cfl_baseset.h:1841
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2132
virtual void Clear(void)
Definition: cfl_baseset.h:1919
Iterator End(void) const
Definition: cfl_baseset.h:1913
Iterator Begin(void) const
Definition: cfl_baseset.h:1908
const std::string & Name(void) const
Definition: cfl_baseset.h:1772
bool EmptyLanguageIntersection(const Generator &rGen1, const Generator &rGen2)
void FullLanguage(const EventSet &rAlphabet, Generator &rResGen)
void LanguageUnion(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void LanguageConcatenateNonDet(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void SelfLoop(Generator &rGen, const EventSet &rAlphabet)
bool LanguageDisjoint(const Generator &rGen1, const Generator &rGen2)
bool LanguageInclusion(const Generator &rGen1, const Generator &rGen2)
void UniqueInit(Generator &rGen)
void KleeneClosure(Generator &rGen)
void PrefixClosure(Generator &rGen)
void Product(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void Deterministic(const Generator &rGen, Generator &rResGen)
void LanguageUnionNonDet(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Definition: cfl_regular.cpp:45
void Automaton(Generator &rGen, const EventSet &rAlphabet)
void AlphabetLanguage(const EventSet &rAlphabet, Generator &rResGen)
void LanguageConcatenate(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
bool IsEmptyLanguage(const Generator &rGen)
bool LanguageEquality(const Generator &rGen1, const Generator &rGen2)
void LanguageDifference(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void LanguageIntersection(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
bool IsPrefixClosed(const Generator &rGen)
void EmptyLanguage(const EventSet &rAlphabet, Generator &rResGen)
void Parallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void LanguageComplement(Generator &rGen, const EventSet &rAlphabet)
void EmptyStringLanguage(const EventSet &rAlphabet, Generator &rResGen)
void KleeneClosureNonDet(Generator &rGen)
void SelfLoopMarkedStates(Generator &rGen, const EventSet &rAlphabet)
uint32_t Idx
bool IsNonblocking(const GeneratorVector &rGvec)
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91

libFAUDES 2.33c --- 2025.05.15 --- c++ api documentaion by doxygen