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("Product", 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  // for correct result, rGen has to be deterministic!
343 #ifdef FAUDES_CHECKED
344  if ( !(rGen.IsDeterministic()) ) {
345  FD_WARN("Automaton(): nondeterministic parameter " << rGen.Name() <<".");
346  }
347 #endif
348 
349  // prepare result
350  rGen.Name(CollapsString("Automaton(" + rGen.Name() + "," + rAlphabet.Name() + ")"));
351 
352  // extend rGen.Alphabet() by rAlphabet
353  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
354 
355  // remove states that do not represent prefixes of marked strings
356  rGen.Coaccessible();
357 
358  // introduce a dump state (unmarked)
359  Idx dump;
360  bool dumpReached=false; // record, whether dump state is indeed used
361  if (rGen.StateNamesEnabled()) {
362  std::string dumpstr=rGen.UniqueStateName("dump");
363  dump = rGen.InsState(dumpstr);
364  } else {
365  dump = rGen.InsState();
366  }
367 
368  // if there is no initial state, the dump state becomes the initial state
369  // (required for automaton from empty language argument)
370  if(rGen.InitStates().Empty()){
371  rGen.SetInitState(dump);
372  dumpReached=true;
373  }
374 
375  // introduce transitions to dumpstate
376  StateSet::Iterator sit;
377  EventSet::Iterator eit;
378  for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
379  for (eit = rGen.Alphabet().Begin(); eit != rGen.Alphabet().End(); ++eit) {
380  // If no transition is defined for this state and event, insert respective
381  // transition to dump state (note that dump state itself is also treated here
382  // and thus provided with selfloops)
383  if (rGen.TransRelBegin(*sit, *eit) == rGen.TransRelEnd(*sit, *eit)) {
384  rGen.SetTransition(*sit, *eit, dump);
385  // indicate that dumstate was reached
386  if(*sit!=dump) dumpReached=true;
387  }
388  }
389  }
390 
391  // if no transition was introduced (except for selfloops), remove dump state
392  if(!dumpReached)
393  rGen.DelState(dump);
394 }
395 
396 // Automaton(rGen)
397 void Automaton(Generator& rGen) {
398  FD_DF("Automaton("<< rGen.Name() << ")");
399  std::string name=rGen.Name();
400  Automaton(rGen,rGen.Alphabet());
401  rGen.Name(CollapsString("Automaton(" + name + ")"));
402 }
403 
404 // LanguageComplement(rGen,rAlphabet)
405 void LanguageComplement(Generator& rGen, const EventSet& rAlphabet) {
406  FD_DF("LanguageComplement("<< rGen.Name() << "," << rAlphabet.Name() << ")");
407 
408  // fix name
409  std::string name = rGen.Name();
410 
411  // convert to automaton (avoiding statename "dump")
412  bool stateNamesEnabled=rGen.StateNamesEnabled();
413  rGen.StateNamesEnabled(false);
414  Automaton(rGen,rAlphabet);
415  rGen.StateNamesEnabled(stateNamesEnabled);
416 
417  // invert marking
418  rGen.InjectMarkedStates(rGen.States() - rGen.MarkedStates());
419 
420  // set name
421  rGen.Name(CollapsString("Complement(" + name + "," + rAlphabet.Name() + ")"));
422 }
423 
424 // LanguageComplement(rGen)
426  FD_DF("LanguageComplement("<< rGen.Name() << ")");
427  std::string name=rGen.Name();
428  LanguageComplement(rGen,rGen.Alphabet());
429  rGen.Name(CollapsString("Complement(" + name + ")"));
430  return;
431 }
432 
433 // language complement, uniform api
434 void LanguageComplement(const Generator& rGen, Generator& rRes) {
435  rRes=rGen;
436  LanguageComplement(rRes);
437 }
438 
439 
440 // language complement, uniform api
441 void LanguageComplement(const Generator& rGen, const EventSet& rSigma, Generator& rRes) {
442  rRes=rGen;
443  LanguageComplement(rRes,rSigma);
444 }
445 
446 
447 
448 
449 //LanguageDifference(rGen1, rGen2, rResGen)
451  const Generator& rGen1,
452  const Generator& rGen2,
453  Generator& rResGen) {
454 
455  FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << ")");
456 
457  // incl. all-empty case
458  if(IsEmptyLanguage(rGen2)) {
459  rResGen.Assign(rGen1);
460  rResGen.Name(CollapsString("LanguageDifference(" + rGen1.Name() + "," + rGen2.Name() + ")"));
461  return;
462  }
463 
464  // use pointer pResGen to result rResGen
465  Generator* pResGen = &rResGen;
466  if(&rResGen == &rGen1 || &rResGen== &rGen2) {
467  pResGen = rResGen.New();
468  }
469 
470  // due to the use of LanguageComplement(), rGen2 has to be deterministic
471  #ifdef FAUDES_CHECKED
472  if(!(rGen2.IsDeterministic())){
473  std::stringstream errstr;
474  errstr << "Nondeterministic parameter " << rGen2.Name() << ".";
475  throw Exception("LanguageDifference()", errstr.str(), 101);
476  }
477  #endif
478 
479  // prepare result
480  pResGen->Clear();
481 
482  // calculate "Lm1-Lm2" by building the intersection of Lm1 with the complement of Lm2
483  // for correct result, complement has to be computed wrt the alphabet of Lm1 (!)
484 
485  *pResGen=rGen2;
486  LanguageComplement(*pResGen,rGen1.Alphabet());
487  LanguageIntersection(rGen1, *pResGen, *pResGen);
488 
489  FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << "): stage 2");
490 
491  // if necessary, move pResGen to rResGen
492  if(pResGen != &rResGen) {
493  pResGen->Move(rResGen);
494  delete pResGen;
495  }
496 
497  FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << "): done");
498  return;
499 }
500 
501 // LanguageConcatenateNonDet(rGen1, rGen2, rResGen)
502 void LanguageConcatenateNonDet(const Generator& rGen1, const Generator& rGen2,
503  Generator& rResGen) {
504  FD_DF("LanguageConcatenateNonDet(" << rGen1.Name() << "," << rGen2.Name() << ")");
505 
506  // are state names enabled in result?
507  bool stateNamesEnabled=rResGen.StateNamesEnabled();
508 
509  // use pointer pResGen to result rResGen
510  Generator* pResGen = &rResGen;
511  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
512  pResGen= rResGen.New();
513  }
514 
515  // prepare result
516  pResGen->Clear();
517 
518  // union of alphabets
519  pResGen->InjectAlphabet(rGen1.Alphabet() + rGen2.Alphabet());
520 
521  // Maps from states of rGen1 and rGen2 to states of ResGen
522  std::map<Idx,Idx> Gen1StatesMap;
523  std::map<Idx,Idx> Gen2StatesMap;
524 
525  // helpers
526  StateSet::Iterator sit;
527  TransSet::Iterator tit;
528 
529  // "union" of states: insert states representing the states of rGen1 and rGen2
530  for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
531  if (stateNamesEnabled) {
532  Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
533  } else {
534  Gen1StatesMap[*sit] = pResGen->InsState();
535  }
536  }
537  for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
538  if (stateNamesEnabled) {
539  Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
540  } else {
541  Gen2StatesMap[*sit] = pResGen->InsState();
542  }
543  }
544 
545  // "union" transitions: insert all rGen1 transitions
546  for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
547  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
548 
549  // "union" transitions: insert all rGen2 transitions
550  for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit)
551  pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
552 
553 
554  // initial state bug (detected by Tomas Masopust, fix by Klaus Schmidt)
555  // 1) copy all transitions to the result, clear initial/marked status
556  // 2) all initial states of G1 become initial states in the result
557  // 3) if L1 contains the empty string, also all initial states of G2 become initial states
558  // in the result
559  // 4) transition leading to a marked state in G1 also become transitions to all
560  // initial states of G2
561  // 5) marked states of G2 become marked in the result
562 
563 
564  // test whether L1 includes the empty string
565  bool concatenateEpsilon1=false;
566  for(sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
567  if(rGen1.ExistsMarkedState(*sit)) {
568  concatenateEpsilon1=true;
569  break;
570  }
571  }
572 
573  // initial states of G1 become initial states in the result
574  for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit)
575  pResGen->SetInitState(Gen1StatesMap[*sit]);
576 
577  // if L1 contains the emtystring, G2 initial states become initial states in the result
578  if(concatenateEpsilon1)
579  for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
580  pResGen->SetInitState(Gen2StatesMap[*sit]);
581 
582  // any G1 transition to a marked state must also lead to all initial states of G2
583  for(tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit)
584  if(rGen1.ExistsMarkedState(tit->X2))
585  for(sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit)
586  pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen2StatesMap[*sit]);
587 
588  // set pResGen marked states corresponding to rGen2 marked states using Gen2StatesMap
589  for(sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
590  pResGen->SetMarkedState(Gen2StatesMap[*sit]);
591  }
592 
593  // remove blocking states as they provide no useful meaning.
594  pResGen->Trim();
595  pResGen->Name("ConcatenateNonDet("+rGen1.Name()+","+rGen2.Name()+")");
596 
597  // if necessary, move pResGen to rResGen
598  if(pResGen != &rResGen) {
599  pResGen->Move(rResGen);
600  delete pResGen;
601  }
602 
603 }
604 
605 // LanguageConcatenate(rGen1, rGen2, rResGen)
606 void LanguageConcatenate(const Generator& rGen1, const Generator& rGen2,
607  Generator& rResGen) {
608 
609  FD_DF("LanguageConcatenate("<< rGen1.Name()
610  << "," << rGen2.Name() << ")");
611 
612  // perform nondeterministic language concatenation
613  LanguageConcatenateNonDet(rGen1, rGen2, rResGen);
614 
615  // make deterministic if necessary
616  if(!(rResGen.IsDeterministic())){
617  Deterministic(rResGen, rResGen);
618  }
619 
620  // set name of result
621  rResGen.Name("Concatenate("+rGen1.Name()+","+rGen2.Name()+")");
622 
623  return;
624 }
625 
626 // FullLanguage(rAlphabet, rResGen)
627 void FullLanguage(const EventSet& rAlphabet, Generator& rResGen) {
628  FD_DF("FullLanguage("<< rAlphabet.Name()
629  << "," << rResGen.Name() << ")");
630 
631  // prepare result
632  rResGen.Clear();
633 
634  // helpers
635  Idx state;
636  EventSet::Iterator evit;
637 
638  // alphabet
639  rResGen.InjectAlphabet(rAlphabet);
640 
641  // insert marked initial state
642  if(rResGen.StateNamesEnabled()){
643  state = rResGen.InsInitState("1");
644  } else{
645  state = rResGen.InsInitState();
646  }
647  rResGen.SetMarkedState(state);
648 
649  // create selfloop for each event
650  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
651  rResGen.SetTransition(state, *evit, state);
652  }
653 
654  // set name of result
655  rResGen.Name("FullLanguage("+rAlphabet.Name()+")");
656 
657  return;
658 }
659 
660 // AlphabetLanguage(rAlphabet, rResGen)
661 void AlphabetLanguage(const EventSet& rAlphabet, Generator& rResGen) {
662  FD_DF("AlphabetLanguage("<< rAlphabet.Name()
663  << "," << rResGen.Name() << ")");
664 
665  // prepare result
666  rResGen.Clear();
667 
668  // set name of result
669  rResGen.Name("AlphabetLanguage("+rAlphabet.Name()+")");
670 
671  // if alphabet is empty, leave generator empty
672  if(rAlphabet.Empty()){
673  FD_WARN("AlphabetLanguage: empty alphabet.");
674  return;
675  }
676 
677  // helpers
678  Idx istate, mstate;
679  EventSet::Iterator evit;
680 
681  // alphabet
682  rResGen.InjectAlphabet(rAlphabet);
683 
684  // insert one initial state and one marked state
685  if(rResGen.StateNamesEnabled()){
686  istate = rResGen.InsInitState("1");
687  mstate = rResGen.InsMarkedState("2");
688  }
689  else{
690  istate = rResGen.InsInitState();
691  mstate = rResGen.InsMarkedState();
692  }
693 
694  // for each event from rAlphabet, inserted transition leading from init state to marked state
695  for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
696  rResGen.SetTransition(istate, *evit, mstate);
697  }
698 
699  return;
700 }
701 
702 // EmptyStringLanguage(rAlphabet, rResGen)
703 void EmptyStringLanguage(const EventSet& rAlphabet, Generator& rResGen) {
704  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
705  << "," << rResGen.Name() << ")");
706 
707  // prepare result
708  rResGen.Clear();
709 
710  // helpers
711  Idx state;
712 
713  // alphabet
714  rResGen.InjectAlphabet(rAlphabet);
715 
716  // insert marked initial state
717  if(rResGen.StateNamesEnabled()){
718  state = rResGen.InsInitState("1");
719  }
720  else{
721  state = rResGen.InsInitState();
722  }
723  rResGen.SetMarkedState(state);
724 
725  // set name of result
726  rResGen.Name("EmptyStringLanguage("+rAlphabet.Name()+")");
727 
728  return;
729 }
730 
731 // EmptyLanguage(rAlphabet, rResGen)
732 void EmptyLanguage(const EventSet& rAlphabet, Generator& rResGen) {
733  FD_DF("EmptyStringLanguage("<< rAlphabet.Name()
734  << "," << rResGen.Name() << ")");
735 
736  // prepare result
737  rResGen.Clear();
738 
739  // set alphabet
740  rResGen.InjectAlphabet(rAlphabet);
741 
742  // set name of result
743  rResGen.Name("EmptyLanguage("+rAlphabet.Name()+")");
744 
745  return;
746 }
747 
748 // EmptyLanguage(rGen)
749 bool IsEmptyLanguage(const Generator& rGen) {
750  // case a) check if set of marked or initial states is empty
751  if(rGen.MarkedStatesSize()==0) return true;
752  if(rGen.InitStatesSize()==0) return true;
753  // case b) check if no marked state is accessible (reachable)
754  return (rGen.AccessibleSet()*rGen.MarkedStates()).Empty();
755 }
756 
757 // LanguageInclusion(rGen1, rGen2)
758 bool LanguageInclusion(const Generator& rGen1, const Generator& rGen2) {
759 
760  FD_DF("LanguageInclusion("<< rGen1.Name() << "," << rGen2.Name() << ")");
761 
762  // check if there is no string in Lm1 that is not in Lm2, which means Lm1<=Lm2
763  Generator NotrGen2=rGen2;
764  NotrGen2.StateNamesEnabled(false);
765  // note: complement w.r.t. union of alphabets to ensure that elementwise
766  // inclusion of Lm1 in Lm2 is tested
767  LanguageComplement(NotrGen2 , rGen1.Alphabet()+rGen2.Alphabet());
768  return EmptyLanguageIntersection(rGen1,NotrGen2);
769 }
770 
771 // LanguageEquality(rGen1, rGen2)
772 bool LanguageEquality(const Generator& rGen1, const Generator& rGen2) {
773 
774  FD_DF("LanguageEquality("<< rGen1.Name() << "," << rGen2.Name() << ")");
775 
776  // Check for equality by testing mutual inclusion
777  return LanguageInclusion(rGen1,rGen2) && LanguageInclusion(rGen2,rGen1);
778 }
779 
780 // KleeneClosure(rGen)
782 
783  FD_DF("KleeneClosure("<< rGen.Name() << ")");
784 
785  // fix name
786  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
787 
788  // The Kleene Closure of the empty set is the empty set
789  if(IsEmptyLanguage(rGen)){
790  rGen.Clear();
791  rGen.Name(name);
792  return;
793  }
794 
795  // run nondet version
796  KleeneClosureNonDet(rGen);
797  Deterministic(rGen, rGen);
798 
799  // set name
800  rGen.Name(name);
801 }
802 
803 // KleeneClosure(rGen, rResGen)
804 void KleeneClosure(const Generator& rGen, Generator& rResGen) {
805 
806  FD_DF("KleeneClosure("<< rGen.Name() << ", ... )");
807 
808  // if arg and result match, call respective version
809  if(&rGen==&rResGen) {
810  KleeneClosure(rResGen);
811  return;
812  }
813 
814  // fix name
815  std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
816 
817  // The Kleene Closure of the empty set is the empty set
818  if(IsEmptyLanguage(rGen)){
819  rResGen.Clear();
820  rResGen.Name(name);
821  return;
822  }
823 
824  // run nondet version with intermediate result
825  Generator* pgen=rGen.Copy();
826  KleeneClosureNonDet(*pgen);
827  Deterministic(*pgen, rResGen);
828  delete pgen;
829 
830  // set name
831  rResGen.Name(name);
832 }
833 
834 // KleeneClosureNonDet(rGen)
836 
837  FD_DF("KleeneClosureNonDet("<< rGen.Name() << ")");
838 
839  // set name
840  rGen.Name(CollapsString("KleeneClosureNonDet("+ rGen.Name() + ")"));
841 
842  // The Kleene Closure of the empty set is the empty set
843  if(IsEmptyLanguage(rGen)) {
844  rGen.Clear();
845  return;
846  }
847 
848  // helpers
849  TransSet::Iterator tit;
850  TransSet TransToInsert;
851 
852  // initial state bug (detected by Tomas Masopust, fix proposed by Klaus Schmidt)
853  // 1. prepare the generator to have a unique initial state
854  // 2. if the initial state fails to be marked, introduce a fake marked initial state.
855  // 3. equip the fake markded initial state with the same transitions as the original initial state
856  UniqueInit(rGen);
857  Idx istate = *rGen.InitStatesBegin();
858  Idx imstate = istate;
859  if(!rGen.ExistsMarkedState(imstate)) {
860  imstate=rGen.InsInitState();
861  rGen.SetMarkedState(imstate);
862  for(tit = rGen.TransRelBegin(istate); tit != rGen.TransRelEnd(istate); ++tit) {
863  TransToInsert.Insert(imstate, tit->Ev, tit->X2);
864  }
865  }
866 
867  // for all transitions leading from a state x1 to a marked state: insert a transition
868  // with the same event that leads to the initial state(s).
869  for(tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
870  if(rGen.ExistsMarkedState(tit->X2)) {
871  if(!(rGen.ExistsTransition(tit->X1, tit->Ev, imstate)) ){
872  TransToInsert.Insert(tit->X1, tit->Ev, imstate);
873  }
874  }
875  }
876  for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
877  rGen.SetTransition(*tit);
878  }
879 
880 }
881 
882 // PrefixClosure(rGen)
884 
885  FD_DF("PrefixClosure("<< rGen.Name() << ")");
886 
887  // fix name
888  std::string name=CollapsString("PrefixClosure("+ rGen.Name() + ")");
889 
890  // remove all states that do net represent prefixes of marked strings
891  rGen.Coaccessible();
892 
893  // mark all remaining states
894  rGen.InjectMarkedStates(rGen.States());
895 
896  // set name
897  rGen.Name(name);
898 
899 }
900 
901 // IsPrefixClosed
902 bool IsPrefixClosed(const Generator& rGen) {
903 
904  // figure relevant states
905  StateSet relevant = rGen.AccessibleSet() * rGen.CoaccessibleSet();
906 
907  // test
908  return relevant <= rGen.MarkedStates();
909 
910 }
911 
912 // IsNonblocking
913 bool IsNonblocking(const Generator& rGen) {
914 
915  // test
916  return rGen.AccessibleSet() <= rGen.CoaccessibleSet();
917 
918 }
919 
920 // IsNonblocking
921 bool IsNonblocking(const Generator& rGen1, const Generator& rGen2) {
922 
923  // build composition
924  Generator parallel;
925  parallel.StateNamesEnabled(false);
926  Parallel(rGen1,rGen2,parallel);
927 
928  // test (parallel returns an accessible generator).
929  return parallel.States() <= parallel.CoaccessibleSet();
930 
931 }
932 
933 
934 
935 // SelfLoop(rGen,rAlphabet)
936 void SelfLoop(Generator& rGen,const EventSet& rAlphabet) {
937 
938  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << ")");
939 
940  // fix name
941  std::string name = CollapsString("SelfLoop(" + rGen.Name() + "," + rAlphabet.Name() + ")");
942  // extend alphabet of rGen
943  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
944 
945  //helpers
946  EventSet::Iterator evit,evbegin,evend;
947  evbegin = rAlphabet.Begin();
948  evend = rAlphabet.End();
949  StateSet::Iterator sit;
950 
951  // iterate over all states and insert selfloop for each event of rAlphabet
952  for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
953  for(evit = evbegin; evit != evend; ++evit){
954  rGen.SetTransition(*sit, *evit, *sit);
955  }
956  }
957 
958  // set name
959  rGen.Name(name);
960 }
961 
962 // SelfLoopMarkedStates(rGen,rAlphabet)
963 void SelfLoopMarkedStates(Generator& rGen,const EventSet& rAlphabet) {
964 
965  FD_DF("SelfLoopMarkedStates(" << rGen.Name() << "," << rAlphabet.Name() << ")");
966 
967  // fix name
968  std::string name = CollapsString("SelfLoopMarkedStates(" + rGen.Name()
969  + "," + rAlphabet.Name() + ")");
970 
971  // extend alphabet of rGen
972  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
973 
974  //helpers
975  EventSet::Iterator evit,evbegin,evend;
976  evbegin = rAlphabet.Begin();
977  evend = rAlphabet.End();
978  StateSet::Iterator sit;
979 
980  // iterate over all marked states and insert selfloop for each event of rAlphabet
981  for (sit = rGen.MarkedStatesBegin(); sit != rGen.MarkedStatesEnd(); ++sit) {
982  for(evit = evbegin; evit != evend; ++evit){
983  rGen.SetTransition(*sit, *evit, *sit);
984  }
985  }
986 
987  // set name
988  rGen.Name(name);
989 }
990 
991 // SelfLoop(rGen,rAlphabet,rStates)
992 void SelfLoop(Generator& rGen,const EventSet& rAlphabet,const StateSet& rStates) {
993 
994  FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << "," << rStates.Name() << ")");
995 
996  // fix name
997  std::string name = CollapsString("SelfLoop(" + rGen.Name()
998  + "," + rAlphabet.Name() + "," + rStates.Name() + ")");
999 
1000  // exception: rStates must be states of rGen
1001 #ifdef FAUDES_CHECKED
1002  if( !(rStates <= rGen.States()) ){
1003  std::stringstream errstr;
1004  errstr << "State set " << rStates.Name() <<
1005  " has to be included in state set of "<< rGen.Name() << ".";
1006  throw Exception("SelfLoop()", errstr.str(), 100);
1007  }
1008 #endif
1009 
1010  // extend alphabet of rGen
1011  rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
1012 
1013  //helpers
1014  EventSet::Iterator evit,evbegin,evend;
1015  evbegin = rAlphabet.Begin();
1016  evend = rAlphabet.End();
1017  StateSet::Iterator sit;
1018 
1019  // iterate over all marked states and insert selfloop for each event of rAlphabet
1020  for (sit = rStates.Begin(); sit != rStates.End(); ++sit) {
1021  for(evit = evbegin; evit != evend; ++evit){
1022  rGen.SetTransition(*sit, *evit, *sit);
1023  }
1024  }
1025 
1026  // set name
1027  rGen.Name(name);
1028 }
1029 
1030 
1031 } // namespace faudes
1032 
1033 #undef Product //see define above for comment

libFAUDES 2.28a --- 2016.09.13 --- c++ api documentaion by doxygen