omg_buechifnct.cpp
Go to the documentation of this file.
1 /** @file omg_buechifnct.cpp
2 
3 Operations regarding omega languages accepted by Buechi automata
4 
5 */
6 
7 /* FAU Discrete Event Systems Library (libfaudes)
8 
9 Copyright (C) 2010, 2025 Thomas Moor
10 
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15 
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20 
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
24 
25 
26 
27 #include "omg_buechifnct.h"
28 
29 
30 namespace faudes {
31 
32 // BuechiTrim
33 // (return True if resulting contains at least one initial state and at least one mark)
34 bool BuechiTrim(vGenerator& rGen) {
35 
36  // note: this really is inefficient; at least we should
37  // record the inverse transition relation for the coaccessile
38  // iteration
39 
40  // first we make the generator accessible
41  rGen.Accessible();
42  // iterate coaccessible and complete until convergence in oserved
43  while(1) {
44  Idx osize=rGen.States().Size();
45  rGen.Coaccessible();
46  rGen.Complete();
47  if(rGen.States().Size()==osize) break;
48  }
49  // done
50  return !rGen.InitStates().Empty() && !rGen.MarkedStates().Empty();
51 }
52 
53 // rti wrapper
54 bool BuechiTrim(const vGenerator& rGen, vGenerator& rRes) {
55  rRes=rGen;
56  return BuechiTrim(rRes);
57 }
58 
59 // IsBuechiTrim()
60 bool IsBuechiTrim(const vGenerator& rGen) {
61  bool res=true;
62  if(!rGen.IsAccessible()) res=false;
63  else if(!rGen.IsCoaccessible()) res=false;
64  else if(!rGen.IsComplete()) res=false;
65  FD_DF("IsBuechiTrim(): result " << res);
66  return res;
67 }
68 
69 // BuechiClosure(rGen)
70 void BuechiClosure(Generator& rGen) {
71  FD_DF("BuechiClosure("<< rGen.Name() << ")");
72  // fix name
73  std::string name=CollapsString("BuechiClosure("+ rGen.Name() + ")");
74  // remove all states that do net represent prefixes of marked strings
75  BuechiTrim(rGen);
76  // mark all remaining states
77  rGen.InjectMarkedStates(rGen.States());
78  // set name
79  rGen.Name(name);
80 }
81 
82 
83 // IsBuechiClosed
84 bool IsBuechiClosed(const Generator& rGen) {
85  FD_DF("IsBuechiClosed("<< rGen.Name() << ")");
86  // figure irrelevant states: not coaccessible / accessible
87  StateSet irrelevant = rGen.States();
88  irrelevant.EraseSet(rGen.AccessibleSet()* rGen.CoaccessibleSet());
89  // figure irrelevant states: terminal
90  irrelevant.InsertSet(rGen.TerminalStates());
91  // iterative search on indirect terminal states ...
92  bool done;
93  do {
94  // ... over all states
95  StateSet::Iterator sit = rGen.States().Begin();
96  StateSet::Iterator sit_end = rGen.States().End();
97  done=true;
98  for(; sit!=sit_end; ++sit) {
99  if(irrelevant.Exists(*sit)) continue;
100  TransSet::Iterator tit = rGen.TransRelBegin(*sit);
101  TransSet::Iterator tit_end = rGen.TransRelEnd(*sit);
102  for (; tit != tit_end; ++tit) {
103  if(!irrelevant.Exists(tit->X2)) break;
104  }
105  if(tit==tit_end) {
106  irrelevant.Insert(*sit);
107  done=false;
108  }
109  }
110  } while(!done);
111 
112  // marked states are irrelevant here
113  irrelevant.InsertSet(rGen.MarkedStates());
114  // report
115 #ifdef FAUDES_DEBUG_FUNCTION
116  FD_DF("IsBuechiClosed(..): irrelevant states "<< irrelevant.ToString());
117 #endif
118  // locate unmarked SCCs
119  // find all relevant SCCs
121  std::list<StateSet> umsccs;
122  StateSet umroots;
123  ComputeScc(rGen,umfilter,umsccs,umroots);
124  // report
125 #ifdef FAUDES_DEBUG_FUNCTION
126  std::list<StateSet>::iterator ssit=umsccs.begin();
127  for(;ssit!=umsccs.end(); ++ssit) {
128  FD_DF("IsBuechiClosed(): GPlant-marked scc without GCand-mark: " << ssit->ToString());
129  }
130 #endif
131  // done
132  return umsccs.empty();
133 }
134 
135 
136 // helper class for omega compositions
137 class OPState {
138 public:
139  // minimal interface
140  OPState() {};
141  OPState(const Idx& rq1, const Idx& rq2, const bool& rf) :
142  q1(rq1), q2(rq2), m1required(rf), mresolved(false) {};
143  std::string Str(void) { return ToStringInteger(q1)+"|"+
145  // order
146  bool operator < (const OPState& other) const {
147  if (q1 < other.q1) return(true);
148  if (q1 > other.q1) return(false);
149  if (q2 < other.q2) return(true);
150  if (q2 > other.q2) return(false);
151  if (!m1required && other.m1required) return(true);
152  if (m1required && !other.m1required) return(false);
153  if (!mresolved && other.mresolved) return(true);
154  return(false);
155  }
156  // member variables
160  bool mresolved;
161 };
162 
163 
164 
165 // BuechiProduct(rGen1, rGen2, res)
167  const Generator& rGen1, const Generator& rGen2,
168  Generator& rResGen)
169 {
170  FD_DF("BuechiProduct(" << &rGen1 << "," << &rGen2 << ")");
171 
172  // prepare result
173  Generator* pResGen = &rResGen;
174  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
175  pResGen= rResGen.New();
176  }
177  pResGen->Clear();
178  pResGen->Name(CollapsString(rGen1.Name()+".x."+rGen2.Name()));
179 
180  // create res alphabet
181  pResGen->InsEvents(rGen1.Alphabet());
182  pResGen->InsEvents(rGen2.Alphabet());
183 
184  // reverse composition map
185  std::map< OPState, Idx> reverseCompositionMap;
186  // todo stack
187  std::stack< OPState > todo;
188  // current pair, new pair
189  OPState currentstates, newstates;
190  // state
191  Idx tmpstate;
192  StateSet::Iterator lit1, lit2;
193  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
194  std::map< OPState, Idx>::iterator rcit;
195  // push all combinations of initial states on todo stack
196  FD_DF("BuechiProduct: adding all combinations of initial states to todo:");
197  for (lit1 = rGen1.InitStatesBegin(); lit1 != rGen1.InitStatesEnd(); ++lit1) {
198  for (lit2 = rGen2.InitStatesBegin(); lit2 != rGen2.InitStatesEnd(); ++lit2) {
199  currentstates = OPState(*lit1, *lit2, true);
200  todo.push(currentstates);
201  reverseCompositionMap[currentstates] = pResGen->InsInitState();
202  FD_DF("BuechiProduct: " << currentstates.Str() << " -> " << reverseCompositionMap[currentstates]);
203  }
204  }
205 
206  // start algorithm
207  FD_DF("BuechiProduct: processing reachable states:");
208  while (! todo.empty()) {
209  // allow for user interrupt
210  LoopCallback();
211  // get next reachable state from todo stack
212  currentstates = todo.top();
213  todo.pop();
214  FD_DF("BuechiProduct: processing (" << currentstates.Str() << " -> " << reverseCompositionMap[currentstates]);
215  // iterate over all rGen1 transitions
216  tit1 = rGen1.TransRelBegin(currentstates.q1);
217  tit1_end = rGen1.TransRelEnd(currentstates.q1);
218  for(; tit1 != tit1_end; ++tit1) {
219  // find transition in rGen2
220  tit2 = rGen2.TransRelBegin(currentstates.q2, tit1->Ev);
221  tit2_end = rGen2.TransRelEnd(currentstates.q2, tit1->Ev);
222  for (; tit2 != tit2_end; ++tit2) {
223  newstates = OPState(tit1->X2, tit2->X2,currentstates.m1required);
224  // figure whether marking was resolved
225  if(currentstates.m1required) {
226  if(rGen1.ExistsMarkedState(currentstates.q1))
227  newstates.m1required=false;
228  } else {
229  if(rGen2.ExistsMarkedState(currentstates.q2))
230  newstates.m1required=true;
231  }
232  // add to todo list if composition state is new
233  rcit = reverseCompositionMap.find(newstates);
234  if(rcit == reverseCompositionMap.end()) {
235  todo.push(newstates);
236  tmpstate = pResGen->InsState();
237  if(!newstates.m1required)
238  if(rGen2.ExistsMarkedState(newstates.q2))
239  pResGen->SetMarkedState(tmpstate);
240  reverseCompositionMap[newstates] = tmpstate;
241  FD_DF("BuechiProduct: todo push: (" << newstates.Str() << ") -> " << reverseCompositionMap[newstates]);
242  }
243  else {
244  tmpstate = rcit->second;
245  }
246  pResGen->SetTransition(reverseCompositionMap[currentstates],
247  tit1->Ev, tmpstate);
248  FD_DF("BuechiProduct: add transition to new generator: " <<
249  pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
250  }
251  }
252  }
253 
254  FD_DF("BuechiProduct: marked states: " << pResGen->MarkedStatesToString());
255 
256 
257  // fix statenames ...
258  if(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled())
259  for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
260  Idx x1=rcit->first.q1;
261  Idx x2=rcit->first.q2;
262  bool m1requ=rcit->first.m1required;
263  Idx x12=rcit->second;
264  if(!pResGen->ExistsState(x12)) continue;
265  std::string name1= rGen1.StateName(x1);
266  if(name1=="") name1=ToStringInteger(x1);
267  std::string name2= rGen2.StateName(x2);
268  if(name2=="") name1=ToStringInteger(x2);
269  std::string name12 = name1 + "|" + name2;
270  if(m1requ) name12 += "|r1m";
271  else name12 +="|r2m";
272  name12=pResGen->UniqueStateName(name12);
273  pResGen->StateName(x12,name12);
274  }
275 
276  // .. or clear them (?)
277  if(!(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled()))
278  pResGen->StateNamesEnabled(false);
279 
280  // copy result
281  if(pResGen != &rResGen) {
282  pResGen->Move(rResGen);
283  delete pResGen;
284  }
285 }
286 
287 // BuechiProduct for Generators, transparent for event attributes.
289  const Generator& rGen1,
290  const Generator& rGen2,
291  Generator& rResGen)
292 {
293  // inputs have to agree on attributes of shared events:
294  bool careattr=rGen1.Alphabet().EqualAttributes(rGen2.Alphabet());
295  // prepare result
296  Generator* pResGen = &rResGen;
297  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
298  pResGen= rResGen.New();
299  }
300  // make product composition of inputs
301  BuechiProduct(rGen1,rGen2,*pResGen);
302  // copy all attributes of input alphabets
303  if(careattr) {
304  pResGen->EventAttributes(rGen1.Alphabet());
305  pResGen->EventAttributes(rGen2.Alphabet());
306  }
307  // copy result
308  if(pResGen != &rResGen) {
309  pResGen->Move(rResGen);
310  delete pResGen;
311  }
312 }
313 
314 
315 // BuechiParallel(rGen1, rGen2, res)
317  const Generator& rGen1, const Generator& rGen2,
318  Generator& rResGen)
319 {
320  FD_DF("BuechiParallel(" << &rGen1 << "," << &rGen2 << ")");
321  // prepare result
322  Generator* pResGen = &rResGen;
323  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
324  pResGen= rResGen.New();
325  }
326  pResGen->Clear();
327  pResGen->Name(CollapsString(rGen1.Name()+"|||"+rGen2.Name()));
328  // create res alphabet
329  pResGen->InsEvents(rGen1.Alphabet());
330  pResGen->InsEvents(rGen2.Alphabet());
331  // shared events
332  EventSet sharedalphabet = rGen1.Alphabet() * rGen2.Alphabet();
333  FD_DF("BuechiParallel: g1 events: " << rGen1.Alphabet().ToString());
334  FD_DF("BuechiParallel: g2 events: " << rGen2.Alphabet().ToString());
335  FD_DF("BuechiParallel: shared events: " << sharedalphabet.ToString());
336 
337  // reverse composition map
338  std::map< OPState, Idx> reverseCompositionMap;
339  // todo stack
340  std::stack< OPState > todo;
341  // current pair, new pair
342  OPState currentstates, newstates;
343  // state
344  Idx tmpstate;
345  StateSet::Iterator lit1, lit2;
346  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
347  std::map< OPState, Idx>::iterator rcit;
348  // push all combinations of initial states on todo stack
349  FD_DF("BuechiParallel: adding all combinations of initial states to todo:");
350  for (lit1 = rGen1.InitStatesBegin(); lit1 != rGen1.InitStatesEnd(); ++lit1) {
351  for (lit2 = rGen2.InitStatesBegin(); lit2 != rGen2.InitStatesEnd(); ++lit2) {
352  currentstates = OPState(*lit1, *lit2, true);
353  tmpstate=pResGen->InsInitState();
354  if(rGen2.ExistsMarkedState(*lit2)) {
355  currentstates.mresolved=true;
356  pResGen->SetMarkedState(tmpstate);
357  }
358  todo.push(currentstates);
359  reverseCompositionMap[currentstates] = tmpstate;
360  FD_DF("BuechiParallel: " << currentstates.Str() << " -> " << tmpstate);
361  }
362  }
363 
364  // start algorithm
365  FD_DF("BuechiParallel: processing reachable states:");
366  while (! todo.empty()) {
367  // allow for user interrupt
368  LoopCallback();
369  // get next reachable state from todo stack
370  currentstates = todo.top();
371  todo.pop();
372  FD_DF("BuechiParallel: processing (" << currentstates.Str() << " -> "
373  << reverseCompositionMap[currentstates]);
374  // iterate over all rGen1 transitions
375  // (includes execution of shared events)
376  tit1 = rGen1.TransRelBegin(currentstates.q1);
377  tit1_end = rGen1.TransRelEnd(currentstates.q1);
378  for(; tit1 != tit1_end; ++tit1) {
379  // if event not shared
380  if(! sharedalphabet.Exists(tit1->Ev)) {
381  FD_DF("BuechiParallel: exists only in rGen1");
382  newstates = OPState(tit1->X2, currentstates.q2, currentstates.m1required);
383  // figure whether marking is resolved
384  // (tmoor 201208: only m1required can be resolved, since only G1 proceeds)
385  if(currentstates.m1required) {
386  if(rGen1.ExistsMarkedState(newstates.q1)) {
387  newstates.m1required=false;
388  //newstates.mresolved=true; // optional
389  }
390  }
391  // add to todo list if composition state is new
392  rcit = reverseCompositionMap.find(newstates);
393  if (rcit == reverseCompositionMap.end()) {
394  todo.push(newstates);
395  tmpstate = pResGen->InsState();
396  if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);
397  reverseCompositionMap[newstates] = tmpstate;
398  FD_DF("BuechiParallel: todo push: " << newstates.Str() << "|"
399  << reverseCompositionMap[newstates]);
400  }
401  else {
402  tmpstate = rcit->second;
403  }
404  // insert transition to result
405  pResGen->SetTransition(reverseCompositionMap[currentstates], tit1->Ev,
406  tmpstate);
407  FD_DF("BuechiParallel: add transition to new generator: " <<
408  pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
409  }
410  // if shared event
411  else {
412  FD_DF("BuechiParallel: common event");
413  // find shared transitions
414  tit2 = rGen2.TransRelBegin(currentstates.q2, tit1->Ev);
415  tit2_end = rGen2.TransRelEnd(currentstates.q2, tit1->Ev);
416  for (; tit2 != tit2_end; ++tit2) {
417  newstates = OPState(tit1->X2,tit2->X2,currentstates.m1required);
418  // figure whether marking was resolved
419  // (tmoor 201208: both markings can be resolved, since both G1 and G2 proceed)
420  if(currentstates.m1required) {
421  if(rGen1.ExistsMarkedState(newstates.q1)) {
422  newstates.m1required=false;
423  //newstates.mresolved=true; // optional
424  }
425  } else {
426  if(rGen2.ExistsMarkedState(newstates.q2)) {
427  newstates.m1required=true;
428  newstates.mresolved=true;
429  }
430  }
431  // add to todo list if composition state is new
432  rcit = reverseCompositionMap.find(newstates);
433  if (rcit == reverseCompositionMap.end()) {
434  todo.push(newstates);
435  tmpstate = pResGen->InsState();
436  if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);
437  reverseCompositionMap[newstates] = tmpstate;
438  FD_DF("BuechiParallel: todo push: (" << newstates.Str() << ") -> "
439  << reverseCompositionMap[newstates]);
440  }
441  else {
442  tmpstate = rcit->second;
443  }
444  pResGen->SetTransition(reverseCompositionMap[currentstates],
445  tit1->Ev, tmpstate);
446  FD_DF("BuechiParallel: add transition to new generator: " <<
447  pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
448  }
449  }
450  }
451  // iterate over all remaining rGen2 transitions
452  // (without execution of shared events)
453  tit2 = rGen2.TransRelBegin(currentstates.q2);
454  tit2_end = rGen2.TransRelEnd(currentstates.q2);
455  for (; tit2 != tit2_end; ++tit2) {
456  if (! sharedalphabet.Exists(tit2->Ev)) {
457  FD_DF("BuechiParallel: exists only in rGen2: " << sharedalphabet.Str(tit2->Ev));
458  newstates = OPState(currentstates.q1, tit2->X2, currentstates.m1required);
459  // figure whether marking was resolved
460  // (tmoor 201208: only m2required=!m1required can be resolved, since only G2 proceeds)
461  if(!currentstates.m1required) {
462  if(rGen2.ExistsMarkedState(newstates.q2)) {
463  newstates.m1required=true;
464  newstates.mresolved=true;
465  }
466  }
467  FD_DF("BuechiParallel: set trans: " << currentstates.Str() << " " << newstates.Str());
468  // add to todo list if composition state is new
469  rcit = reverseCompositionMap.find(newstates);
470  if (rcit == reverseCompositionMap.end()) {
471  todo.push(newstates);
472  tmpstate = pResGen->InsState();
473  if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);
474  reverseCompositionMap[newstates] = tmpstate;
475  FD_DF("BuechiParallel: todo push: " << newstates.Str() << " -> "
476  << reverseCompositionMap[newstates]);
477  }
478  else {
479  tmpstate = rcit->second;
480  }
481  pResGen->SetTransition(reverseCompositionMap[currentstates],
482  tit2->Ev, tmpstate);
483  FD_DF("BuechiParallel: add transition to new generator: " <<
484  pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit2->Ev, tmpstate)));
485  }
486  }
487  }
488 
489  FD_DF("BuechiParallel: marked states: " << pResGen->MarkedStatesToString());
490 
491  // fix statenames ...
492  if(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled())
493  for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
494  Idx x1=rcit->first.q1;
495  Idx x2=rcit->first.q2;
496  bool m1requ=rcit->first.m1required;
497  bool mres=rcit->first.mresolved;
498  Idx x12=rcit->second;
499  if(!pResGen->ExistsState(x12)) continue;
500  std::string name1= rGen1.StateName(x1);
501  if(name1=="") name1=ToStringInteger(x1);
502  std::string name2= rGen2.StateName(x2);
503  if(name2=="") name1=ToStringInteger(x2);
504  std::string name12 = name1 + "|" + name2 ;
505  if(m1requ) name12 += "|r1m";
506  else name12 +="|r2m";
507  if(mres) name12 += "*";
508  name12=pResGen->UniqueStateName(name12);
509  pResGen->StateName(x12,name12);
510  }
511 
512  // .. or clear them (?)
513  if(!(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled()))
514  pResGen->StateNamesEnabled(false);
515 
516  // copy result
517  if(pResGen != &rResGen) {
518  pResGen->Move(rResGen);
519  delete pResGen;
520  }
521 }
522 
523 
524 // BuechiParallel for Generators, transparent for event attributes.
526  const Generator& rGen1,
527  const Generator& rGen2,
528  Generator& rResGen)
529 {
530  // inputs have to agree on attributes of shared events:
531  bool careattr=rGen1.Alphabet().EqualAttributes(rGen2.Alphabet());
532  // prepare result
533  Generator* pResGen = &rResGen;
534  if(&rResGen== &rGen1 || &rResGen== &rGen2) {
535  pResGen= rResGen.New();
536  }
537  // make product composition of inputs
538  BuechiParallel(rGen1,rGen2,*pResGen);
539  // copy all attributes of input alphabets
540  if(careattr) {
541  pResGen->EventAttributes(rGen1.Alphabet());
542  pResGen->EventAttributes(rGen2.Alphabet());
543  }
544  // copy result
545  if(pResGen != &rResGen) {
546  pResGen->Move(rResGen);
547  delete pResGen;
548  }
549 }
550 
551 
552 // IsOmegaRelativelyMarked(rGenPlant,rGenCand)
553 bool IsBuechiRelativelyMarked(const Generator& rGenPlant, const Generator& rGenCand) {
554 
555 
556  FD_DF("IsBuechiRelativelyMarked(\"" << rGenPlant.Name() << "\", \"" << rGenCand.Name() << "\")");
557 
558  // alphabets must match
559  if ( rGenPlant.Alphabet() != rGenCand.Alphabet()) {
560  std::stringstream errstr;
561  errstr << "Alphabets of generators do not match.";
562  throw Exception("BuechiRelativelyMarked", errstr.str(), 100);
563  }
564 
565 #ifdef FAUDES_CHECKED
566  // generators are meant to be nonblocking
567  if ( !IsBuechiTrim(rGenCand) || !IsBuechiTrim(rGenPlant)) {
568  std::stringstream errstr;
569  errstr << "Arguments are expected to be nonblocking.";
570  throw Exception("IsBuechiRelativelyMarked", errstr.str(), 201);
571  }
572 #endif
573 
574 #ifdef FAUDES_CHECKED
575  // generators are meant to be deterministic
576  if ( !IsDeterministic(rGenCand) || !IsDeterministic(rGenPlant)) {
577  std::stringstream errstr;
578  errstr << "Arguments are expected to be deterministic.";
579  throw Exception("IsBuechiRelativelyMarked", errstr.str(), 202);
580  }
581 #endif
582 
583 
584  // perform composition
585  std::map< std::pair<Idx,Idx> , Idx> revmap;
586  Generator product;
587  product.StateNamesEnabled(false);
588  StateSet markCand;
589  StateSet markPlant;
590  Product(rGenPlant,rGenCand,revmap,markPlant,markCand,product);
591 
592  // find all relevant SCCs
594  markCand,markPlant);
595  std::list<StateSet> umsccs;
596  StateSet umroots;
597  ComputeScc(product,umfilter,umsccs,umroots);
598 
599  // report
600  std::list<StateSet>::iterator ssit=umsccs.begin();
601  for(;ssit!=umsccs.end(); ++ssit) {
602  FD_DF("IsBuechiRelativelyMarked(): GPlant-marked scc without GCand-mark: " << ssit->ToString());
603  }
604 
605  // result is true if no problematic SCCs exist
606  return umsccs.size()==0;
607 
608 
609 }
610 
611 
612 
613 
614 // IsOmegaRelativelyClosed(rGenPlant,rGenCand)
615 bool IsBuechiRelativelyClosed(const Generator& rGenPlant, const Generator& rGenCand) {
616 
617 
618  FD_DF("IsBuechiRelativelyClosed(\"" << rGenPlant.Name() << "\", \"" << rGenCand.Name() << "\")");
619 
620  // alphabets must match
621  if ( rGenPlant.Alphabet() != rGenCand.Alphabet()) {
622  std::stringstream errstr;
623  errstr << "Alphabets of generators do not match.";
624  throw Exception("BuechiRelativelyClosed", errstr.str(), 100);
625  }
626 
627 #ifdef FAUDES_CHECKED
628  // generators are meant to be nonblocking
629  if( !IsBuechiTrim(rGenCand) ) {
630  std::stringstream errstr;
631  errstr << "Argument \"" << rGenCand.Name() << "\" is not omegatrim.";
632  throw Exception("IsBuechiRelativelyClosed", errstr.str(), 201);
633  }
634  if( !IsBuechiTrim(rGenPlant) ) {
635  std::stringstream errstr;
636  errstr << "Argument \"" << rGenPlant.Name() << "\" is not omega-trim.";
637  throw Exception("IsBuechiRelativelyClosed", errstr.str(), 201);
638  }
639 #endif
640 
641 
642  // the trivial case: if B1 is empty it is relatively closed
643  // (we must treat this case because empty generators are not regarded deterministic)
644  if(rGenCand.Empty()) {
645  FD_DF("IsBuechiRelativelyClosed(..): empty candidate: pass");
646  return true;
647  }
648 
649  // the trivial case: if B2 is empty but B1 is not empty, the test failed
650  // (we must treat this case because empty generators are not regarded deterministic)
651  if(rGenPlant.Empty()) {
652  FD_DF("IsBuechiRelativelyClosed(..): non-empty candidate. empty plant: fail");
653  return false;
654  }
655 
656 #ifdef FAUDES_CHECKED
657  // generators are meant to be deterministic
658  if ( !IsDeterministic(rGenCand) || !IsDeterministic(rGenPlant)) {
659  std::stringstream errstr;
660  errstr << "Arguments are expected to be deterministic.";
661  throw Exception("IsBuechiRelativelyClosed", errstr.str(), 202);
662  }
663 #endif
664 
665  // doit
666  return IsBuechiRelativelyClosedUnchecked(rGenPlant,rGenCand);
667 }
668 
669 
670 // IsOmegaRelativelyClosed(rGenPlant,rGenCand)
671 bool IsBuechiRelativelyClosedUnchecked(const Generator& rGenPlant, const Generator& rGenCand) {
672 
673  // perform composition (variant of cfl_parallel.cpp)
674  std::map< std::pair<Idx,Idx> , Idx> revmap;
675  Generator product;
676  product.StateNamesEnabled(false);
677  StateSet mark1;
678  StateSet mark2;
679 
680  // shared alphabet
681  product.InjectAlphabet(rGenCand.Alphabet());
682 
683  // todo stack
684  std::stack< std::pair<Idx,Idx> > todo;
685  // current pair, new pair
686  std::pair<Idx,Idx> currentstates, newstates;
687  // state
688  Idx tmpstate;
689  // iterators
690  StateSet::Iterator lit1, lit2;
691  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
692  std::map< std::pair<Idx,Idx>, Idx>::iterator rcit;
693  // sense violation of L(G1) <= L(G2)
694  bool inclusion12=true;
695 
696  // push all combinations of initial states on todo stack
697  FD_DF("IsBuechiRelativelyClosed(): Product composition A");
698  for (lit1 = rGenCand.InitStatesBegin();
699  lit1 != rGenCand.InitStatesEnd(); ++lit1) {
700  for (lit2 = rGenPlant.InitStatesBegin();
701  lit2 != rGenPlant.InitStatesEnd(); ++lit2) {
702  currentstates = std::make_pair(*lit1, *lit2);
703  todo.push(currentstates);
704  tmpstate = product.InsInitState();
705  revmap[currentstates] = tmpstate;
706  FD_DF("IsBuechiRelativelyClosed(): Product composition A: (" << *lit1 << "|" << *lit2 << ") -> "
707  << revmap[currentstates]);
708  }
709  }
710 
711  // start algorithm
712  while (! todo.empty() && inclusion12) {
713  // allow for user interrupt
714  LoopCallback();
715  // get next reachable state from todo stack
716  currentstates = todo.top();
717  todo.pop();
718  FD_DF("IsBuechiRelativelyClosed(): Product composition B: (" << currentstates.first << "|"
719  << currentstates.second << ") -> " << revmap[currentstates]);
720  // iterate over all rGenCand transitions
721  tit1 = rGenCand.TransRelBegin(currentstates.first);
722  tit1_end = rGenCand.TransRelEnd(currentstates.first);
723  tit2 = rGenPlant.TransRelBegin(currentstates.second);
724  tit2_end = rGenPlant.TransRelEnd(currentstates.second);
725  Idx curev1=0;
726  bool resolved12=true;
727  while((tit1 != tit1_end) && (tit2 != tit2_end)) {
728  // sense new event
729  if(tit1->Ev != curev1) {
730  if(!resolved12) inclusion12=false;
731  curev1=tit1->Ev;
732  resolved12=false;
733  }
734  // shared event
735  if (tit1->Ev == tit2->Ev) {
736  resolved12=true;
737  newstates = std::make_pair(tit1->X2, tit2->X2);
738  // add to todo list if composition state is new
739  rcit = revmap.find(newstates);
740  if (rcit == revmap.end()) {
741  todo.push(newstates);
742  tmpstate = product.InsState();
743  revmap[newstates] = tmpstate;
744  FD_DF("IsBuechiRelativelyClosed(): Product composition C: (" << newstates.first << "|"
745  << newstates.second << ") -> " << revmap[newstates]);
746  }
747  else {
748  tmpstate = rcit->second;
749  }
750  product.SetTransition(revmap[currentstates], tit1->Ev, tmpstate);
751  ++tit1;
752  ++tit2;
753  }
754  // try resync tit1
755  else if (tit1->Ev < tit2->Ev) {
756  ++tit1;
757  }
758  // try resync tit2
759  else if (tit1->Ev > tit2->Ev) {
760  ++tit2;
761  }
762  }
763  // last event was not resolved in the product
764  if(!resolved12) inclusion12=false;
765  }
766  // report
767 #ifdef FAUDES_DEBUG_FUNCTION
768  FD_DF("IsBuechiRelativelyClosed(): Product: done");
769  if(!inclusion12) {
770  FD_DF("IsBuechiRelativelyClosed(): Product: inclusion L(G1) <= L(G2) not satisfied");
771  }
772 #endif
773 
774  // bail out
775  if(!inclusion12) return false;
776 
777  // retrieve marking from reverse composition map
778  std::map< std::pair<Idx,Idx>, Idx>::iterator rit;
779  for(rit=revmap.begin(); rit!=revmap.end(); ++rit){
780  if(rGenCand.ExistsMarkedState(rit->first.first)) mark1.Insert(rit->second);
781  if(rGenPlant.ExistsMarkedState(rit->first.second)) mark2.Insert(rit->second);
782  }
783 
784  // find all relevant SCCs 1
786  mark1,mark2);
787  std::list<StateSet> umsccs12;
788  StateSet umroots12;
789  ComputeScc(product,umfilter12,umsccs12,umroots12);
790 
791  // report
792  std::list<StateSet>::iterator ssit=umsccs12.begin();
793  for(;ssit!=umsccs12.end(); ++ssit) {
794  FD_DF("IsBuechiRelativelyClosed(): G2-marked scc without G1-mark: " << ssit->ToString());
795  }
796 
797  // result is false if we found problematic SCCs to exist
798  if(umsccs12.size()!=0) return false;
799 
800  // find all relevant SCCs 2
802  mark2,mark1);
803  std::list<StateSet> umsccs21;
804  StateSet umroots21;
805  ComputeScc(product,umfilter21,umsccs21,umroots21);
806 
807  // report
808  ssit=umsccs21.begin();
809  for(;ssit!=umsccs21.end(); ++ssit) {
810  FD_DF("IsBuechiRelativelyClosed(): G1-marked scc without G2-mark: " << ssit->ToString());
811  }
812 
813  // result is false if we found problematic SCCs to exist
814  if(umsccs21.size()!=0) return false;
815 
816  // done, all tests passed
817  FD_DF("IsBuechiRelativelyClosed(): pass");
818  return true;
819 }
820 
821 
822 
823 } // namespace faudes
824 
#define FD_DF(message)
const std::string & Name(void) const
Definition: cfl_types.cpp:422
bool Exists(const Idx &rIndex) const
std::string Str(const Idx &rIndex) const
bool operator<(const OPState &other) const
OPState(const Idx &rq1, const Idx &rq2, const bool &rf)
std::string Str(void)
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Definition: cfl_types.cpp:175
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)
std::string MarkedStatesToString(void) const
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
bool IsAccessible(void) const
void InsEvents(const EventSet &events)
bool IsComplete(void) const
virtual vGenerator * New(void) const
void InjectMarkedStates(const StateSet &rNewMarkedStates)
StateSet AccessibleSet(void) const
bool ExistsState(Idx index) const
bool IsCoaccessible(void) const
std::string TStr(const Transition &rTrans) const
std::string StateName(Idx index) const
TransSet::Iterator TransRelEnd(void) const
StateSet TerminalStates(void) const
void SetMarkedState(Idx index)
bool Empty(void) const
virtual void EventAttributes(const EventSet &rEventSet)
bool StateNamesEnabled(void) const
StateSet::Iterator InitStatesEnd(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:1787
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2180
Iterator End(void) const
Definition: cfl_baseset.h:1956
virtual void InsertSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2052
bool EqualAttributes(const TBaseSet &rOtherSet) const
Definition: cfl_baseset.h:2261
Iterator Begin(void) const
Definition: cfl_baseset.h:1951
virtual void EraseSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2107
Idx Size(void) const
Definition: cfl_baseset.h:1782
bool ComputeScc(const Generator &rGen, const SccFilter &rFilter, std::list< StateSet > &rSccList, StateSet &rRoots)
void Product(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
bool IsDeterministic(const vGenerator &rGen)
void aBuechiProduct(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void BuechiProduct(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void BuechiParallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void aBuechiParallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
bool BuechiTrim(vGenerator &rGen)
void BuechiClosure(Generator &rGen)
bool IsBuechiClosed(const Generator &rGen)
bool IsBuechiRelativelyClosed(const Generator &rGenPlant, const Generator &rGenCand)
bool IsBuechiRelativelyMarked(const Generator &rGenPlant, const Generator &rGenCand)
uint32_t Idx
void LoopCallback(bool pBreak(void))
Definition: cfl_utils.cpp:679
bool IsBuechiTrim(const vGenerator &rGen)
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91
bool IsBuechiRelativelyClosedUnchecked(const Generator &rGenPlant, const Generator &rGenCand)

libFAUDES 2.33h --- 2025.06.18 --- c++ api documentaion by doxygen