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

libFAUDES 2.26g --- 2015.08.17 --- c++ api documentaion by doxygen