omg_buechictrl.cpp
Go to the documentation of this file.
1 /** @file omg_buechictrl.cpp Supremal controllable sublanguage w.r.t. Buechi acceptance */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2010, 2025 Thomas Moor
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
20 
21 
22 //#define FAUDES_DEBUG_FUNCTION
23 
24 #include "omg_include.h"
25 #include "syn_include.h"
26 
27 
28 namespace faudes {
29 
30 
31 /*
32 ***************************************************************************************
33 ***************************************************************************************
34  Implementation IsBuechiControllabe
35 ***************************************************************************************
36 ***************************************************************************************
37 */
38 
39 // IsBuechiControllable()
41  const Generator& rGenPlant,
42  const EventSet& rCAlph,
43  const Generator& rGenCand)
44 {
45  FD_DF("IsBuechiControllable(\"" << rGenPlant.Name() << "\", \"" << rGenCand.Name() << "\")");
46 
47  // alphabets must match
48  if ( rGenPlant.Alphabet() != rGenCand.Alphabet()) {
49  std::stringstream errstr;
50  errstr << "Alphabets of generators do not match.";
51  throw Exception("IsBuechiControllable(..)", errstr.str(), 100);
52  }
53 
54 #ifdef FAUDES_CHECKED
55  // generators are meant to be nonblocking
56  if( !IsBuechiTrim(rGenCand) ) {
57  std::stringstream errstr;
58  errstr << "Argument \"" << rGenCand.Name() << "\" is not omega-trim.";
59  throw Exception("IsBuechiControllable(..)", errstr.str(), 201);
60  }
61  if( !IsBuechiTrim(rGenPlant) ) {
62  std::stringstream errstr;
63  errstr << "Argument \"" << rGenPlant.Name() << "\" is not omega-trim.";
64  throw Exception("IsBuechiControllable(..)", errstr.str(), 201);
65  }
66 #endif
67 
68  // the trivial case: empty cand is fine
69  // (we must treat this case because empty generators are not regarded deterministic)
70  if(rGenCand.Empty()) {
71  FD_DF("IsBuechiControllable(..): empty candidate, pass");
72  return true;
73  }
74 
75  // the trivial case: empty plant is fails
76  // (we must treat this case because empty generators are not regarded deterministic)
77  if(rGenPlant.Empty()) {
78  FD_DF("IsBuechiControllable(..): empty plant, fail");
79  return false;
80  }
81 
82 #ifdef FAUDES_CHECKED
83  // generators are meant to be deterministic
84  if ( !IsDeterministic(rGenCand) || !IsDeterministic(rGenPlant)) {
85  std::stringstream errstr;
86  errstr << "Arguments are expected to be deterministic.";
87  throw Exception("IsBuechiControllable", errstr.str(), 202);
88  }
89 #endif
90 
91  // test controllability
92  StateSet dummy;
93  if(!IsControllableUnchecked(rGenPlant,rCAlph,rGenCand,dummy)) return false;
94 
95  // test relative closedness
96  if(!IsBuechiRelativelyClosedUnchecked(rGenPlant,rGenCand)) return false;
97 
98  // pass
99  FD_DF("IsBuechiControllable(...): passed");
100  return true;
101 }
102 
103 
104 // IsBuechiControllable() wrapper
106  const System& rPlantGen,
107  const Generator& rCandGen)
108 {
109  return IsBuechiControllable(rPlantGen,rPlantGen.ControllableEvents(),rCandGen);
110 }
111 
112 /*
113 ***************************************************************************************
114 ***************************************************************************************
115  Computation of the controllable prefix / enforcing omega-controlled liveness
116 ***************************************************************************************
117 ***************************************************************************************
118 */
119 
120 
121 
122 /*
123 Initial libFAUDES implementation of omega-controlled liveness, tmoor 2011, last used
124 for libFAUDES 2.22p. The function retsricts the candidate to states for which a
125 prefix-closed controller exists such that in closed-loop configuration the acceptance condition
126 is implied by the plant acceptance condition. This corresponds to the controllable prefix,
127 originally proposed by J. Thistle et al. The actual implementation, however, is based on a sufficient
128 but not necessary test. It therefore identifies a subset of the controllable prefix, which may
129 turn out empty even when a prefix-closed controller exists. The below code is obsolete and will
130 be removed eventually.
131 */
132 
133 /*
134 
135 // ControlledBuechiLiveness(...)
136 bool ControlledBuechiLiveness(
137  Generator& rSupCandGen,
138  const EventSet& rCAlph,
139  StateSet& rMarkedPlantStates,
140  StateSet& rMarkedSpecStates)
141 {
142  FD_DF("ControlledBuechiLiveness(...)");
143 
144  // set of critical states
145  StateSet critical;
146 
147  // return true if parallelcomp contains no initial states
148  if(rSupCandGen.InitStatesEmpty()) {
149  return true;
150  }
151 
152 #ifdef FAUDES_DEBUG_FUNCTION
153  FD_DF("ControlledBuechiLiveness(): marked states: ");
154  StateSet ssd= rMarkedPlantStates + rMarkedSpecStates;
155  ssd.Write();
156 #endif
157 
158  // find un-marked sccs
159  StateSet astates = rMarkedPlantStates + rMarkedSpecStates;
160  SccFilter umfilter(SccFilter::FmIgnoreTrivial | SccFilter::FmStatesAvoid, astates);
161  std::list<StateSet> umsccs;
162  StateSet umroots;
163  ComputeScc(rSupCandGen,umfilter,umsccs,umroots);
164 
165  // report
166  std::list<StateSet>::iterator ssit=umsccs.begin();
167  for(;ssit!=umsccs.end(); ++ssit) {
168  FD_DF("ControlledBuechiLiveness(): unmarked scc: " << ssit->ToString());
169  }
170 
171  // good-states iteration
172  StateSet goodstates = rMarkedSpecStates;
173 
174  // drive states to good states
175  while(true) {
176  // LoopCallback();
177  // allow for user interrupt, incl progress report
178  FD_WPC(1,2,"ControlledBuechiLiveness(): iterating states");
179  // test individual states
180  FD_DF("ControlledBuechiLiveness(): iterate over states (#" << rSupCandGen.Size() << ")");
181  bool found=false;
182 
183  StateSet::Iterator sit = rSupCandGen.StatesBegin();
184  StateSet::Iterator sit_end = rSupCandGen.StatesEnd();
185  for(; sit!=sit_end; ++sit) {
186  bool fail = false; // cbaier 20121011
187  bool positive=false; // cbaier 20121011
188  // goodstate anyway
189  if(goodstates.Exists(*sit)) continue;
190  // test transitions
191  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
192  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
193  // no transitions at all
194  if(tit==tit_end) continue;
195  // loop over successors
196  for(; tit!=tit_end; ++tit) {
197  if(goodstates.Exists(tit->X2))
198  {positive=true; // cbaier 20121011: added
199  continue;}
200  if(rCAlph.Exists(tit->Ev)) continue;
201 
202  // good states survive the loop // cbaier 20121011: added
203  if(tit!=tit_end) {
204  fail=true;
205  break;
206  }
207  }
208 
209  // good states survive
210  if(!fail && positive) { // cbaier 20121011: changed
211  FD_DF("ControlledBuechiLiveness(): good state " << rSupCandGen.SStr(*sit));
212  goodstates.Insert(*sit);
213  found=true;
214  }
215  }
216 
217  // test individual unmarked sccs
218  FD_DF("ControlledBuechiLiveness(): iterate over unmarked sccs (#" << umsccs.size() <<")");
219  std::list<StateSet>::iterator ssit=umsccs.begin();
220  while(ssit!=umsccs.end()) {
221  bool fail=false;
222  bool positive=false;
223  sit=ssit->Begin();
224  sit_end=ssit->End();
225  for(; sit!=sit_end; ++sit) {
226  // goodstate anyway
227  if(goodstates.Exists(*sit)) continue;
228  // test transitions
229  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
230  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
231  // no transitions at all
232  if(tit==tit_end) continue;
233  // loop over successors
234  for(; tit!=tit_end; ++tit) {
235  if(goodstates.Exists(tit->X2)) { positive=true; continue;}
236  if(rCAlph.Exists(tit->Ev)) continue; // tmoor 20110202: fixed typo
237  if(ssit->Exists(tit->X2)) continue;
238  break;
239  }
240  // good states survive the loop
241  if(tit!=tit_end) {
242  fail=true;
243  break;
244  }
245  }
246 
247  // prepare next scc iterator
248  std::list<StateSet>::iterator ssitnext=ssit;
249  ++ssitnext;
250  bool lend= (ssitnext==umsccs.end());
251  // all states passed, then they are all good
252  if(!fail && positive) {
253  FD_DF("ControlledBuechiLiveness(): good scc " << ssit->ToString());
254  goodstates.InsertSet(*ssit);
255  umsccs.erase(ssit);
256  found=true;
257  }
258  // break on end of list
259  if(lend) break;
260  // progress
261  ssit=ssitnext;
262  }
263 
264  // exit
265  if(!found) break;
266  };
267 
268  // delete critical states
269  FD_DF("ControlledBuechiLiveness(): good states: " << goodstates.ToString())
270  StateSet::Iterator sit = rSupCandGen.StatesBegin();
271  StateSet::Iterator sit_end = rSupCandGen.StatesEnd();
272  for(; sit!=sit_end; ++sit) {
273  if(!goodstates.Exists(*sit))
274  rSupCandGen.DelState(*sit);
275  }
276 
277  // return true
278  FD_DF("ControlledBuechiLiveness(): done");
279  return true;
280 }
281 
282 */
283 
284 
285 /*
286 This implementation is a direct transscript of the mu-calculus formulas stated in "Control of
287 w-Automata, Church's Problem, and the Emptiness Problem for Tree w-Automata", by J. Thistle and
288 W.M. Wonham, 1992, adapted for the special case of deterministic Buchi-automata. Referring to the
289 referenced literature, the corresponding iteration is "essentially optimal" in terms of performance.
290 In the below implementation, we unwind each individual mu/nu quantifiation literally and resist
291 to apply strategic substitutions in order to obtain a reference implementation. This is suspected
292 to introduce (linear) penalty for avoidable boolean operations on sets of states. In a recent study,
293 Christian Wamser proposed a fine-tuned alternative implementation which will be integrated in
294 libFAUDES in due course.
295 */
296 
298  Generator& rSupCandGen,
299  const EventSet& rCAlph,
300  const StateSet& rPlantMarking)
301 {
302 
303  FD_DF("ControlledBuechiLiveness()");
304 
305  // declare iterate sets
306  StateSet resolved, initialK, targetLstar;
307  StateSet initialL, targetL;
308  StateSet domainL, target1;
309  StateSet target, domain, theta;
310 
311  // convenience
312  const StateSet& full = rSupCandGen.States();
313  Idx fsz=full.Size();
314 
315  // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ];
316  // here, p(T) denotes the set of states that can be driven to enter T under liveness assumption inf-markL;
317  // use std. mu-nu-iteration
318  resolved.Clear();
319  while(true) {
320  Idx rsz = resolved.Size();
321  initialK = full;
322  while(true) {
323  Idx iKsz = initialK.Size();
324 
325  // prepare target for P(): targetLstar = initialK * markedK + resolved
326  targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved;
327  FD_DF("ControlledBuechiLiveness(): [STD] iterate resolved/targetLstar #" << rsz << "/" << targetLstar.Size());
328 
329  // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ]
330  // here, thetaTilde(T) denotes the set of states that can be controlled such that T is persistently
331  // reachable and markL is not passed before T is entered;
332  // start with initialL:=0 and iterate initialL += thetaTilde(targetLstar+initialL);
333  initialL.Clear();
334  while(true) {
335  Idx iLsz = initialL.Size();
336 
337  // prepare targetL=targetLstar+initialL
338  targetL=targetLstar+initialL;
339  FD_DF("ControlledBuechiLiveness(): [STD] ---- iterate targetL #" << targetL.Size());
340 
341  // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ];
342  // here, theta(T,D) is the set of states that, by one transition, can enter T and can be controlled not to exit D+T;
343  // start with domainL:=full and iterate domainL -= mu(target1)[theta(targetL+(target1-markL), domainL-markL)];
344  domainL=full;
345  targetL = targetLstar + initialL;
346  while(true) {
347  Idx dLsz = domainL.Size();
348  FD_DF("ControlledBuechiLiveness(): [STD] --- iterate domainL #" << domainL.Size());
349 
350  // user interrupt/ progress
351  FD_WPC(1,2,"ControlledBuechiLiveness(): [STD] iterating reverse dynamics");
352 
353  // prepare domain = domainL - marL
354  domain=domainL-rPlantMarking;
355 
356  // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ];
357  // start with target1:=0 and iterate target+=theta(targetL+(target1-markL), domainL-markL) ];
358  target1.Clear();
359  while(true) {
360  Idx t1sz = target1.Size();
361 
362  // prepare target= targetL+(target1-markL)
363  target = targetL + (target1-rPlantMarking);
364 
365  // evaluate theta(target,domain)
366  FD_DF("ControlledBuechiLiveness(): [STD] -- evaluate theta for target/domain # "
367  << target.Size() << "/" << domain.Size());
368  theta.Clear();
369  StateSet::Iterator sit = full.Begin();
370  StateSet::Iterator sit_end = full.End();
371  for(;sit!=sit_end;++sit) {
372  bool pass = false;
373  bool fail = false;
374  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
375  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
376  for(;tit!=tit_end; ++tit) {
377  if(target.Exists(tit->X2)) {pass = true; continue;}
378  if(domain.Exists(tit->X2)) {continue;}
379  if(!rCAlph.Exists(tit->Ev)){ fail = true; break;}
380  }
381  if(pass && !fail) {
382  theta.Insert(*sit);
383  FD_DF("ControlledBuechiLiveness(): [STD] theta found state " << rSupCandGen.SStr(*sit));
384  }
385  } // end: theta
386 
387  // mu-loop on target1
388  target1.InsertSet(theta);
389  if(target1.Size()==t1sz) break;
390  if(target1.Size()==fsz) break;
391  } // end: mu
392 
393  FD_DF("ControlledBuechiLiveness(): [STD] -- mu-target1 # " << target1.Size());
394 
395  // nu-loop on domainL
396  domainL.RestrictSet(target1);
397  if(domainL.Size()==dLsz) break;
398  if(domainL.Size()==0) break;
399  } // end: nu
400 
401  FD_DF("ControlledBuechiLiveness(): [STD] --- nu-domainL-mu-target1 # " << domainL.Size());
402 
403  // mu-loop on initialL
404  initialL.InsertSet(domainL);
405  if(initialL.Size()==iLsz) break;
406  if(initialL.Size()==fsz) break;
407  } // end: mu
408 
409  // nu-loop on initialK
410  initialK.RestrictSet(initialL);
411  if(initialK.Size()==iKsz) break;
412  if(initialK.Size()==0) break;
413  } // end: nu
414 
415  // mu-loop on resolved
416  resolved.InsertSet(initialK);
417  if(resolved.Size()==rsz) break;
418  if(resolved.Size()==fsz) break;
419  } // end: mu
420 
421  // restrict candidate to resolved states
422  rSupCandGen.DelStates(full - resolved);
423 
424  // done
425  return true;
426 }
427 
428 
429 /*
430 Variant of the controllable prefix to extract a particular feedback map. Again, this is
431 very close to the relevant literature and meant as a reference. It is not particulary performant.
432 */
433 
435  Generator& rSupCandGen,
436  const EventSet& rCAlph,
437  const StateSet& rPlantMarking,
438  std::map< Idx , EventSet>& rFeedbackMap)
439 {
440 
441  FD_DF("ControlledBuechiLiveness()");
442 
443  // declare iterate sets
444  StateSet resolved, initialK, targetLstar;
445  StateSet initialL, targetL;
446  StateSet domainL, target1;
447  StateSet target, domain, theta;
448 
449  // record controls per state
450  EventSet disable;
451  std::map< Idx , EventSet> controls1;
452  std::map< Idx , EventSet> controls1L;
453  std::map< Idx , EventSet> controls1X;
454 
455  // convenience
456  const StateSet& full = rSupCandGen.States();
457  Idx fsz=full.Size();
458 
459  // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ];
460  resolved.Clear();
461  while(true) {
462  Idx xsz = resolved.Size();
463  initialK = full;
464  while(true) {
465  Idx rsz = initialK.Size();
466  targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved;
467  FD_DF("ControlledBuechiLiveness(): [FBM] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size());
468 
469  // reset controls
470  controls1L.clear();
471 
472  // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ]
473  initialL.Clear();
474  while(true) {
475  Idx t1Lsz = initialL.Size();
476  targetL = targetLstar + initialL;
477  FD_DF("ControlledBuechiLiveness(): [FBM] ---- iterate targetL #" << targetL.Size());
478 
479  // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ];
480  domainL=full;
481  while(true) {
482  Idx dsz = domainL.Size();
483  domain=domainL-rPlantMarking;
484  FD_DF("ControlledBuechiLiveness(): [FBM] --- iterate domain #" << domain.Size());
485 
486  // reset controls
487  controls1.clear();
488 
489  // user interrupt/ progress
490  FD_WPC(1,2,"ControlledBuechiLiveness(): [FBM] iterating reverse dynamics");
491 
492  // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ];
493  target1.Clear();
494  while(true) {
495  Idx t1sz = target1.Size();
496  target = targetL + (target1-rPlantMarking);
497 
498  // evaluate theta(target,domain)
499  FD_DF("ControlledBuechiLiveness(): [FBM] -- evaluate theta for target/domain # "
500  << target.Size() << "/" << domain.Size());
501  theta.Clear();
502  StateSet::Iterator sit = full.Begin();
503  StateSet::Iterator sit_end = full.End();
504  for(;sit!=sit_end;++sit) {
505  bool pass = false;
506  bool fail = false;
507  disable.Clear();
508  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
509  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
510  for(;tit!=tit_end; ++tit) {
511  if(target.Exists(tit->X2)) { pass = true; continue; }
512  if(domain.Exists(tit->X2)) { continue; }
513  if(!rCAlph.Exists(tit->Ev)){ fail = true; break; }
514  disable.Insert(tit->Ev);
515  }
516  if(pass && !fail) {
517  theta.Insert(*sit);
518  if(controls1.find(*sit)==controls1.end()) controls1[*sit]=disable;
519  FD_DF("ControlledBuechiLiveness(): [FBM] theta found state " << rSupCandGen.SStr(*sit));
520 #ifdef FAUDES_DEBUG_FUNCTION
521  if(!disable.Empty()) disable.Write();
522 #endif
523  }
524  } // end: theta
525 
526  // mu-loop on target1
527  target1.InsertSet(theta);
528  if(target1.Size()==t1sz) break;
529  if(target1.Size()==fsz) break;
530  } // end: mu
531 
532  FD_DF("ControlledBuechiLiveness(): [FBM] -- mu-target1 # " << target1.Size());
533 
534  // nu-loop on domainL
535  domainL.RestrictSet(target1);
536  if(domainL.Size()==dsz) break;
537  if(domainL.Size()==0) break;
538  } // end: nu
539 
540  FD_DF("ControlledBuechiLiveness(): [FBM] --- nu-domainL-mu-target1 # " << domainL.Size());
541 
542  // merge controls
543  std::map< Idx , EventSet>::iterator cit=controls1.begin();
544  std::map< Idx , EventSet>::iterator cit_end=controls1.end();
545  for(;cit!=cit_end;++cit) {
546  if(controls1L.find(cit->first)!=controls1L.end()) continue;
547  controls1L[cit->first]=cit->second;
548  }
549 
550  // mu-loop on initialL
551  initialL.InsertSet(domainL);
552  if(initialL.Size()==t1Lsz) break;
553  if(initialL.Size()==fsz) break;
554  } // end: mu
555 
556  // nu-loop on initialK
557  initialK.RestrictSet(initialL);
558  if(initialK.Size()==rsz) break;
559  if(initialK.Size()==0) break;
560  } // end: nu
561 
562  // merge controls
563  std::map< Idx , EventSet>::iterator cit=controls1L.begin();
564  std::map< Idx , EventSet>::iterator cit_end=controls1L.end();
565  for(;cit!=cit_end;++cit) {
566  if(controls1X.find(cit->first)!=controls1X.end()) continue;
567  controls1X[cit->first]=cit->second;
568  }
569 
570  // mu-loop on resolved
571  resolved.InsertSet(initialK);
572  if(resolved.Size()==xsz) break;
573  if(resolved.Size()==fsz) break;
574  } // end: mu
575 
576  // restrict candidate to valid restrict
577  rSupCandGen.DelStates(full - resolved);
578 
579  // re-write controls as feedback map
580  EventSet ucalph = rSupCandGen.Alphabet() - rCAlph;
581  StateSet::Iterator sit = resolved.Begin();
582  StateSet::Iterator sit_end = resolved.End();
583  for(;sit!=sit_end;++sit) {
584  FD_DF("ControlledBuechiLiveness(): [FBM] controls " << rSupCandGen.SStr(*sit) << " " << controls1X[*sit].ToString());
585  rFeedbackMap[*sit]= (rSupCandGen.ActiveEventSet(*sit) + ucalph) - controls1X[*sit];
586  }
587 
588  // done
589  return true;
590 }
591 
592 
593 
594 
595 // helper class: mergable control pattern
597 public:
598  // merge with other
599  void merge(const MCtrlPattern& other) {
601  enable_one.insert(other.enable_one.begin(),other.enable_one.end());
602  }
603  // test conflict
604  bool conflict() {
605  std::set< EventSet >::iterator eit =enable_one.begin();
606  std::set< EventSet >::iterator eit_end =enable_one.end();
607  for(; eit!=eit_end ; ++eit)
608  if( (*eit - disable_all).Empty() ) return true;
609  return false;
610  }
611  // member variables
613  std::set< EventSet > enable_one;
614 };
615 
616 
617 
618 /*
619 Variant of a controllable prefix under partial observation. This is **experimantal**.
620 Based on the situation of full observation, this variant records control patterns
621 used to establish controlled liveness and only accepts a new state if the corresponding
622 pattern complies all recorded patterns that correspond to the same observation.
623 The result is a (possibly strict) subset of the controllable prefix for the purpose.
624 Theoretical background will be provided in due course.
625 */
626 
628  Generator& rSupCandGen,
629  const EventSet& rCAlph,
630  const StateSet& rPlantMarking,
631  std::map< Idx , Idx>& rControllerStatesMap,
632  std::map< Idx , EventSet>& rFeedbackMap)
633 {
634 
635  FD_DF("ControlledBuechiLiveness(): [POBS]: cand #" << rSupCandGen.Size());
636 
637  // debugging: interpret empty controllermap as identity
638  StateSet::Iterator xit = rSupCandGen.StatesBegin();
639  StateSet::Iterator xit_end = rSupCandGen.StatesEnd();
640  for(;xit!=xit_end;++xit) {
641  std::map< Idx , Idx >::const_iterator cxit=rControllerStatesMap.find(*xit);
642  if(cxit==rControllerStatesMap.end()) rControllerStatesMap[*xit]=*xit;
643  }
644 
645  // informative
646  std::map< Idx , Idx>::const_iterator oit = rControllerStatesMap.begin();
647  std::set< Idx > ostates;
648  for(; oit != rControllerStatesMap.end(); ++oit)
649  ostates.insert(oit->second);
650  FD_DF("ControlledBuechiLiveness(): [POBS]: " << "obs #" << ostates.size());
651 
652  // declare iterate sets
653  StateSet resolved, initialK, targetLstar;
654  StateSet initialL, targetL;
655  StateSet domainL, target1;
656  StateSet target, domain, theta;
657 
658  // record controls per state
659  EventSet disable;
660  EventSet enable;
661  std::map< Idx , MCtrlPattern> controlsT;
662  std::map< Idx , MCtrlPattern> controls1;
663  std::map< Idx , MCtrlPattern> controls1L;
664  std::map< Idx , MCtrlPattern> controls1X;
665 
666  // convenience
667  const StateSet& full = rSupCandGen.States();
668  Idx fsz=full.Size();
669 
670  // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ];
671  resolved.Clear();
672  while(true) {
673  Idx xsz = resolved.Size();
674  initialK = full;
675  while(true) {
676  Idx rsz = initialK.Size();
677  targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved;
678  FD_DF("ControlledBuechiLiveness(): [POBS] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size());
679 
680  // reset controls
681  controls1L.clear();
682 
683  // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ]
684  initialL.Clear();
685  while(true) {
686  Idx t1Lsz = initialL.Size();
687  targetL = targetLstar + initialL;
688  FD_DF("ControlledBuechiLiveness(): [POBS] ---- iterate targetL #" << targetL.Size());
689 
690  // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ];
691  domainL=full;
692  while(true) {
693  Idx dsz = domainL.Size();
694  domain=domainL-rPlantMarking;
695  FD_DF("ControlledBuechiLiveness(): [POBS] --- iterate domain #" << domain.Size());
696 
697  // reset controls
698  controls1.clear();
699 
700  // user interrupt/ progress
701  FD_WPC(1,2,"ControlledBuechiLiveness(): [POBS] iterating reverse dynamics");
702 
703  // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ];
704  target1.Clear();
705  while(true) {
706  Idx t1sz = target1.Size();
707  target = targetL + (target1-rPlantMarking);
708 
709  // evaluate theta(target,domain) in three passes
710  FD_DF("ControlledBuechiLiveness(): [POBS] -- evaluate theta for target/domain # "
711  << target.Size() << "/" << domain.Size());
712  theta.Clear();
713  controlsT.clear();
714 
715  // pass 1: find new candidate states and acumulate required controls
716  StateSet::Iterator sit = full.Begin();
717  StateSet::Iterator sit_end = full.End();
718  for(;sit!=sit_end;++sit) {
719  Idx cx=rControllerStatesMap[*sit];
720  bool pass = false;
721  bool fail = false;
722  disable.Clear();
723  enable.Clear();
724  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
725  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
726  for(;tit!=tit_end; ++tit) {
727  if(disable.Exists(tit->Ev)) continue;
728  if(target.Exists(tit->X2)) {enable.Insert(tit->Ev); pass = true; continue;}
729  if(domain.Exists(tit->X2)) {continue;}
730  if(!rCAlph.Exists(tit->Ev)){ fail = true; break;}
731  disable.Insert(tit->Ev);
732  }
733  if(pass && !fail) {
734  // initialize control with existing patterns
735  if(controlsT.find(cx)==controlsT.end()) {
736  if(controls1.find(cx)!=controls1.end())
737  controlsT[cx].merge(controls1[cx]);
738  if(controls1L.find(cx)!=controls1L.end())
739  controlsT[cx].merge(controls1L[cx]);
740  if(controls1X.find(cx)!=controls1X.end())
741  controlsT[cx].merge(controls1X[cx]);
742  }
743  // apply additional pattern
744  controlsT[cx].disable_all.InsertSet(disable);
745  controlsT[cx].enable_one.insert(enable);
746  }
747  } // end: theta pass 1
748 
749  // pass 2: merge new controls to controls1, reject conflicting
750  std::map< Idx , MCtrlPattern >::iterator cpit=controlsT.begin();
751  std::map< Idx , MCtrlPattern >::iterator cpit_end=controlsT.end();
752  while(cpit!=cpit_end) {
753  if(cpit->second.conflict()) {controlsT.erase(cpit++); continue;}
754  controls1[cpit->first].merge(cpit->second);
755  ++cpit;
756  }
757 
758  // pass 3: evaluate theta by accumulated controls control
759  sit = rSupCandGen.StatesBegin();
760  sit_end = rSupCandGen.StatesEnd();
761  for(;sit!=sit_end;++sit) {
762  bool pass = false;
763  bool fail = false;
764  Idx cx=rControllerStatesMap[*sit];
765  if(controls1.find(cx)==controls1.end()) continue;
766  disable=controls1[cx].disable_all;
767  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
768  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
769  for(;tit!=tit_end; ++tit) {
770  if(disable.Exists(tit->Ev)) continue;
771  if(target.Exists(tit->X2)) {pass = true; continue;}
772  if(domain.Exists(tit->X2)) {continue;}
773  fail = true;
774  }
775  if(pass && !fail) {
776  theta.Insert(*sit);
777  //FD_DF("ControlledBuechiLiveness(): [POBS] theta candidate verified " << rSupCandGen.SStr(*sit));
778  }
779  } // end: theta pass 3
780 
781  // mu-loop on target1
782  target1.InsertSet(theta);
783  if(target1.Size()==t1sz) break;
784  if(target1.Size()==fsz) break;
785  } // end: mu
786 
787  FD_DF("ControlledBuechiLiveness(): [POBS] -- mu-target1 # " << target1.Size());
788 
789  // nu-loop on domainL
790  domainL.RestrictSet(target1);
791  if(domainL.Size()==dsz) break;
792  if(domainL.Size()==0) break;
793  } // end: nu
794 
795  FD_DF("ControlledBuechiLiveness(): [POBS] --- nu-domainL-mu-target1 # " << domainL.Size());
796 
797  // merge controls
798  std::map< Idx , MCtrlPattern>::iterator cit = controls1.begin();
799  std::map< Idx , MCtrlPattern>::iterator cit_end = controls1.end();
800  for(;cit!=cit_end;++cit)
801  controls1L[cit->first].merge(cit->second);
802 
803  // mu-loop on initialL
804  initialL.InsertSet(domainL);
805  if(initialL.Size()==t1Lsz) break;
806  if(initialL.Size()==fsz) break;
807  } // end: mu
808 
809  // nu-loop on initialK
810  initialK.RestrictSet(initialL);
811  if(initialK.Size()==rsz) break;
812  if(initialK.Size()==0) break;
813  } // end: nu
814 
815  // merge controls
816  std::map< Idx , MCtrlPattern>::iterator cit = controls1L.begin();
817  std::map< Idx , MCtrlPattern>::iterator cit_end = controls1L.end();
818  for(;cit!=cit_end;++cit)
819  controls1X[cit->first].merge(cit->second);
820 
821  // mu-loop on resolved
822  resolved.InsertSet(initialK);
823  if(resolved.Size()==xsz) break;
824  if(resolved.Size()==fsz) break;
825  } // end: mu
826 
827  // restrict candidate to valid restrict
828  rSupCandGen.DelStates(full - resolved);
829 
830  // debugging
831  if(rSupCandGen.IsCoaccessible())
832  FD_DF("ControlledBuechiLiveness(): [POBS] ---- coaccessible ok");
833  if(rSupCandGen.IsComplete())
834  FD_DF("ControlledBuechiLiveness(): [POBS] ---- complete ok");
835  if(!rSupCandGen.InitStates().Empty())
836  FD_DF("ControlledBuechiLiveness(): [POBS] ---- init state ok");
837 
838  // re-write controls as feedback map (w.r.t. candidate states)
839  StateSet::Iterator sit = resolved.Begin();
840  StateSet::Iterator sit_end = resolved.End();
841  for(;sit!=sit_end;++sit) {
842  Idx cx=rControllerStatesMap[*sit];
843  //FD_DF("ControlledBuechiLiveness(): [POBS] controls at cx=" << cx << " for plant state " << rSupCandGen.SStr(*sit) << " " << controls1X[cx].disable_all.ToString());
844  rFeedbackMap[*sit]= rSupCandGen.Alphabet() - controls1X[cx].disable_all;
845  }
846 
847  // done
848  return true;
849 }
850 
851 
852 /*
853 ***************************************************************************************
854 ***************************************************************************************
855  Implementation of SupBuechiCon and friends
856 ***************************************************************************************
857 ***************************************************************************************
858 */
859 
860 // helper class: omega-product state
861 class OPSState {
862 public:
863  // minimal interface
864  OPSState() {};
865  OPSState(const Idx& rq1, const Idx& rq2, const bool& rf) :
866  q1(rq1), q2(rq2), m1required(rf) {};
867  std::string Str(void) { return ToStringInteger(q1)+"|"+
869  // order
870  bool operator < (const OPSState& other) const {
871  if (q1 < other.q1) return(true);
872  if (q1 > other.q1) return(false);
873  if (q2 < other.q2) return(true);
874  if (q2 > other.q2) return(false);
875  if (m1required && !other.m1required) return(true);
876  return(false);
877  }
878  // member variables
882 };
883 
884 
885 // SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen)
887  const Generator& rPlantGen,
888  const EventSet& rCAlph,
889  const Generator& rSpecGen,
890  std::map< OPSState , Idx>& rProductCompositionMap,
891  Generator& rResGen)
892 {
893  FD_DF("SupBuechiConProduct(" << &rPlantGen << "," << &rSpecGen << ")");
894 
895  // prepare result
896  rResGen.Clear();
897  rResGen.InjectAlphabet(rPlantGen.Alphabet());
898 
899  // trivial case
900  if (rPlantGen.InitStatesEmpty()) {
901  FD_DF("SupBuechiConProduct: plant got no initial states. "
902  << "parallel composition contains empty language.");
903  return;
904  }
905  if (rSpecGen.InitStatesEmpty()) {
906  FD_DF("SupBuechiConProduct: spec got no initial states. "
907  << "parallel composition contains empty language.");
908  return;
909  }
910 
911  // todo stack
912  std::stack< OPSState > todo;
913  // current/next state as pair with flag
914  OPSState currentp, nextp;
915  // current/next state as target index
916  Idx currentt, nextt;
917  TransSet::Iterator ptit, ptit_end, stit, stit_end;
918  std::map< OPSState, Idx>::iterator rcit;
919  // critical states
920  StateSet critical;
921  // disabled events
922  EventSet disable;
923 
924 
925  // push initial state on todo stack
926  currentp = OPSState(*rPlantGen.InitStatesBegin(), *rSpecGen.InitStatesBegin(), true);
927  todo.push(currentp);
928  currentt=rResGen.InsInitState();
929  rProductCompositionMap[currentp] = currentt;
930 
931  // process/feed todo stack
932  FD_DF("SupBuechiConProduct: processing reachable states:");
933  while(!todo.empty()) {
934  // allow for user interrupt
935  // LoopCallback();
936  // allow for user interrupt, incl progress report
937  FD_WPC(rProductCompositionMap.size(),rProductCompositionMap.size()+todo.size(),"SupBuechiConProduct(): processing");
938  FD_DF("SupBuechiConProduct(): processing" << rProductCompositionMap.size() << " " << todo.size());
939  // get next reachable state from todo stack
940  currentp = todo.top();
941  currentt = rProductCompositionMap[currentp];
942  todo.pop();
943  // skip critical (tmoor 201308)
944  if(critical.Exists(currentt)) continue;
945  // report
946  FD_DF("SupBuechiConProduct: processing (" << currentp.Str() << " -> " << currentt <<")");
947 
948  // iterate over transitions, pass1: figure whether current state becomes critical (tmoor 201308)
949  ptit = rPlantGen.TransRelBegin(currentp.q1);
950  ptit_end = rPlantGen.TransRelEnd(currentp.q1);
951  stit = rSpecGen.TransRelBegin(currentp.q2);
952  stit_end = rSpecGen.TransRelEnd(currentp.q2);
953  disable.Clear();
954  // process all transitions and increment iterators strategically
955  while((ptit != ptit_end) && (stit != stit_end)) {
956  FD_DF("SupBuechiConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) );
957  FD_DF("SupBuechiConProduct: current spec-transition: " << rSpecGen.TStr(*stit));
958  // case A: execute common event
959  if(ptit->Ev == stit->Ev) {
960  nextp = OPSState(ptit->X2, stit->X2,currentp.m1required);
961  if(currentp.m1required) {
962  if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false;
963  } else {
964  if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true;
965  }
966  // figure whether successor state is known to be critical
967  rcit = rProductCompositionMap.find(nextp);
968  if(rcit != rProductCompositionMap.end()) {
969  if(critical.Exists(rcit->second)) {
970  FD_DF("SupBuechiConParallel: common event " << rSpecGen.EStr(stit->Ev) << " to a critical states");
971  // if event is uncontrollable, current state becomes critical
972  if(!rCAlph.Exists(ptit->Ev)) {
973  FD_DF("SupBuechiConProduct: critical insert" << currentt);
974  critical.Insert(currentt); // tmoor 201308
975  // exit all loops
976  ptit = ptit_end;
977  stit = stit_end;
978  break;
979  }
980  // else, event is disabled
981  disable.Insert(stit->Ev);
982  }
983  }
984  // increment transition
985  ++ptit;
986  ++stit;
987  }
988  // case B: process plant event that is disabled by the specification
989  else if (ptit->Ev < stit->Ev) {
990  FD_DF("SupConProduct: " << rPlantGen.EStr(ptit->Ev) << " is enabled in the plant but disabled in the specification");
991  // if the event is uncontrollable, this makes the current state critical
992  if (!rCAlph.Exists(ptit->Ev)) {
993  FD_DF("SupBuechiConProduct: disabled event " << rPlantGen.EStr(ptit->Ev) << " is uncontrollable");
994  FD_DF("SupBuechiConProduct: critical insert" << currentt);
995  critical.Insert(currentt);
996  // exit all loops
997  ptit = ptit_end;
998  stit = stit_end;
999  break;
1000  }
1001  FD_DF("SupBuechiConProduct: incrementing plant transrel");
1002  ++ptit;
1003  }
1004  // increment titg and titg, case C: process h event that is not enabled for g
1005  else {
1006  FD_DF("SupBuechiConProduct: incrementing spec transrel");
1007  ++stit;
1008  }
1009  } // end while incrementing
1010  // increment iterators case D: process leftover events of plant
1011  while (ptit != ptit_end) {
1012  FD_DF("SupBuechiConProduct: current g-transition: " << rPlantGen.TStr(*ptit));
1013  FD_DF("SupBuechiConProduct: current h-transition: end");
1014  // if uncontrollable event leaves candidate
1015  if (!rCAlph.Exists(ptit->Ev)) {
1016  FD_DF("SupBuechiConProduct: asynchron executed uncontrollable "
1017  << "event " << rPlantGen.EStr(ptit->Ev) << " leaves specification:");
1018  FD_DF("SupConProduct: critical insert" << rPlantGen.SStr(currentt));
1019  critical.Insert(currentt);
1020  // exit this loop
1021  break;
1022  }
1023  FD_DF("SupBuechiConProduct: incrementing g transrel");
1024  ++ptit;
1025  } // end iterating pass1
1026 
1027  // skip critical (tmoor 201308)
1028  if(critical.Exists(currentt)) continue;
1029 
1030  // iterate over transitions, pass2: execute shared events (tmoor 201308)
1031  FD_DF("SupBuechiConProduct(): processing pass2");
1032  ptit = rPlantGen.TransRelBegin(currentp.q1);
1033  ptit_end = rPlantGen.TransRelEnd(currentp.q1);
1034  stit = rSpecGen.TransRelBegin(currentp.q2);
1035  stit_end = rSpecGen.TransRelEnd(currentp.q2);
1036  // process all transitions and increment iterators strategically
1037  while((ptit != ptit_end) && (stit != stit_end)) {
1038  FD_DF("SupBuechiConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) );
1039  FD_DF("SupBuechiConProduct: current spec-transition: " << rSpecGen.TStr(*stit));
1040  // case A: execute common event
1041  if(ptit->Ev == stit->Ev) {
1042  if(!disable.Exists(stit->Ev)) {
1043  FD_DF("SupBuechiConProduct: executing common event " << rPlantGen.EStr(ptit->Ev));
1044  nextp = OPSState(ptit->X2, stit->X2,currentp.m1required);
1045  if(currentp.m1required) {
1046  if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false;
1047  } else {
1048  if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true;
1049  }
1050  // figure target index
1051  rcit = rProductCompositionMap.find(nextp);
1052  // if state is new: add to todo list and result
1053  if(rcit == rProductCompositionMap.end()) {
1054  todo.push(nextp);
1055  nextt = rResGen.InsState();
1056  rProductCompositionMap[nextp] = nextt;
1057  if(!nextp.m1required)
1058  if(rSpecGen.ExistsMarkedState(nextp.q2))
1059  rResGen.SetMarkedState(nextt);
1060  FD_DF("SupBuechiConProduct: todo push: (" << nextp.Str() << ") -> " << nextt);
1061  } else {
1062  nextt = rcit->second;
1063  }
1064  // set the transition and increment iterators
1065  FD_DF("SupBuechierParallel: add transition to new generator: " << rResGen.TStr(Transition(currentt, ptit->Ev, nextt)));
1066  rResGen.SetTransition(currentt, ptit->Ev, nextt);
1067  }
1068  // increment transition
1069  ++ptit;
1070  ++stit;
1071  } // end: if processing common event
1072  // case B: process plant event that is disabled by the specification
1073  else if (ptit->Ev < stit->Ev) {
1074  ++ptit;
1075  }
1076  // increment titg and titg, case C: process h event that is not enabled for g
1077  else {
1078  ++stit;
1079  }
1080  } // end while incrementing for pass2
1081 
1082  } // while todo
1083 
1084  FD_DF("SupBuechiConProduct: deleting critical states: " << critical.ToString());
1085  rResGen.DelStates(critical);
1086 
1087  // restrict composition map
1088  std::map< OPSState , Idx>::iterator cit = rProductCompositionMap.begin();
1089  while(cit != rProductCompositionMap.end())
1090  if(!rResGen.ExistsState(cit->second)) rProductCompositionMap.erase(cit++);
1091  else cit++;
1092 
1093 }
1094 
1095 
1096 
1097 
1098 // SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen,rResGen)
1100  const Generator& rPlantGen,
1101  const EventSet& rCAlph,
1102  const Generator& rSpecGen,
1103  StateSet& rPlantMarking,
1104  Generator& rResGen)
1105 {
1106  FD_DF("SupBuechiConUnchecked(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")");
1107 
1108  // PREPARE RESULT:
1109  Generator* pResGen = &rResGen;
1110  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1111  pResGen= rResGen.New();
1112  }
1113  pResGen->Clear();
1114  pResGen->InjectAlphabet(rPlantGen.Alphabet());
1115 
1116  // controllable events
1117  FD_DF("SupBuechiCon: controllable events: " << rCAlph.ToString());
1118 
1119  // perform product
1120  std::map< OPSState , Idx> cmap;
1121  SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen);
1122 
1123  // figure plant marking
1124  rPlantMarking.Clear();
1125  std::map< OPSState, Idx>::iterator pcit;
1126  for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit)
1127  if(rPlantGen.ExistsMarkedState(pcit->first.q1))
1128  rPlantMarking.Insert(pcit->second);
1129 
1130  // fix statenames (debugging)
1131 #ifdef FAUDES_DEBUG_FUNCTION
1132  std::map< OPSState, Idx>::iterator dcit;
1133  for(dcit=cmap.begin(); dcit!=cmap.end(); ++dcit) {
1134  Idx x1=dcit->first.q1;
1135  Idx x2=dcit->first.q2;
1136  bool m1requ=dcit->first.m1required;
1137  Idx x12=dcit->second;
1138  if(!pResGen->ExistsState(x12)) continue;
1139  std::string name1= rPlantGen.StateName(x1);
1140  if(name1=="") name1=ToStringInteger(x1);
1141  std::string name2= rSpecGen.StateName(x2);
1142  if(name2=="") name1=ToStringInteger(x2);
1143  std::string name12;
1144  if(m1requ) name12= name1 + "|" + name2 + "|r1m";
1145  else name12= name1 + "|" + name2 + "|r2m";
1146  name12=pResGen->UniqueStateName(name12);
1147  pResGen->StateName(x12,name12);
1148  }
1149 #endif
1150 
1151 #ifdef FAUDES_DEBUG_FUNCTION
1152  pResGen->DWrite();
1153  pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen");
1154  pResGen->WriteStateSet(rPlantMarking);
1155 #endif
1156 
1157  // iterate for required properties
1158  while(true) {
1159  // catch trivial
1160  if(pResGen->Empty()) break;
1161  // fast inner loop: prefix controllability and omega-trim
1162  while(true) {
1163  Idx count1 = pResGen->Size();
1164  FD_DF("SupBuechiCon: iterate: do prefix con on #" << pResGen->Size());
1165  SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen);
1166  FD_DF("SupBuechiCon: iterate: do coaccessible on #" << pResGen->Size());
1167  pResGen->Coaccessible();
1168  FD_DF("SupBuechiCon: iterate: do accessible on #" << pResGen->Size());
1169  pResGen->Accessible();
1170  FD_DF("SupBuechiCon: iterate: do complete on #" << pResGen->Size());
1171  pResGen->Complete();
1172  if(pResGen->Size() == count1) break;
1173  if(pResGen->Size() == 0) break;
1174  }
1175  // slow outer loop: controlled liveness aka restrict to controllable prefix
1176  Idx count2 = pResGen->Size();
1177  FD_DF("SupBuechiCon: iterate: do controlled liveness on #" << pResGen->Size());
1178  ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking);
1179  if(pResGen->Size() == count2) break;
1180  }
1181 
1182  // fix statenames ...
1183  std::map< OPSState, Idx>::iterator rcit;
1184  if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled())
1185  for(rcit=cmap.begin(); rcit!=cmap.end(); rcit++) {
1186  Idx x1=rcit->first.q1;
1187  Idx x2=rcit->first.q2;
1188  bool m1requ=rcit->first.m1required;
1189  Idx x12=rcit->second;
1190  if(!pResGen->ExistsState(x12)) continue;
1191  std::string name1= rPlantGen.StateName(x1);
1192  if(name1=="") name1=ToStringInteger(x1);
1193  std::string name2= rSpecGen.StateName(x2);
1194  if(name2=="") name1=ToStringInteger(x2);
1195  std::string name12;
1196  if(m1requ) name12= name1 + "|" + name2 + "|r1m";
1197  else name12= name1 + "|" + name2 + "|r2m";
1198  name12=pResGen->UniqueStateName(name12);
1199  pResGen->StateName(x12,name12);
1200  }
1201 
1202  // .. or clear them (?)
1203  if(!(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled()))
1204  pResGen->StateNamesEnabled(false);
1205 
1206  // copy result
1207  if(pResGen != &rResGen) {
1208  pResGen->Move(rResGen);
1209  delete pResGen;
1210  }
1211 
1212  FD_DF("SupBuechiCon: return #" << rResGen.Size());
1213 }
1214 
1215 
1216 // SupConBuechiNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, rFeedbackMap, rResGen)
1218  const Generator& rPlantGen,
1219  const EventSet& rCAlph,
1220  const EventSet& rOAlph,
1221  const Generator& rSpecGen,
1222  StateSet& rPlantMarking,
1223  std::map< Idx , Idx >& rObserverStateMap,
1224  std::map< Idx , EventSet>& rFeedbackMap,
1225  Generator& rResGen)
1226 {
1227  FD_DF("SupBuechiConNorm(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")");
1228 
1229  // prepare result
1230  Generator* pResGen = &rResGen;
1231  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1232  pResGen= rResGen.New();
1233  }
1234  pResGen->Clear();
1235  pResGen->InjectAlphabet(rPlantGen.Alphabet());
1236 
1237  // report events
1238  FD_DF("SupBuechiConNorm: controllable events: " << rCAlph.ToString());
1239  FD_DF("SupBuechiConNorm: un-observabel events: " << (rPlantGen.Alphabet()-rOAlph).ToString());
1240 
1241  // perform product
1242  std::map< OPSState , Idx> cmap;
1243  SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen);
1244  BuechiTrim(*pResGen);
1245 
1246  // no statenames impülemented
1247  pResGen->StateNamesEnabled(false);
1248 
1249  // figure plant marking
1250  rPlantMarking.Clear();
1251  std::map< OPSState, Idx>::iterator pcit;
1252  for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit)
1253  if(rPlantGen.ExistsMarkedState(pcit->first.q1))
1254  rPlantMarking.Insert(pcit->second);
1255 
1256  // extend by observer states
1257  Generator obsG= *pResGen;
1258  MarkAllStates(obsG);
1259  Project(obsG,rOAlph,obsG);
1260  InvProject(obsG,pResGen->Alphabet());
1261  std::map< std::pair<Idx,Idx>, Idx> rObserverCompositionMap;
1262  Product(*pResGen, obsG, rObserverCompositionMap, *pResGen);
1263  // track plantmarking
1264  StateSet fixmarking;
1265  std::map< std::pair<Idx,Idx>, Idx>::iterator cit;
1266  for(cit=rObserverCompositionMap.begin(); cit!=rObserverCompositionMap.end();++cit)
1267  if(rPlantMarking.Exists(cit->first.first)) fixmarking.Insert(cit->second);
1268  rPlantMarking=fixmarking;
1269  // construct reverse map "pResGen.State --> obsG.State"
1270  std::map< std::pair<Idx,Idx>, Idx>::iterator sit;
1271  for(sit=rObserverCompositionMap.begin(); sit!=rObserverCompositionMap.end();++sit)
1272  rObserverStateMap[sit->second]=sit->first.second;
1273 
1274 #ifdef FAUDES_DEBUG_FUNCTION
1275  pResGen->DWrite();
1276  pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen");
1277  pResGen->WriteStateSet(rPlantMarking);
1278 #endif
1279 
1280  FD_DF("SupBuechiConNorm(): cand #" << pResGen->Size() << " obs #" << obsG.Size());
1281  // make resulting generator trim until it's fully controllable
1282  while(true) {
1283  // catch trivial
1284  if(pResGen->Empty()) break;
1285  // fast inner loop: prefix controllability and omega-trim
1286  while(true) {
1287  Idx count1 = pResGen->Size();
1288  FD_DF("SupBuechiConNorm: iterate: do prefix-contr on #" << pResGen->Size());
1289  SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen);
1290  FD_DF("SupBuechiConNorm: iterate: do accessible on #" << pResGen->Size());
1291  pResGen->Accessible();
1292  FD_DF("SupBuechiConNorm: iterate: do coaccessible on #" << pResGen->Size());
1293  pResGen->Coaccessible();
1294  FD_DF("SupBuechiConNorm: iterate: do prefix-norm on #" << pResGen->Size());
1295  SupConNormClosedUnchecked(rPlantGen, rOAlph, rOAlph, obsG, *pResGen);
1296  FD_DF("SupBuechiConNorm: iterate: do coaccessible on #" << pResGen->Size());
1297  pResGen->Coaccessible();
1298  FD_DF("SupBuechiConNorm: iterate: do accessible on #" << pResGen->Size());
1299  pResGen->Accessible();
1300  FD_DF("SupBuechiConNorm: iterate: do complete on #" << pResGen->Size());
1301  pResGen->Complete();
1302  if(pResGen->Size() == count1) break;
1303  if(pResGen->Size() == 0) break;
1304  }
1305  // slow outer loop: controlled liveness
1306  Idx count2 = pResGen->Size();
1307  FD_DF("SupBuechiConNorm: iterate: do controlled liveness on #" << pResGen->Size());
1308 
1309  // cosmetic: restrict observer map and count effective states
1310  std::map< Idx , Idx>::iterator oit = rObserverStateMap.begin();
1311  while(oit != rObserverStateMap.end())
1312  if(!pResGen->ExistsState(oit->first)) rObserverStateMap.erase(oit++);
1313  else oit++;
1314  std::set< Idx > ostates;
1315  for(oit = rObserverStateMap.begin(); oit != rObserverStateMap.end(); ++oit)
1316  ostates.insert(oit->second);
1317 
1318  //omega controlled liveness aka controllabe prefix
1319  FD_DF("SupBuechiConNorm(): cand #" << pResGen->Size() << " obs #" << ostates.size());
1320  std::map< Idx , EventSet> feedback;
1321  ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking,rObserverStateMap,feedback);
1322  //ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking);
1323  if(pResGen->Size() == count2) break;
1324  }
1325 
1326  // copy result
1327  if(pResGen != &rResGen) {
1328  pResGen->Move(rResGen);
1329  delete pResGen;
1330  }
1331 }
1332 
1333 
1334 /*
1335 ****************************************
1336 * SUPCON: WRAPPER / USER FUNCTIONS *
1337 ****************************************
1338 */
1339 
1340 
1341 // SupBuechiCon(rPlantGen, rCAlph, rSpecGen, rResGen)
1343  const Generator& rPlantGen,
1344  const EventSet& rCAlph,
1345  const Generator& rSpecGen,
1346  Generator& rResGen)
1347 {
1348  // consitenct check
1349  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
1350  // execute
1351  StateSet plantmarking;
1352  SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen);
1353  // record name
1354  rResGen.Name(CollapsString("SupBuechiCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1355 }
1356 
1357 
1358 // SupBuechiCon for Systems:
1359 // uses and maintains controllablity from plant
1361  const System& rPlantGen,
1362  const Generator& rSpecGen,
1363  Generator& rResGen) {
1364  // prepare result
1365  Generator* pResGen = &rResGen;
1366  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1367  pResGen= rResGen.New();
1368  }
1369  // execute
1370  SupBuechiCon(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
1371  // copy all attributes of input alphabet
1372  pResGen->EventAttributes(rPlantGen.Alphabet());
1373  // copy result
1374  if(pResGen != &rResGen) {
1375  pResGen->Move(rResGen);
1376  delete pResGen;
1377  }
1378 }
1379 
1380 // BuechiCon(rPlantGen, rCAlph, rSpecGen, rResGen)
1382  const Generator& rPlantGen,
1383  const EventSet& rCAlph,
1384  const Generator& rSpecGen,
1385  Generator& rResGen)
1386 {
1387 
1388  // consitency check
1389  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
1390  // compute supremal closed-loop behaviour
1391  StateSet plantmarking;
1392  SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen);
1393  // compute restrictive feedback
1394  std::map< Idx , EventSet> feedback;
1395  ControlledBuechiLiveness(rResGen, rCAlph, plantmarking, feedback);
1396  // apply restrictive feedback
1397  StateSet::Iterator sit = rResGen.StatesBegin();
1398  StateSet::Iterator sit_end = rResGen.StatesEnd();
1399  for(;sit!=sit_end;++sit) {
1400  const EventSet& pattern = feedback[*sit];
1401  TransSet::Iterator tit = rResGen.TransRelBegin(*sit);
1402  TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit);
1403  while(tit!=tit_end) {
1404  if(pattern.Exists(tit->Ev)) { tit++; continue;};
1405  rResGen.ClrTransition(tit++);
1406  }
1407  }
1408  // cosmetic trim
1409  rResGen.Trim();
1410 
1411 #ifdef FAUDES_CODE
1412  // during development: test controllability and livenes
1413  if(!IsControllable(rPlantGen,rCAlph,rResGen)) {
1414  throw Exception("BuechiCon(..)", "ERROR: controllability test failed", 500);
1415  }
1416  if(!IsBuechiRelativelyClosed(rPlantGen,rResGen)) {
1417  throw Exception("BuechiCon(..)", "ERROR: rel. top. closedness test failed", 500);
1418  }
1419 #endif
1420 
1421  // record name
1422  rResGen.Name(CollapsString("BuechiCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1423 }
1424 
1425 // BuechiCon for Systems:
1426 // uses and maintains controllablity from plant
1428  const System& rPlantGen,
1429  const Generator& rSpecGen,
1430  Generator& rResGen)
1431 {
1432  // prepare result
1433  Generator* pResGen = &rResGen;
1434  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1435  pResGen= rResGen.New();
1436  }
1437  // execute
1438  BuechiCon(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
1439  // copy all attributes of input alphabet
1440  pResGen->EventAttributes(rPlantGen.Alphabet());
1441  // copy result
1442  if(pResGen != &rResGen) {
1443  pResGen->Move(rResGen);
1444  delete pResGen;
1445  }
1446 }
1447 
1448 
1449 // SupBuechiConNorm(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen)
1451  const Generator& rPlantGen,
1452  const EventSet& rCAlph,
1453  const EventSet& rOAlph,
1454  const Generator& rSpecGen,
1455  Generator& rResGen)
1456 {
1457  // consitenct check
1458  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen);
1459  // execute
1460  std::map< Idx , Idx> constates;
1461  std::map< Idx , EventSet> feedback;
1462  StateSet plantmarking;
1463  SupBuechiConNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, constates, feedback, rResGen);
1464  // record name
1465  rResGen.Name(CollapsString("SupBuechiConNorm(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1466 }
1467 
1468 
1469 // SupBuechiConNorm for Systems:
1470 // uses and maintains controllablity from plant
1472  const System& rPlantGen,
1473  const Generator& rSpecGen,
1474  Generator& rResGen) {
1475  // prepare result
1476  Generator* pResGen = &rResGen;
1477  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1478  pResGen= rResGen.New();
1479  }
1480  // execute
1481  SupBuechiConNorm(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(),rSpecGen,*pResGen);
1482  // copy all attributes of input alphabet
1483  pResGen->EventAttributes(rPlantGen.Alphabet());
1484  // copy result
1485  if(pResGen != &rResGen) {
1486  pResGen->Move(rResGen);
1487  delete pResGen;
1488  }
1489 }
1490 
1491 // BuechiConNrm(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen)
1493  const Generator& rPlantGen,
1494  const EventSet& rCAlph,
1495  const EventSet& rOAlph,
1496  const Generator& rSpecGen,
1497  Generator& rResGen)
1498 {
1499 
1500  // consitency check
1501  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen);
1502  // compute supremal closed-loop behaviour
1503  StateSet plantmarking;
1504  std::map< Idx , Idx> cxmap;
1505  std::map< Idx , EventSet> feedback;
1506  SupBuechiConNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, cxmap, feedback, rResGen);
1507  // compute restrictive feedback
1508  ControlledBuechiLiveness(rResGen, rCAlph, plantmarking, cxmap, feedback);
1509  // apply restrictive feedback
1510  StateSet::Iterator sit = rResGen.StatesBegin();
1511  StateSet::Iterator sit_end = rResGen.StatesEnd();
1512  for(;sit!=sit_end;++sit) {
1513  // Idx cx = cxmap[*sit]; etc ...
1514  const EventSet& pattern = feedback[*sit];
1515  TransSet::Iterator tit = rResGen.TransRelBegin(*sit);
1516  TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit);
1517  while(tit!=tit_end) {
1518  if(pattern.Exists(tit->Ev)) { tit++; continue;};
1519  rResGen.ClrTransition(tit++);
1520  }
1521  }
1522  // trim (?)
1523  BuechiTrim(rResGen);
1524 //#ifdef FAUDES_CODE
1525  // during development: test controllability, normality and livenes
1526  if(!IsControllable(rPlantGen,rCAlph,rResGen)) {
1527  throw Exception("BuechiConNorm(..)", "ERROR: controllability test failed", 500);
1528  }
1529  if(!IsBuechiRelativelyClosed(rPlantGen,rResGen)) {
1530  throw Exception("BuechiConNorm(..)", "ERROR: rel. top. closedness test failed", 500);
1531  }
1532  Generator prK=rResGen;
1533  MarkAllStates(prK);
1534  Generator prL=rPlantGen;
1535  prL.Trim();
1536  MarkAllStates(prL);
1537  if(!IsNormal(prL,rOAlph,prK)){
1538  throw Exception("BuechiConNorm(..)", "ERROR: prefix normality test failed", 500);
1539  }
1540 //#endif
1541 
1542  // record name
1543  rResGen.Name(CollapsString("BuechiConNorm(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1544 }
1545 
1546 // BuechiConNorm for Systems
1547 // uses and maintains controllablity from plant
1549  const System& rPlantGen,
1550  const Generator& rSpecGen,
1551  Generator& rResGen) {
1552  // prepare result
1553  Generator* pResGen = &rResGen;
1554  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1555  pResGen= rResGen.New();
1556  }
1557  // execute
1558  BuechiConNorm(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(), rSpecGen,*pResGen);
1559  // copy all attributes of input alphabet
1560  pResGen->EventAttributes(rPlantGen.Alphabet());
1561  // copy result
1562  if(pResGen != &rResGen) {
1563  pResGen->Move(rResGen);
1564  delete pResGen;
1565  }
1566 }
1567 
1568 
1569 
1570 } // name space
#define FD_WPC(cntnow, contdone, message)
#define FD_DF(message)
const std::string & Name(void) const
Definition: cfl_types.cpp:422
std::set< EventSet > enable_one
void merge(const MCtrlPattern &other)
bool Exists(const Idx &rIndex) const
virtual void InsertSet(const NameSet &rOtherSet)
bool Insert(const Idx &rIndex)
std::string Str(void)
bool operator<(const OPSState &other) const
OPSState(const Idx &rq1, const Idx &rq2, const bool &rf)
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
const TaEventSet< EventAttr > & Alphabet(void) const
EventSet ControllableEvents(void) const
EventSet ObservableEvents(void) const
void DWrite(const Type *pContext=0) const
Definition: cfl_types.cpp:231
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Definition: cfl_types.cpp:175
void Write(const Type *pContext=0) const
Definition: cfl_types.cpp:145
StateSet::Iterator StatesBegin(void) const
StateSet::Iterator InitStatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
virtual void Move(vGenerator &rGen)
bool InitStatesEmpty(void) const
EventSet ActiveEventSet(Idx x1) const
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
void ClrTransition(Idx x1, Idx ev, Idx x2)
void WriteStateSet(const StateSet &rStateSet) const
bool IsComplete(void) const
virtual vGenerator * New(void) const
bool ExistsState(Idx index) const
bool IsCoaccessible(void) const
std::string TStr(const Transition &rTrans) const
std::string StateName(Idx index) const
StateSet::Iterator StatesEnd(void) const
void DelStates(const StateSet &rDelStates)
TransSet::Iterator TransRelEnd(void) const
std::string EStr(Idx index) const
void SetMarkedState(Idx index)
bool Empty(void) const
virtual void EventAttributes(const EventSet &rEventSet)
bool StateNamesEnabled(void) const
Idx Size(void) const
std::string SStr(Idx index) 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:1904
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2322
virtual void Clear(void)
Definition: cfl_baseset.h:2104
Iterator End(void) const
Definition: cfl_baseset.h:2098
virtual void RestrictSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2271
virtual void InsertSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2194
Iterator Begin(void) const
Definition: cfl_baseset.h:2093
Idx Size(void) const
Definition: cfl_baseset.h:1899
void Product(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void MarkAllStates(vGenerator &rGen)
void Project(const Generator &rGen, const EventSet &rProjectAlphabet, Generator &rResGen)
void InvProject(Generator &rGen, const EventSet &rProjectAlphabet)
bool IsDeterministic(const vGenerator &rGen)
void BuechiConNorm(const Generator &rPlantGen, const EventSet &rCAlph, const EventSet &rOAlph, const Generator &rSpecGen, Generator &rResGen)
void SupBuechiCon(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSpecGen, Generator &rResGen)
bool IsBuechiControllable(const Generator &rGenPlant, const EventSet &rCAlph, const Generator &rGenCand)
bool BuechiTrim(vGenerator &rGen)
void BuechiCon(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSpecGen, Generator &rResGen)
void SupBuechiConNorm(const Generator &rPlantGen, const EventSet &rCAlph, const EventSet &rOAlph, const Generator &rSpecGen, Generator &rResGen)
bool IsControllable(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSupCandGen)
Definition: syn_supcon.cpp:718
bool IsNormal(const Generator &rL, const EventSet &rOAlph, const Generator &rK)
uint32_t Idx
bool IsControllableUnchecked(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSupCandGen, StateSet &rCriticalStates)
Definition: syn_supcon.cpp:243
void SupBuechiConUnchecked(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSpecGen, StateSet &rPlantMarking, Generator &rResGen)
void SupConNormClosedUnchecked(const Generator &rPlantGen, const EventSet &rCAlph, const EventSet &rOAlph, Generator &rObserverGen, Generator &rSupCandGen)
bool ControlledBuechiLiveness(Generator &rSupCandGen, const EventSet &rCAlph, const StateSet &rPlantMarking)
void ControlProblemConsistencyCheck(const GeneratorVector &rPlantGenVec, const EventSet &rConAlph, const GeneratorVector &rSpecGenVec)
void SupConClosedUnchecked(const Generator &rPlantGen, const EventSet &rCAlph, Generator &rSupCandGen)
Definition: syn_supcon.cpp:57
bool IsBuechiTrim(const vGenerator &rGen)
bool IsBuechiRelativelyClosed(const Generator &rGenPlant, const Generator &rGenCand)
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
void SupBuechiConProduct(const Generator &rPlantGen, const EventSet &rCAlph, const Generator &rSpecGen, std::map< OPSState, Idx > &rProductCompositionMap, Generator &rResGen)
void SupBuechiConNormUnchecked(const Generator &rPlantGen, const EventSet &rCAlph, const EventSet &rOAlph, const Generator &rSpecGen, StateSet &rPlantMarking, std::map< Idx, Idx > &rObserverStateMap, std::map< Idx, EventSet > &rFeedbackMap, Generator &rResGen)
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.33l --- 2025.09.16 --- c++ api documentaion by doxygen