omg_buechifnct.cpp
Go to the documentation of this file.
1/** @file omg_buechifnct.cpp
2
3Operations regarding omega languages accepted by Buechi automata
4
5*/
6
7/* FAU Discrete Event Systems Library (libfaudes)
8
9Copyright (C) 2010, 2025 Thomas Moor
10
11This library is free software; you can redistribute it and/or
12modify it under the terms of the GNU Lesser General Public
13License as published by the Free Software Foundation; either
14version 2.1 of the License, or (at your option) any later version.
15
16This library is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19Lesser General Public License for more details.
20
21You should have received a copy of the GNU Lesser General Public
22License along with this library; if not, write to the Free Software
23Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
24
25
26
27#include "omg_buechifnct.h"
28
29
30namespace faudes {
31
32// BuechiTrim
33// (return True if resulting contains at least one initial state and at least one mark)
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
54bool BuechiTrim(const vGenerator& rGen, vGenerator& rRes) {
55 rRes=rGen;
56 return BuechiTrim(rRes);
57}
58
59// IsBuechiTrim()
60bool 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)
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
84bool 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
137class OPState {
138public:
139 // minimal interface
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
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)
553bool 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// IsOmegaRelativelyClosed(rGenPlant,rGenCand)
614bool IsBuechiRelativelyClosed(const Generator& rGenPlant, const Generator& rGenCand) {
615
616
617 FD_DF("IsBuechiRelativelyClosed(\"" << rGenPlant.Name() << "\", \"" << rGenCand.Name() << "\")");
618
619 // alphabets must match
620 if ( rGenPlant.Alphabet() != rGenCand.Alphabet()) {
621 std::stringstream errstr;
622 errstr << "Alphabets of generators do not match.";
623 throw Exception("BuechiRelativelyClosed", errstr.str(), 100);
624 }
625
626#ifdef FAUDES_CHECKED
627 // generators are meant to be nonblocking
628 if( !IsBuechiTrim(rGenCand) ) {
629 std::stringstream errstr;
630 errstr << "Argument \"" << rGenCand.Name() << "\" is not omegatrim.";
631 throw Exception("IsBuechiRelativelyClosed", errstr.str(), 201);
632 }
633 if( !IsBuechiTrim(rGenPlant) ) {
634 std::stringstream errstr;
635 errstr << "Argument \"" << rGenPlant.Name() << "\" is not omega-trim.";
636 throw Exception("IsBuechiRelativelyClosed", errstr.str(), 201);
637 }
638#endif
639
640
641 // the trivial case: if B1 is empty it is relatively closed
642 // (we must treat this case because empty generators are not regarded deterministic)
643 if(rGenCand.Empty()) {
644 FD_DF("IsBuechiRelativelyClosed(..): empty candidate: pass");
645 return true;
646 }
647
648 // the trivial case: if B2 is empty but B1 is not empty, the test failed
649 // (we must treat this case because empty generators are not regarded deterministic)
650 if(rGenPlant.Empty()) {
651 FD_DF("IsBuechiRelativelyClosed(..): non-empty candidate. empty plant: fail");
652 return false;
653 }
654
655#ifdef FAUDES_CHECKED
656 // generators are meant to be deterministic
657 if ( !IsDeterministic(rGenCand) || !IsDeterministic(rGenPlant)) {
658 std::stringstream errstr;
659 errstr << "Arguments are expected to be deterministic.";
660 throw Exception("IsBuechiRelativelyClosed", errstr.str(), 202);
661 }
662#endif
663
664 // doit
665 return IsBuechiRelativelyClosedUnchecked(rGenPlant,rGenCand);
666}
667
668
669// IsOmegaRelativelyClosed(rGenPlant,rGenCand)
670bool IsBuechiRelativelyClosedUnchecked(const Generator& rGenPlant, const Generator& rGenCand) {
671
672 // perform composition (variant of cfl_parallel.cpp)
673 std::map< std::pair<Idx,Idx> , Idx> revmap;
674 Generator product;
675 product.StateNamesEnabled(false);
676 StateSet mark1;
677 StateSet mark2;
678
679 // shared alphabet
680 product.InjectAlphabet(rGenCand.Alphabet());
681
682 // todo stack
683 std::stack< std::pair<Idx,Idx> > todo;
684 // current pair, new pair
685 std::pair<Idx,Idx> currentstates, newstates;
686 // state
687 Idx tmpstate;
688 // iterators
689 StateSet::Iterator lit1, lit2;
690 TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
691 std::map< std::pair<Idx,Idx>, Idx>::iterator rcit;
692 // sense violation of L(GenCand) <= L(GenPlant)
693 bool inclusion12=true;
694
695 // push all combinations of initial states on todo stack
696 FD_DF("IsBuechiRelativelyClosed(): Product composition A");
697 for (lit1 = rGenCand.InitStatesBegin();
698 lit1 != rGenCand.InitStatesEnd(); ++lit1) {
699 for (lit2 = rGenPlant.InitStatesBegin();
700 lit2 != rGenPlant.InitStatesEnd(); ++lit2) {
701 currentstates = std::make_pair(*lit1, *lit2);
702 todo.push(currentstates);
703 tmpstate = product.InsInitState();
704 revmap[currentstates] = tmpstate;
705 FD_DF("IsBuechiRelativelyClosed(): Product composition A: (" << *lit1 << "|" << *lit2 << ") -> "
706 << revmap[currentstates]);
707 }
708 }
709
710 // start algorithm
711 while (! todo.empty() && inclusion12) {
712 // allow for user interrupt
713 LoopCallback();
714 // get next reachable state from todo stack
715 currentstates = todo.top();
716 todo.pop();
717 FD_DF("IsBuechiRelativelyClosed(): Product composition B: (" << currentstates.first << "|"
718 << currentstates.second << ") -> " << revmap[currentstates]);
719 // iterate over all rGenCand transitions
720 tit1 = rGenCand.TransRelBegin(currentstates.first);
721 tit1_end = rGenCand.TransRelEnd(currentstates.first);
722 tit2 = rGenPlant.TransRelBegin(currentstates.second);
723 tit2_end = rGenPlant.TransRelEnd(currentstates.second);
724 Idx curev1=0;
725 bool resolved12=true;
726 while((tit1 != tit1_end) && (tit2 != tit2_end)) {
727 // sense new event
728 if(tit1->Ev != curev1) {
729 if(!resolved12) inclusion12=false;
730 curev1=tit1->Ev;
731 resolved12=false;
732 }
733 // shared event
734 if (tit1->Ev == tit2->Ev) {
735 resolved12=true;
736 newstates = std::make_pair(tit1->X2, tit2->X2);
737 // add to todo list if composition state is new
738 rcit = revmap.find(newstates);
739 if (rcit == revmap.end()) {
740 todo.push(newstates);
741 tmpstate = product.InsState();
742 revmap[newstates] = tmpstate;
743 FD_DF("IsBuechiRelativelyClosed(): Product composition C: (" << newstates.first << "|"
744 << newstates.second << ") -> " << revmap[newstates]);
745 }
746 else {
747 tmpstate = rcit->second;
748 }
749 product.SetTransition(revmap[currentstates], tit1->Ev, tmpstate);
750 ++tit1;
751 ++tit2;
752 }
753 // try resync tit1
754 else if (tit1->Ev < tit2->Ev) {
755 ++tit1;
756 }
757 // try resync tit2
758 else if (tit1->Ev > tit2->Ev) {
759 ++tit2;
760 }
761 }
762 // last event was not resolved in the product
763 if(!resolved12) inclusion12=false;
764 }
765 // report
766#ifdef FAUDES_DEBUG_FUNCTION
767 FD_DF("IsBuechiRelativelyClosed(): Product: done");
768 if(!inclusion12) {
769 FD_DF("IsBuechiRelativelyClosed(): Product: inclusion L(GenCand) <= L(GenPlant) not satisfied");
770 }
771#endif
772
773 // bail out
774 if(!inclusion12) return false;
775
776 // retrieve marking from reverse composition map
777 std::map< std::pair<Idx,Idx>, Idx>::iterator rit;
778 for(rit=revmap.begin(); rit!=revmap.end(); ++rit){
779 if(rGenCand.ExistsMarkedState(rit->first.first)) mark1.Insert(rit->second);
780 if(rGenPlant.ExistsMarkedState(rit->first.second)) mark2.Insert(rit->second);
781 }
782
783 // find all relevant SCCs 1
785 mark1,mark2);
786 std::list<StateSet> umsccs12;
787 StateSet umroots12;
788 ComputeScc(product,umfilter12,umsccs12,umroots12);
789
790 // report
791 std::list<StateSet>::iterator ssit=umsccs12.begin();
792 for(;ssit!=umsccs12.end(); ++ssit) {
793 FD_DF("IsBuechiRelativelyClosed(): G2-marked scc without G1-mark: " << ssit->ToString());
794 }
795
796 // result is false if we found problematic SCCs to exist
797 if(umsccs12.size()!=0) return false;
798
799 // find all relevant SCCs 2
801 mark2,mark1);
802 std::list<StateSet> umsccs21;
803 StateSet umroots21;
804 ComputeScc(product,umfilter21,umsccs21,umroots21);
805
806 // report
807 ssit=umsccs21.begin();
808 for(;ssit!=umsccs21.end(); ++ssit) {
809 FD_DF("IsBuechiRelativelyClosed(): G1-marked scc without G2-mark: " << ssit->ToString());
810 }
811
812 // result is false if we found problematic SCCs to exist
813 if(umsccs21.size()!=0) return false;
814
815 // done, all tests passed
816 FD_DF("IsBuechiRelativelyClosed(): pass");
817 return true;
818}
819
820
821// LanguageInclusion
822bool BuechiLanguageInclusion(const Generator& rGen1, const Generator& rGen2) {
823
824 FD_DF("BuechiLanguageInclusion(\"" << rGen1.Name() << "\", \"" << rGen2.Name() << "\")");
825
826 // alphabets must match
827 if ( rGen1.Alphabet() != rGen2.Alphabet()) {
828 std::stringstream errstr;
829 errstr << "Alphabets of generators do not match.";
830 throw Exception("BuechiLanguageInclusion", errstr.str(), 100);
831 }
832
833#ifdef FAUDES_CHECKED
834 // generators are meant to be nonblocking
835 if( !IsBuechiTrim(rGen1) ) {
836 std::stringstream errstr;
837 errstr << "Argument \"" << rGen1.Name() << "\" is not omegatrim.";
838 throw Exception("BuechiLanguageInclusion", errstr.str(), 201);
839 }
840 if( !IsBuechiTrim(rGen2) ) {
841 std::stringstream errstr;
842 errstr << "Argument \"" << rGen2.Name() << "\" is not omega-trim.";
843 throw Exception("BuechiLanguageInclusion", errstr.str(), 201);
844 }
845#endif
846
847 // the trivial case: if B1 is empty it is relatively closed
848 // (we must treat this case because empty generators are not regarded deterministic)
849 if(rGen1.Empty()) {
850 FD_DF("BuechiLanguageInclusion(..): empty candidate: pass");
851 return true;
852 }
853
854 // the trivial case: if B2 is empty but B1 is not empty, the test failed
855 // (we must treat this case because empty generators are not regarded deterministic)
856 if(rGen2.Empty()) {
857 FD_DF("BuechiLanguageInclusion(..): non-empty candidate. empty plant: fail");
858 return false;
859 }
860
861#ifdef FAUDES_CHECKED
862 // generators are meant to be deterministic
863 if ( !IsDeterministic(rGen1) || !IsDeterministic(rGen2)) {
864 std::stringstream errstr;
865 errstr << "Arguments are expected to be deterministic.";
866 throw Exception("BuechiLanguageInclusion", errstr.str(), 202);
867 }
868#endif
869
870 // perform composition (variant of cfl_parallel.cpp)
871 std::map< std::pair<Idx,Idx> , Idx> revmap;
872 Generator product;
873 product.StateNamesEnabled(false);
874 StateSet mark1;
875 StateSet mark2;
876
877 // shared alphabet
878 product.InjectAlphabet(rGen1.Alphabet());
879
880 // todo stack
881 std::stack< std::pair<Idx,Idx> > todo;
882 // current pair, new pair
883 std::pair<Idx,Idx> currentstates, newstates;
884 // state
885 Idx tmpstate;
886 // iterators
887 StateSet::Iterator lit1, lit2;
888 TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
889 std::map< std::pair<Idx,Idx>, Idx>::iterator rcit;
890 // sense violation of L(Gen1) <= L(Gen2)
891 bool inclusion12=true;
892
893 // push all combinations of initial states on todo stack
894 FD_DF("BuechiLanguageInclusion(): Product composition A");
895 for (lit1 = rGen1.InitStatesBegin();
896 lit1 != rGen1.InitStatesEnd(); ++lit1) {
897 for (lit2 = rGen2.InitStatesBegin();
898 lit2 != rGen2.InitStatesEnd(); ++lit2) {
899 currentstates = std::make_pair(*lit1, *lit2);
900 todo.push(currentstates);
901 tmpstate = product.InsInitState();
902 revmap[currentstates] = tmpstate;
903 FD_DF("BuechiLanguageInclusion(): Product composition A: (" << *lit1 << "|" << *lit2 << ") -> "
904 << revmap[currentstates]);
905 }
906 }
907
908 // start algorithm
909 while (! todo.empty() && inclusion12) {
910 // allow for user interrupt
911 LoopCallback();
912 // get next reachable state from todo stack
913 currentstates = todo.top();
914 todo.pop();
915 FD_DF("BuechiLanguageInclusion(): Product composition B: (" << currentstates.first << "|"
916 << currentstates.second << ") -> " << revmap[currentstates]);
917 // iterate over all rGenCand transitions
918 tit1 = rGen1.TransRelBegin(currentstates.first);
919 tit1_end = rGen1.TransRelEnd(currentstates.first);
920 tit2 = rGen2.TransRelBegin(currentstates.second);
921 tit2_end = rGen2.TransRelEnd(currentstates.second);
922 Idx curev1=0;
923 bool resolved12=true;
924 while((tit1 != tit1_end) && (tit2 != tit2_end)) {
925 // sense new event
926 if(tit1->Ev != curev1) {
927 if(!resolved12) inclusion12=false;
928 curev1=tit1->Ev;
929 resolved12=false;
930 }
931 // shared event
932 if (tit1->Ev == tit2->Ev) {
933 resolved12=true;
934 newstates = std::make_pair(tit1->X2, tit2->X2);
935 // add to todo list if composition state is new
936 rcit = revmap.find(newstates);
937 if (rcit == revmap.end()) {
938 todo.push(newstates);
939 tmpstate = product.InsState();
940 revmap[newstates] = tmpstate;
941 FD_DF("BuechiLanguageInclusion(): Product composition C: (" << newstates.first << "|"
942 << newstates.second << ") -> " << revmap[newstates]);
943 }
944 else {
945 tmpstate = rcit->second;
946 }
947 product.SetTransition(revmap[currentstates], tit1->Ev, tmpstate);
948 ++tit1;
949 ++tit2;
950 }
951 // try resync tit1
952 else if (tit1->Ev < tit2->Ev) {
953 ++tit1;
954 }
955 // try resync tit2
956 else if (tit1->Ev > tit2->Ev) {
957 ++tit2;
958 }
959 }
960 // last event was not resolved in the product
961 if(!resolved12) inclusion12=false;
962 }
963 // report
964#ifdef FAUDES_DEBUG_FUNCTION
965 FD_DF("BuechiLanguageInclusion(): Product: done");
966 if(!inclusion12) {
967 FD_DF("BuechiLanguageInclusion(): Product: inclusion L(Gen1) <= L(Gen2) not satisfied");
968 }
969#endif
970
971 // bail out
972 if(!inclusion12) return false;
973
974 // retrieve marking from reverse composition map
975 std::map< std::pair<Idx,Idx>, Idx>::iterator rit;
976 for(rit=revmap.begin(); rit!=revmap.end(); ++rit){
977 if(rGen1.ExistsMarkedState(rit->first.first)) mark1.Insert(rit->second);
978 if(rGen2.ExistsMarkedState(rit->first.second)) mark2.Insert(rit->second);
979 }
980
981 // find all relevant SCCs
983 mark2,mark1);
984 std::list<StateSet> umsccs21;
985 StateSet umroots21;
986 ComputeScc(product,umfilter21,umsccs21,umroots21);
987
988 // report
989 std::list<StateSet>::iterator ssit=umsccs21.begin();
990 for(;ssit!=umsccs21.end(); ++ssit) {
991 FD_DF("BuechiLanguageInclusion(): G1-marked scc without G2-mark: " << ssit->ToString());
992 }
993
994 // result is false if we found problematic SCCs to exist
995 if(umsccs21.size()!=0) return false;
996
997 // done, all tests passed
998 FD_DF("BuechiLanguageInclusion(): pass");
999 return true;
1000}
1001
1002
1003// LanguageEquality
1004bool BuechiLanguageEquality(const Generator& rGen1, const Generator& rGen2) {
1005
1006 FD_DF("BuechiLanguageEquality(\"" << rGen1.Name() << "\", \"" << rGen2.Name() << "\")");
1007
1008 // alphabets must match
1009 if ( rGen1.Alphabet() != rGen2.Alphabet()) {
1010 std::stringstream errstr;
1011 errstr << "Alphabets of generators do not match.";
1012 throw Exception("BuechiLanguageEquality", errstr.str(), 100);
1013 }
1014
1015#ifdef FAUDES_CHECKED
1016 // generators are meant to be nonblocking
1017 if( !IsBuechiTrim(rGen1) ) {
1018 std::stringstream errstr;
1019 errstr << "Argument \"" << rGen1.Name() << "\" is not omegatrim.";
1020 throw Exception("BuechiLanguageEquality", errstr.str(), 201);
1021 }
1022 if( !IsBuechiTrim(rGen2) ) {
1023 std::stringstream errstr;
1024 errstr << "Argument \"" << rGen2.Name() << "\" is not omega-trim.";
1025 throw Exception("BuechiLanguageEquality", errstr.str(), 201);
1026 }
1027#endif
1028
1029
1030 // the trivial case: both are empty, or one is empty and one not
1031 // (we must treat this case because empty generators are not regarded deterministic)
1032 bool empty1=rGen1.Empty();
1033 bool empty2=rGen2.Empty();
1034 if( empty1 && empty2) {
1035 FD_DF("BuechiLanguageEquality(..): empty candidates: pass");
1036 return true;
1037 }
1038 if( empty1 != empty2) {
1039 FD_DF("BuechiLanguageEquality(..): empty/non-empty candidates: fail");
1040 return false;
1041 }
1042
1043#ifdef FAUDES_CHECKED
1044 // generators are meant to be deterministic
1045 if ( !IsDeterministic(rGen1) || !IsDeterministic(rGen2)) {
1046 std::stringstream errstr;
1047 errstr << "Arguments are expected to be deterministic.";
1048 throw Exception("BuechiLanguageEquality", errstr.str(), 202);
1049 }
1050#endif
1051
1052 // perform composition (variant of cfl_parallel.cpp)
1053 std::map< std::pair<Idx,Idx> , Idx> revmap;
1054 Generator product;
1055 product.StateNamesEnabled(false);
1056 StateSet mark1;
1057 StateSet mark2;
1058
1059 // shared alphabet
1060 product.InjectAlphabet(rGen1.Alphabet());
1061
1062 // todo stack
1063 std::stack< std::pair<Idx,Idx> > todo;
1064 // current pair, new pair
1065 std::pair<Idx,Idx> currentstates, newstates;
1066 // state
1067 Idx tmpstate;
1068 // iterators
1069 StateSet::Iterator lit1, lit2;
1070 TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
1071 std::map< std::pair<Idx,Idx>, Idx>::iterator rcit;
1072 // sense violation of L(Gen1) = L(Gen2)
1073 bool equal12=true;
1074
1075 // push all combinations of initial states on todo stack
1076 FD_DF("BuechiLanguageEquality(): Product composition A");
1077 for (lit1 = rGen1.InitStatesBegin();
1078 lit1 != rGen1.InitStatesEnd(); ++lit1) {
1079 for (lit2 = rGen2.InitStatesBegin();
1080 lit2 != rGen2.InitStatesEnd(); ++lit2) {
1081 currentstates = std::make_pair(*lit1, *lit2);
1082 todo.push(currentstates);
1083 tmpstate = product.InsInitState();
1084 revmap[currentstates] = tmpstate;
1085 FD_DF("BuechiLanguageEquality(): Product composition A: (" << *lit1 << "|" << *lit2 << ") -> "
1086 << revmap[currentstates]);
1087 }
1088 }
1089
1090 // start algorithm
1091 while (! todo.empty() && equal12) {
1092 // allow for user interrupt
1093 LoopCallback();
1094 // get next reachable state from todo stack
1095 currentstates = todo.top();
1096 todo.pop();
1097 FD_DF("BuechiLanguageEquality(): Product composition B: (" << currentstates.first << "|"
1098 << currentstates.second << ") -> " << revmap[currentstates]);
1099 // iterate over all rGen1, rGen2 transitions
1100 tit1 = rGen1.TransRelBegin(currentstates.first);
1101 tit1_end = rGen1.TransRelEnd(currentstates.first);
1102 tit2 = rGen2.TransRelBegin(currentstates.second);
1103 tit2_end = rGen2.TransRelEnd(currentstates.second);
1104 while((tit1 != tit1_end) && (tit2 != tit2_end)) {
1105 // event mismatch
1106 if (tit1->Ev != tit2->Ev) {
1107 equal12=false;
1108 break;
1109 }
1110 // matching event
1111 newstates = std::make_pair(tit1->X2, tit2->X2);
1112 // add to todo list if composition state is new
1113 rcit = revmap.find(newstates);
1114 if (rcit == revmap.end()) {
1115 todo.push(newstates);
1116 tmpstate = product.InsState();
1117 revmap[newstates] = tmpstate;
1118 FD_DF("BuechiLanguageEquality(): Product composition C: (" << newstates.first << "|"
1119 << newstates.second << ") -> " << revmap[newstates]);
1120 } else {
1121 tmpstate = rcit->second;
1122 }
1123 product.SetTransition(revmap[currentstates], tit1->Ev, tmpstate);
1124 ++tit1;
1125 ++tit2;
1126 }
1127 }
1128 // report
1129#ifdef FAUDES_DEBUG_FUNCTION
1130 FD_DF("BuechiLanguageEquality(): Product: done");
1131 if(!equal12) {
1132 FD_DF("BuechiLanguageEquality(): Product: inclusion L(Gen1) == L(Gen2) not satisfied");
1133 }
1134#endif
1135
1136 // bail out
1137 if(!equal12) return false;
1138
1139 // retrieve marking from reverse composition map
1140 std::map< std::pair<Idx,Idx>, Idx>::iterator rit;
1141 for(rit=revmap.begin(); rit!=revmap.end(); ++rit){
1142 if(rGen1.ExistsMarkedState(rit->first.first)) mark1.Insert(rit->second);
1143 if(rGen2.ExistsMarkedState(rit->first.second)) mark2.Insert(rit->second);
1144 }
1145
1146 // find all relevant SCCs 1
1148 mark2,mark1);
1149 std::list<StateSet> umsccs12;
1150 StateSet umroots12;
1151 ComputeScc(product,umfilter12,umsccs12,umroots12);
1152
1153 // report
1154 std::list<StateSet>::iterator ssit=umsccs12.begin();
1155 for(;ssit!=umsccs12.end(); ++ssit) {
1156 FD_DF("BuechiLanguageEquality(): G1-marked scc without G2-mark: " << ssit->ToString());
1157 }
1158
1159 // result is false if we found problematic SCCs to exist
1160 if(umsccs12.size()!=0) return false;
1161
1162 // find all relevant SCCs 2
1164 mark1,mark2);
1165 std::list<StateSet> umsccs21;
1166 StateSet umroots21;
1167 ComputeScc(product,umfilter21,umsccs21,umroots21);
1168
1169 // report
1170 ssit=umsccs21.begin();
1171 for(;ssit!=umsccs21.end(); ++ssit) {
1172 FD_DF("BuechiLanguageEquality(): G2-marked scc without G1-mark: " << ssit->ToString());
1173 }
1174
1175 // result is false if we found problematic SCCs to exist
1176 if(umsccs21.size()!=0) return false;
1177
1178 // done, all tests passed
1179 FD_DF("BuechiLanguageEquality(): pass");
1180 return true;
1181}
1182
1183
1184
1185} // namespace faudes
1186
#define FD_DF(message)
const std::string & Name(void) const
bool Exists(const Idx &rIndex) const
virtual 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)
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
StateSet::Iterator InitStatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
virtual void Move(vGenerator &rGen)
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
bool Exists(const T &rElem) const
Iterator End(void) const
virtual void InsertSet(const TBaseSet &rOtherSet)
bool EqualAttributes(const TBaseSet &rOtherSet) const
Iterator Begin(void) const
virtual void EraseSet(const TBaseSet &rOtherSet)
Idx Size(void) const
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)
uint32_t Idx
void LoopCallback(void)
bool BuechiLanguageInclusion(const Generator &rGen1, const Generator &rGen2)
bool BuechiLanguageEquality(const Generator &rGen1, const Generator &rGen2)
bool IsBuechiTrim(const vGenerator &rGen)
bool IsBuechiRelativelyClosed(const Generator &rGenPlant, const Generator &rGenCand)
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:43
bool IsBuechiRelativelyMarked(const Generator &rGenPlant, const Generator &rGenCand)
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen