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. A more efficient
432 implementation proposed by Christian Wamser will be integrated in due course.
433 */
434 
436  Generator& rSupCandGen,
437  const EventSet& rCAlph,
438  const StateSet& rPlantMarking,
439  std::map< Idx , EventSet>& rFeedbackMap)
440 {
441 
442  FD_WARN("ControlledBuechiLiveness()");
443 
444  // declare iterate sets
445  StateSet resolved, initialK, targetLstar;
446  StateSet initialL, targetL;
447  StateSet domainL, target1;
448  StateSet target, domain, theta;
449 
450  // record controls per state
451  EventSet disable;
452  std::map< Idx , EventSet> controls1;
453  std::map< Idx , EventSet> controls1L;
454  std::map< Idx , EventSet> controls1X;
455 
456  // convenience
457  const StateSet& full = rSupCandGen.States();
458  Idx fsz=full.Size();
459 
460  // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ];
461  resolved.Clear();
462  while(true) {
463  Idx xsz = resolved.Size();
464  initialK = full;
465  while(true) {
466  Idx rsz = initialK.Size();
467  targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved;
468  FD_WARN("ControlledBuechiLiveness(): [FBM] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size());
469 
470  // reset controls
471  controls1L.clear();
472 
473  // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ]
474  initialL.Clear();
475  while(true) {
476  Idx t1Lsz = initialL.Size();
477  targetL = targetLstar + initialL;
478  FD_WARN("ControlledBuechiLiveness(): [FBM] ---- iterate targetL #" << targetL.Size());
479 
480  // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ];
481  domainL=full;
482  while(true) {
483  Idx dsz = domainL.Size();
484  domain=domainL-rPlantMarking;
485  FD_WARN("ControlledBuechiLiveness(): [FBM] --- iterate domain #" << domain.Size());
486 
487  // reset controls
488  controls1.clear();
489 
490  // user interrupt/ progress
491  FD_WPC(1,2,"ControlledBuechiLiveness(): [FBM] iterating reverse dynamics");
492 
493  // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ];
494  target1.Clear();
495  while(true) {
496  Idx t1sz = target1.Size();
497  target = targetL + (target1-rPlantMarking);
498 
499  // evaluate theta(target,domain)
500  FD_WARN("ControlledBuechiLiveness(): [FBM] -- evaluate theta for target/domain # "
501  << target.Size() << "/" << domain.Size());
502  theta.Clear();
503  StateSet::Iterator sit = full.Begin();
504  StateSet::Iterator sit_end = full.End();
505  for(;sit!=sit_end;++sit) {
506  bool pass = false;
507  bool fail = false;
508  disable.Clear();
509  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
510  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
511  for(;tit!=tit_end; ++tit) {
512  if(target.Exists(tit->X2)) { pass = true; continue; }
513  if(domain.Exists(tit->X2)) { continue; }
514  if(!rCAlph.Exists(tit->Ev)){ fail = true; break; }
515  disable.Insert(tit->Ev);
516  }
517  if(pass && !fail) {
518  theta.Insert(*sit);
519  if(controls1.find(*sit)==controls1.end()) controls1[*sit]=disable;
520  FD_WARN("ControlledBuechiLiveness(): [FBM] theta found state " << rSupCandGen.SStr(*sit));
521  if(!disable.Empty()) disable.Write();
522  }
523  } // end: theta
524 
525  // mu-loop on target1
526  target1.InsertSet(theta);
527  if(target1.Size()==t1sz) break;
528  if(target1.Size()==fsz) break;
529  } // end: mu
530 
531  FD_WARN("ControlledBuechiLiveness(): [FBM] -- mu-target1 # " << target1.Size());
532 
533  // nu-loop on domainL
534  domainL.RestrictSet(target1);
535  if(domainL.Size()==dsz) break;
536  if(domainL.Size()==0) break;
537  } // end: nu
538 
539  FD_WARN("ControlledBuechiLiveness(): [FBM] --- nu-domainL-mu-target1 # " << domainL.Size());
540 
541  // merge controls
542  std::map< Idx , EventSet>::iterator cit=controls1.begin();
543  std::map< Idx , EventSet>::iterator cit_end=controls1.end();
544  for(;cit!=cit_end;++cit) {
545  if(controls1L.find(cit->first)!=controls1L.end()) continue;
546  controls1L[cit->first]=cit->second;
547  }
548 
549  // mu-loop on initialL
550  initialL.InsertSet(domainL);
551  if(initialL.Size()==t1Lsz) break;
552  if(initialL.Size()==fsz) break;
553  } // end: mu
554 
555  // nu-loop on initialK
556  initialK.RestrictSet(initialL);
557  if(initialK.Size()==rsz) break;
558  if(initialK.Size()==0) break;
559  } // end: nu
560 
561  // merge controls
562  std::map< Idx , EventSet>::iterator cit=controls1L.begin();
563  std::map< Idx , EventSet>::iterator cit_end=controls1L.end();
564  for(;cit!=cit_end;++cit) {
565  if(controls1X.find(cit->first)!=controls1X.end()) continue;
566  controls1X[cit->first]=cit->second;
567  }
568 
569  // mu-loop on resolved
570  resolved.InsertSet(initialK);
571  if(resolved.Size()==xsz) break;
572  if(resolved.Size()==fsz) break;
573  } // end: mu
574 
575  // restrict candidate to valid restrict
576  rSupCandGen.DelStates(full - resolved);
577 
578  // re-write controls as feedback map
579  EventSet ucalph = rSupCandGen.Alphabet() - rCAlph;
580  StateSet::Iterator sit = resolved.Begin();
581  StateSet::Iterator sit_end = resolved.End();
582  for(;sit!=sit_end;++sit) {
583  FD_WARN("ControlledBuechiLiveness(): [FBM] controls " << rSupCandGen.SStr(*sit) << " " << controls1X[*sit].ToString());
584  rFeedbackMap[*sit]= (rSupCandGen.ActiveEventSet(*sit) + ucalph) - controls1X[*sit];
585  }
586 
587  // done
588  return true;
589 }
590 
591 
592 
593 
594 // helper class: mergable control pattern
596 public:
597  // merge with other
598  void merge(const MCtrlPattern& other) {
600  enable_one.insert(other.enable_one.begin(),other.enable_one.end());
601  }
602  // test conflict
603  bool conflict() {
604  std::set< EventSet >::iterator eit =enable_one.begin();
605  std::set< EventSet >::iterator eit_end =enable_one.end();
606  for(; eit!=eit_end ; ++eit)
607  if( (*eit - disable_all).Empty() ) return true;
608  return false;
609  }
610  // member variables
612  std::set< EventSet > enable_one;
613 };
614 
615 
616 
617 /*
618 Variant of a controllable prefix under partial observation. This is **experimantal**.
619 Based on the situation of full observation, this variant records control patterns
620 used to establish controlled liveness and only accepts a new state if the corresponding
621 pattern complies all recorded patterns that correspond to the same observation.
622 The result is a (possibly strict) subset of the controllable prefix for the purpose.
623 Theoretical background will be provided in due course.
624 */
625 
627  Generator& rSupCandGen,
628  const EventSet& rCAlph,
629  const StateSet& rPlantMarking,
630  std::map< Idx , Idx>& rControllerStatesMap,
631  std::map< Idx , EventSet>& rFeedbackMap)
632 {
633 
634  FD_WARN("ControlledBuechiLiveness(): [POBS]: cand #" << rSupCandGen.Size());
635 
636  // debugging: interpret empty controllermap as identity
637  StateSet::Iterator xit = rSupCandGen.StatesBegin();
638  StateSet::Iterator xit_end = rSupCandGen.StatesEnd();
639  for(;xit!=xit_end;++xit) {
640  std::map< Idx , Idx >::const_iterator cxit=rControllerStatesMap.find(*xit);
641  if(cxit==rControllerStatesMap.end()) rControllerStatesMap[*xit]=*xit;
642  }
643 
644  // informative
645  std::map< Idx , Idx>::const_iterator oit = rControllerStatesMap.begin();
646  std::set< Idx > ostates;
647  for(; oit != rControllerStatesMap.end(); ++oit)
648  ostates.insert(oit->second);
649  FD_WARN("ControlledBuechiLiveness(): [POBS]: " << "obs #" << ostates.size());
650 
651  // declare iterate sets
652  StateSet resolved, initialK, targetLstar;
653  StateSet initialL, targetL;
654  StateSet domainL, target1;
655  StateSet target, domain, theta;
656 
657  // record controls per state
658  EventSet disable;
659  EventSet enable;
660  std::map< Idx , MCtrlPattern> controlsT;
661  std::map< Idx , MCtrlPattern> controls1;
662  std::map< Idx , MCtrlPattern> controls1L;
663  std::map< Idx , MCtrlPattern> controls1X;
664 
665  // convenience
666  const StateSet& full = rSupCandGen.States();
667  Idx fsz=full.Size();
668 
669  // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ];
670  resolved.Clear();
671  while(true) {
672  Idx xsz = resolved.Size();
673  initialK = full;
674  while(true) {
675  Idx rsz = initialK.Size();
676  targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved;
677  FD_WARN("ControlledBuechiLiveness(): [POBS] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size());
678 
679  // reset controls
680  controls1L.clear();
681 
682  // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ]
683  initialL.Clear();
684  while(true) {
685  Idx t1Lsz = initialL.Size();
686  targetL = targetLstar + initialL;
687  FD_WARN("ControlledBuechiLiveness(): [POBS] ---- iterate targetL #" << targetL.Size());
688 
689  // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ];
690  domainL=full;
691  while(true) {
692  Idx dsz = domainL.Size();
693  domain=domainL-rPlantMarking;
694  FD_WARN("ControlledBuechiLiveness(): [POBS] --- iterate domain #" << domain.Size());
695 
696  // reset controls
697  controls1.clear();
698 
699  // user interrupt/ progress
700  FD_WPC(1,2,"ControlledBuechiLiveness(): [POBS] iterating reverse dynamics");
701 
702  // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ];
703  target1.Clear();
704  while(true) {
705  Idx t1sz = target1.Size();
706  target = targetL + (target1-rPlantMarking);
707 
708  // evaluate theta(target,domain) in three passes
709  FD_WARN("ControlledBuechiLiveness(): [POBS] -- evaluate theta for target/domain # "
710  << target.Size() << "/" << domain.Size());
711  theta.Clear();
712  controlsT.clear();
713 
714  // pass 1: find new candidate states and acumulate required controls
715  StateSet::Iterator sit = full.Begin();
716  StateSet::Iterator sit_end = full.End();
717  for(;sit!=sit_end;++sit) {
718  Idx cx=rControllerStatesMap[*sit];
719  bool pass = false;
720  bool fail = false;
721  disable.Clear();
722  enable.Clear();
723  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
724  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
725  for(;tit!=tit_end; ++tit) {
726  if(disable.Exists(tit->Ev)) continue;
727  if(target.Exists(tit->X2)) {enable.Insert(tit->Ev); pass = true; continue;}
728  if(domain.Exists(tit->X2)) {continue;}
729  if(!rCAlph.Exists(tit->Ev)){ fail = true; break;}
730  disable.Insert(tit->Ev);
731  }
732  if(pass && !fail) {
733  // initialize control with existing patterns
734  if(controlsT.find(cx)==controlsT.end()) {
735  if(controls1.find(cx)!=controls1.end())
736  controlsT[cx].merge(controls1[cx]);
737  if(controls1L.find(cx)!=controls1L.end())
738  controlsT[cx].merge(controls1L[cx]);
739  if(controls1X.find(cx)!=controls1X.end())
740  controlsT[cx].merge(controls1X[cx]);
741  }
742  // apply additional pattern
743  controlsT[cx].disable_all.InsertSet(disable);
744  controlsT[cx].enable_one.insert(enable);
745  }
746  } // end: theta pass 1
747 
748  // pass 2: merge new controls to controls1, reject conflicting
749  std::map< Idx , MCtrlPattern >::iterator cpit=controlsT.begin();
750  std::map< Idx , MCtrlPattern >::iterator cpit_end=controlsT.end();
751  while(cpit!=cpit_end) {
752  if(cpit->second.conflict()) {controlsT.erase(cpit++); continue;}
753  controls1[cpit->first].merge(cpit->second);
754  ++cpit;
755  }
756 
757  // pass 3: evaluate theta by accumulated controls control
758  sit = rSupCandGen.StatesBegin();
759  sit_end = rSupCandGen.StatesEnd();
760  for(;sit!=sit_end;++sit) {
761  bool pass = false;
762  bool fail = false;
763  Idx cx=rControllerStatesMap[*sit];
764  if(controls1.find(cx)==controls1.end()) continue;
765  disable=controls1[cx].disable_all;
766  TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit);
767  TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit);
768  for(;tit!=tit_end; ++tit) {
769  if(disable.Exists(tit->Ev)) continue;
770  if(target.Exists(tit->X2)) {pass = true; continue;}
771  if(domain.Exists(tit->X2)) {continue;}
772  fail = true;
773  }
774  if(pass && !fail) {
775  theta.Insert(*sit);
776  //FD_WARN("ControlledBuechiLiveness(): [POBS] theta candidate verified " << rSupCandGen.SStr(*sit));
777  }
778  } // end: theta pass 3
779 
780  // mu-loop on target1
781  target1.InsertSet(theta);
782  if(target1.Size()==t1sz) break;
783  if(target1.Size()==fsz) break;
784  } // end: mu
785 
786  FD_WARN("ControlledBuechiLiveness(): [POBS] -- mu-target1 # " << target1.Size());
787 
788  // nu-loop on domainL
789  domainL.RestrictSet(target1);
790  if(domainL.Size()==dsz) break;
791  if(domainL.Size()==0) break;
792  } // end: nu
793 
794  FD_WARN("ControlledBuechiLiveness(): [POBS] --- nu-domainL-mu-target1 # " << domainL.Size());
795 
796  // merge controls
797  std::map< Idx , MCtrlPattern>::iterator cit = controls1.begin();
798  std::map< Idx , MCtrlPattern>::iterator cit_end = controls1.end();
799  for(;cit!=cit_end;++cit)
800  controls1L[cit->first].merge(cit->second);
801 
802  // mu-loop on initialL
803  initialL.InsertSet(domainL);
804  if(initialL.Size()==t1Lsz) break;
805  if(initialL.Size()==fsz) break;
806  } // end: mu
807 
808  // nu-loop on initialK
809  initialK.RestrictSet(initialL);
810  if(initialK.Size()==rsz) break;
811  if(initialK.Size()==0) break;
812  } // end: nu
813 
814  // merge controls
815  std::map< Idx , MCtrlPattern>::iterator cit = controls1L.begin();
816  std::map< Idx , MCtrlPattern>::iterator cit_end = controls1L.end();
817  for(;cit!=cit_end;++cit)
818  controls1X[cit->first].merge(cit->second);
819 
820  // mu-loop on resolved
821  resolved.InsertSet(initialK);
822  if(resolved.Size()==xsz) break;
823  if(resolved.Size()==fsz) break;
824  } // end: mu
825 
826  // restrict candidate to valid restrict
827  rSupCandGen.DelStates(full - resolved);
828 
829  // debugging
830  if(rSupCandGen.IsCoaccessible())
831  FD_WARN("ControlledBuechiLiveness(): [POBS] ---- coaccessible ok");
832  if(rSupCandGen.IsComplete())
833  FD_WARN("ControlledBuechiLiveness(): [POBS] ---- complete ok");
834  if(!rSupCandGen.InitStates().Empty())
835  FD_WARN("ControlledBuechiLiveness(): [POBS] ---- init state ok");
836 
837  // re-write controls as feedback map (w.r.t. candidate states)
838  StateSet::Iterator sit = resolved.Begin();
839  StateSet::Iterator sit_end = resolved.End();
840  for(;sit!=sit_end;++sit) {
841  Idx cx=rControllerStatesMap[*sit];
842  //FD_WARN("ControlledBuechiLiveness(): [POBS] controls at cx=" << cx << " for plant state " << rSupCandGen.SStr(*sit) << " " << controls1X[cx].disable_all.ToString());
843  rFeedbackMap[*sit]= rSupCandGen.Alphabet() - controls1X[cx].disable_all;
844  }
845 
846  // done
847  return true;
848 }
849 
850 
851 /*
852 ***************************************************************************************
853 ***************************************************************************************
854  Implementation of SupBuechiCon and friends
855 ***************************************************************************************
856 ***************************************************************************************
857 */
858 
859 // helper class: omega-product state
860 class OPSState {
861 public:
862  // minimal interface
863  OPSState() {};
864  OPSState(const Idx& rq1, const Idx& rq2, const bool& rf) :
865  q1(rq1), q2(rq2), m1required(rf) {};
866  std::string Str(void) { return ToStringInteger(q1)+"|"+
868  // order
869  bool operator < (const OPSState& other) const {
870  if (q1 < other.q1) return(true);
871  if (q1 > other.q1) return(false);
872  if (q2 < other.q2) return(true);
873  if (q2 > other.q2) return(false);
874  if (m1required && !other.m1required) return(true);
875  return(false);
876  }
877  // member variables
881 };
882 
883 
884 // SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen)
886  const Generator& rPlantGen,
887  const EventSet& rCAlph,
888  const Generator& rSpecGen,
889  std::map< OPSState , Idx>& rProductCompositionMap,
890  Generator& rResGen)
891 {
892  FD_DF("SupBuechiConProduct(" << &rPlantGen << "," << &rSpecGen << ")");
893 
894  // prepare result
895  rResGen.Clear();
896  rResGen.InjectAlphabet(rPlantGen.Alphabet());
897 
898  // trivial case
899  if (rPlantGen.InitStatesEmpty()) {
900  FD_DF("SupBuechiConProduct: plant got no initial states. "
901  << "parallel composition contains empty language.");
902  return;
903  }
904  if (rSpecGen.InitStatesEmpty()) {
905  FD_DF("SupBuechiConProduct: spec got no initial states. "
906  << "parallel composition contains empty language.");
907  return;
908  }
909 
910  // todo stack
911  std::stack< OPSState > todo;
912  // current/next state as pair with flag
913  OPSState currentp, nextp;
914  // current/next state as target index
915  Idx currentt, nextt;
916  TransSet::Iterator ptit, ptit_end, stit, stit_end;
917  std::map< OPSState, Idx>::iterator rcit;
918  // critical states
919  StateSet critical;
920  // disabled events
921  EventSet disable;
922 
923 
924  // push initial state on todo stack
925  currentp = OPSState(*rPlantGen.InitStatesBegin(), *rSpecGen.InitStatesBegin(), true);
926  todo.push(currentp);
927  currentt=rResGen.InsInitState();
928  rProductCompositionMap[currentp] = currentt;
929 
930  // process/feed todo stack
931  FD_DF("SupBuechiConProduct: processing reachable states:");
932  while(!todo.empty()) {
933  // allow for user interrupt
934  // LoopCallback();
935  // allow for user interrupt, incl progress report
936  FD_WPC(rProductCompositionMap.size(),rProductCompositionMap.size()+todo.size(),"SupBuechiConProduct(): processing");
937  FD_DF("SupBuechiConProduct(): processing" << rProductCompositionMap.size() << " " << todo.size());
938  // get next reachable state from todo stack
939  currentp = todo.top();
940  currentt = rProductCompositionMap[currentp];
941  todo.pop();
942  // skip critical (tmoor 201308)
943  if(critical.Exists(currentt)) continue;
944  // report
945  FD_DF("SupBuechiConProduct: processing (" << currentp.Str() << " -> " << currentt <<")");
946 
947  // iterate over transitions, pass1: figure whether current state becomes critical (tmoor 201308)
948  ptit = rPlantGen.TransRelBegin(currentp.q1);
949  ptit_end = rPlantGen.TransRelEnd(currentp.q1);
950  stit = rSpecGen.TransRelBegin(currentp.q2);
951  stit_end = rSpecGen.TransRelEnd(currentp.q2);
952  disable.Clear();
953  // process all transitions and increment iterators strategically
954  while((ptit != ptit_end) && (stit != stit_end)) {
955  FD_DF("SupBuechiConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) );
956  FD_DF("SupBuechiConProduct: current spec-transition: " << rSpecGen.TStr(*stit));
957  // case A: execute common event
958  if(ptit->Ev == stit->Ev) {
959  nextp = OPSState(ptit->X2, stit->X2,currentp.m1required);
960  if(currentp.m1required) {
961  if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false;
962  } else {
963  if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true;
964  }
965  // figure whether successor state is known to be critical
966  rcit = rProductCompositionMap.find(nextp);
967  if(rcit != rProductCompositionMap.end()) {
968  if(critical.Exists(rcit->second)) {
969  FD_DF("SupBuechiConParallel: common event " << rSpecGen.EStr(stit->Ev) << " to a critical states");
970  // if event is uncontrollable, current state becomes critical
971  if(!rCAlph.Exists(ptit->Ev)) {
972  FD_DF("SupBuechiConProduct: critical insert" << currentt);
973  critical.Insert(currentt); // tmoor 201308
974  // exit all loops
975  ptit = ptit_end;
976  stit = stit_end;
977  break;
978  }
979  // else, event is disabled
980  disable.Insert(stit->Ev);
981  }
982  }
983  // increment transition
984  ++ptit;
985  ++stit;
986  }
987  // case B: process plant event that is disabled by the specification
988  else if (ptit->Ev < stit->Ev) {
989  FD_DF("SupConProduct: " << rPlantGen.EStr(ptit->Ev) << " is enabled in the plant but disabled in the specification");
990  // if the event is uncontrollable, this makes the current state critical
991  if (!rCAlph.Exists(ptit->Ev)) {
992  FD_DF("SupBuechiConProduct: disabled event " << rPlantGen.EStr(ptit->Ev) << " is uncontrollable");
993  FD_DF("SupBuechiConProduct: critical insert" << currentt);
994  critical.Insert(currentt);
995  // exit all loops
996  ptit = ptit_end;
997  stit = stit_end;
998  break;
999  }
1000  FD_DF("SupBuechiConProduct: incrementing plant transrel");
1001  ++ptit;
1002  }
1003  // increment titg and titg, case C: process h event that is not enabled for g
1004  else {
1005  FD_DF("SupBuechiConProduct: incrementing spec transrel");
1006  ++stit;
1007  }
1008  } // end while incrementing
1009  // increment iterators case D: process leftover events of plant
1010  while (ptit != ptit_end) {
1011  FD_DF("SupBuechiConProduct: current g-transition: " << rPlantGen.TStr(*ptit));
1012  FD_DF("SupBuechiConProduct: current h-transition: end");
1013  // if uncontrollable event leaves candidate
1014  if (!rCAlph.Exists(ptit->Ev)) {
1015  FD_DF("SupBuechiConProduct: asynchron executed uncontrollable "
1016  << "event " << rPlantGen.EStr(ptit->Ev) << " leaves specification:");
1017  FD_DF("SupConProduct: critical insert" << rPlantGen.SStr(currentt));
1018  critical.Insert(currentt);
1019  // exit this loop
1020  break;
1021  }
1022  FD_DF("SupBuechiConProduct: incrementing g transrel");
1023  ++ptit;
1024  } // end iterating pass1
1025 
1026  // skip critical (tmoor 201308)
1027  if(critical.Exists(currentt)) continue;
1028 
1029  // iterate over transitions, pass2: execute shared events (tmoor 201308)
1030  FD_DF("SupBuechiConProduct(): processing pass2");
1031  ptit = rPlantGen.TransRelBegin(currentp.q1);
1032  ptit_end = rPlantGen.TransRelEnd(currentp.q1);
1033  stit = rSpecGen.TransRelBegin(currentp.q2);
1034  stit_end = rSpecGen.TransRelEnd(currentp.q2);
1035  // process all transitions and increment iterators strategically
1036  while((ptit != ptit_end) && (stit != stit_end)) {
1037  FD_DF("SupBuechiConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) );
1038  FD_DF("SupBuechiConProduct: current spec-transition: " << rSpecGen.TStr(*stit));
1039  // case A: execute common event
1040  if(ptit->Ev == stit->Ev) {
1041  if(!disable.Exists(stit->Ev)) {
1042  FD_DF("SupBuechiConProduct: executing common event " << rPlantGen.EStr(ptit->Ev));
1043  nextp = OPSState(ptit->X2, stit->X2,currentp.m1required);
1044  if(currentp.m1required) {
1045  if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false;
1046  } else {
1047  if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true;
1048  }
1049  // figure target index
1050  rcit = rProductCompositionMap.find(nextp);
1051  // if state is new: add to todo list and result
1052  if(rcit == rProductCompositionMap.end()) {
1053  todo.push(nextp);
1054  nextt = rResGen.InsState();
1055  rProductCompositionMap[nextp] = nextt;
1056  if(!nextp.m1required)
1057  if(rSpecGen.ExistsMarkedState(nextp.q2))
1058  rResGen.SetMarkedState(nextt);
1059  FD_DF("SupBuechiConProduct: todo push: (" << nextp.Str() << ") -> " << nextt);
1060  } else {
1061  nextt = rcit->second;
1062  }
1063  // set the transition and increment iterators
1064  FD_DF("SupBuechierParallel: add transition to new generator: " << rResGen.TStr(Transition(currentt, ptit->Ev, nextt)));
1065  rResGen.SetTransition(currentt, ptit->Ev, nextt);
1066  }
1067  // increment transition
1068  ++ptit;
1069  ++stit;
1070  } // end: if processing common event
1071  // case B: process plant event that is disabled by the specification
1072  else if (ptit->Ev < stit->Ev) {
1073  ++ptit;
1074  }
1075  // increment titg and titg, case C: process h event that is not enabled for g
1076  else {
1077  ++stit;
1078  }
1079  } // end while incrementing for pass2
1080 
1081  } // while todo
1082 
1083  FD_DF("SupBuechiConProduct: deleting critical states: " << critical.ToString());
1084  rResGen.DelStates(critical);
1085 
1086  // restrict composition map
1087  std::map< OPSState , Idx>::iterator cit = rProductCompositionMap.begin();
1088  while(cit != rProductCompositionMap.end())
1089  if(!rResGen.ExistsState(cit->second)) rProductCompositionMap.erase(cit++);
1090  else cit++;
1091 
1092 }
1093 
1094 
1095 
1096 
1097 // SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen,rResGen)
1099  const Generator& rPlantGen,
1100  const EventSet& rCAlph,
1101  const Generator& rSpecGen,
1102  StateSet& rPlantMarking,
1103  Generator& rResGen)
1104 {
1105  FD_DF("SupBuechiConUnchecked(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")");
1106 
1107  // PREPARE RESULT:
1108  Generator* pResGen = &rResGen;
1109  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1110  pResGen= rResGen.New();
1111  }
1112  pResGen->Clear();
1113  pResGen->InjectAlphabet(rPlantGen.Alphabet());
1114 
1115  // controllable events
1116  FD_DF("SupBuechiCon: controllable events: " << rCAlph.ToString());
1117 
1118  // perform product
1119  std::map< OPSState , Idx> cmap;
1120  SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen);
1121 
1122  // figure plant marking
1123  rPlantMarking.Clear();
1124  std::map< OPSState, Idx>::iterator pcit;
1125  for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit)
1126  if(rPlantGen.ExistsMarkedState(pcit->first.q1))
1127  rPlantMarking.Insert(pcit->second);
1128 
1129  // fix statenames (debugging)
1130 #ifdef FAUDES_DEBUG_FUNCTION
1131  std::map< OPSState, Idx>::iterator dcit;
1132  for(dcit=cmap.begin(); dcit!=cmap.end(); ++dcit) {
1133  Idx x1=dcit->first.q1;
1134  Idx x2=dcit->first.q2;
1135  bool m1requ=dcit->first.m1required;
1136  Idx x12=dcit->second;
1137  if(!pResGen->ExistsState(x12)) continue;
1138  std::string name1= rPlantGen.StateName(x1);
1139  if(name1=="") name1=ToStringInteger(x1);
1140  std::string name2= rSpecGen.StateName(x2);
1141  if(name2=="") name1=ToStringInteger(x2);
1142  std::string name12;
1143  if(m1requ) name12= name1 + "|" + name2 + "|r1m";
1144  else name12= name1 + "|" + name2 + "|r2m";
1145  name12=pResGen->UniqueStateName(name12);
1146  pResGen->StateName(x12,name12);
1147  }
1148 #endif
1149 
1150 #ifdef FAUDES_DEBUG_FUNCTION
1151  pResGen->DWrite();
1152  pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen");
1153  pResGen->WriteStateSet(rPlantMarking);
1154 #endif
1155 
1156  // iterate for required properties
1157  while(true) {
1158  // catch trivial
1159  if(pResGen->Empty()) break;
1160  // fast inner loop: prefix controllability and omega-trim
1161  while(true) {
1162  Idx count1 = pResGen->Size();
1163  FD_WARN("SupBuechiCon: iterate: do prefix con on #" << pResGen->Size());
1164  SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen);
1165  FD_WARN("SupBuechiCon: iterate: do coaccessible on #" << pResGen->Size());
1166  pResGen->Coaccessible();
1167  FD_WARN("SupBuechiCon: iterate: do accessible on #" << pResGen->Size());
1168  pResGen->Accessible();
1169  FD_WARN("SupBuechiCon: iterate: do complete on #" << pResGen->Size());
1170  pResGen->Complete();
1171  if(pResGen->Size() == count1) break;
1172  if(pResGen->Size() == 0) break;
1173  }
1174  // slow outer loop: controlled liveness aka restrict to controllable prefix
1175  Idx count2 = pResGen->Size();
1176  FD_WARN("SupBuechiCon: iterate: do controlled liveness on #" << pResGen->Size());
1177  ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking);
1178  if(pResGen->Size() == count2) break;
1179  }
1180 
1181  // fix statenames ...
1182  std::map< OPSState, Idx>::iterator rcit;
1183  if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled())
1184  for(rcit=cmap.begin(); rcit!=cmap.end(); rcit++) {
1185  Idx x1=rcit->first.q1;
1186  Idx x2=rcit->first.q2;
1187  bool m1requ=rcit->first.m1required;
1188  Idx x12=rcit->second;
1189  if(!pResGen->ExistsState(x12)) continue;
1190  std::string name1= rPlantGen.StateName(x1);
1191  if(name1=="") name1=ToStringInteger(x1);
1192  std::string name2= rSpecGen.StateName(x2);
1193  if(name2=="") name1=ToStringInteger(x2);
1194  std::string name12;
1195  if(m1requ) name12= name1 + "|" + name2 + "|r1m";
1196  else name12= name1 + "|" + name2 + "|r2m";
1197  name12=pResGen->UniqueStateName(name12);
1198  pResGen->StateName(x12,name12);
1199  }
1200 
1201  // .. or clear them (?)
1202  if(!(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled()))
1203  pResGen->StateNamesEnabled(false);
1204 
1205  // copy result
1206  if(pResGen != &rResGen) {
1207  pResGen->Move(rResGen);
1208  delete pResGen;
1209  }
1210 
1211  FD_WARN("SupBuechiCon: return #" << rResGen.Size());
1212 }
1213 
1214 
1215 // SupConBuechiNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, rFeedbackMap, rResGen)
1217  const Generator& rPlantGen,
1218  const EventSet& rCAlph,
1219  const EventSet& rOAlph,
1220  const Generator& rSpecGen,
1221  StateSet& rPlantMarking,
1222  std::map< Idx , Idx >& rObserverStateMap,
1223  std::map< Idx , EventSet>& rFeedbackMap,
1224  Generator& rResGen)
1225 {
1226  FD_WARN("SupBuechiConNorm(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")");
1227 
1228  // prepare result
1229  Generator* pResGen = &rResGen;
1230  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1231  pResGen= rResGen.New();
1232  }
1233  pResGen->Clear();
1234  pResGen->InjectAlphabet(rPlantGen.Alphabet());
1235 
1236  // report events
1237  FD_WARN("SupBuechiConNorm: controllable events: " << rCAlph.ToString());
1238  FD_WARN("SupBuechiConNorm: un-observabel events: " << (rPlantGen.Alphabet()-rOAlph).ToString());
1239 
1240  // perform product
1241  std::map< OPSState , Idx> cmap;
1242  SupBuechiConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen);
1243  BuechiTrim(*pResGen);
1244 
1245  // no statenames impülemented
1246  pResGen->StateNamesEnabled(false);
1247 
1248  // figure plant marking
1249  rPlantMarking.Clear();
1250  std::map< OPSState, Idx>::iterator pcit;
1251  for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit)
1252  if(rPlantGen.ExistsMarkedState(pcit->first.q1))
1253  rPlantMarking.Insert(pcit->second);
1254 
1255  // extend by observer states
1256  Generator obsG= *pResGen;
1257  MarkAllStates(obsG);
1258  Project(obsG,rOAlph,obsG);
1259  InvProject(obsG,pResGen->Alphabet());
1260  std::map< std::pair<Idx,Idx>, Idx> rObserverCompositionMap;
1261  Product(*pResGen, obsG, rObserverCompositionMap, *pResGen);
1262  // track plantmarking
1263  StateSet fixmarking;
1264  std::map< std::pair<Idx,Idx>, Idx>::iterator cit;
1265  for(cit=rObserverCompositionMap.begin(); cit!=rObserverCompositionMap.end();++cit)
1266  if(rPlantMarking.Exists(cit->first.first)) fixmarking.Insert(cit->second);
1267  rPlantMarking=fixmarking;
1268  // construct reverse map "pResGen.State --> obsG.State"
1269  std::map< std::pair<Idx,Idx>, Idx>::iterator sit;
1270  for(sit=rObserverCompositionMap.begin(); sit!=rObserverCompositionMap.end();++sit)
1271  rObserverStateMap[sit->second]=sit->first.second;
1272 
1273 #ifdef FAUDES_DEBUG_FUNCTION
1274  pResGen->DWrite();
1275  pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen");
1276  pResGen->WriteStateSet(rPlantMarking);
1277 #endif
1278 
1279  FD_WARN("SupBuechiConNorm(): cand #" << pResGen->Size() << " obs #" << obsG.Size());
1280  // make resulting generator trim until it's fully controllable
1281  while(true) {
1282  // catch trivial
1283  if(pResGen->Empty()) break;
1284  // fast inner loop: prefix controllability and omega-trim
1285  while(true) {
1286  Idx count1 = pResGen->Size();
1287  FD_WARN("SupBuechiConNorm: iterate: do prefix-contr on #" << pResGen->Size());
1288  SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen);
1289  FD_WARN("SupBuechiConNorm: iterate: do accessible on #" << pResGen->Size());
1290  pResGen->Accessible();
1291  FD_WARN("SupBuechiConNorm: iterate: do coaccessible on #" << pResGen->Size());
1292  pResGen->Coaccessible();
1293  FD_WARN("SupBuechiConNorm: iterate: do prefix-norm on #" << pResGen->Size());
1294  SupConNormClosedUnchecked(rPlantGen, rOAlph, rOAlph, obsG, *pResGen);
1295  FD_WARN("SupBuechiConNorm: iterate: do coaccessible on #" << pResGen->Size());
1296  pResGen->Coaccessible();
1297  FD_WARN("SupBuechiConNorm: iterate: do accessible on #" << pResGen->Size());
1298  pResGen->Accessible();
1299  FD_WARN("SupBuechiConNorm: iterate: do complete on #" << pResGen->Size());
1300  pResGen->Complete();
1301  if(pResGen->Size() == count1) break;
1302  if(pResGen->Size() == 0) break;
1303  }
1304  // slow outer loop: controlled liveness
1305  Idx count2 = pResGen->Size();
1306  FD_WARN("SupBuechiConNorm: iterate: do controlled liveness on #" << pResGen->Size());
1307 
1308  // cosmetic: restrict observer map and count effective states
1309  std::map< Idx , Idx>::iterator oit = rObserverStateMap.begin();
1310  while(oit != rObserverStateMap.end())
1311  if(!pResGen->ExistsState(oit->first)) rObserverStateMap.erase(oit++);
1312  else oit++;
1313  std::set< Idx > ostates;
1314  for(oit = rObserverStateMap.begin(); oit != rObserverStateMap.end(); ++oit)
1315  ostates.insert(oit->second);
1316 
1317  //omega controlled liveness aka controllabe prefix
1318  FD_WARN("SupBuechiConNorm(): cand #" << pResGen->Size() << " obs #" << ostates.size());
1319  std::map< Idx , EventSet> feedback;
1320  ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking,rObserverStateMap,feedback);
1321  //ControlledBuechiLiveness(*pResGen,rCAlph,rPlantMarking);
1322  if(pResGen->Size() == count2) break;
1323  }
1324 
1325  // copy result
1326  if(pResGen != &rResGen) {
1327  pResGen->Move(rResGen);
1328  delete pResGen;
1329  }
1330 }
1331 
1332 
1333 /*
1334 ****************************************
1335 * SUPCON: WRAPPER / USER FUNCTIONS *
1336 ****************************************
1337 */
1338 
1339 
1340 // SupBuechiCon(rPlantGen, rCAlph, rSpecGen, rResGen)
1342  const Generator& rPlantGen,
1343  const EventSet& rCAlph,
1344  const Generator& rSpecGen,
1345  Generator& rResGen)
1346 {
1347  // consitenct check
1348  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
1349  // execute
1350  StateSet plantmarking;
1351  SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen);
1352  // record name
1353  rResGen.Name(CollapsString("SupBuechiCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1354 }
1355 
1356 
1357 // SupBuechiCon for Systems:
1358 // uses and maintains controllablity from plant
1360  const System& rPlantGen,
1361  const Generator& rSpecGen,
1362  Generator& rResGen) {
1363  // prepare result
1364  Generator* pResGen = &rResGen;
1365  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1366  pResGen= rResGen.New();
1367  }
1368  // execute
1369  SupBuechiCon(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
1370  // copy all attributes of input alphabet
1371  pResGen->EventAttributes(rPlantGen.Alphabet());
1372  // copy result
1373  if(pResGen != &rResGen) {
1374  pResGen->Move(rResGen);
1375  delete pResGen;
1376  }
1377 }
1378 
1379 // BuechiCon(rPlantGen, rCAlph, rSpecGen, rResGen)
1381  const Generator& rPlantGen,
1382  const EventSet& rCAlph,
1383  const Generator& rSpecGen,
1384  Generator& rResGen)
1385 {
1386 
1387  // consitency check
1388  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
1389  // compute supremal closed-loop behaviour
1390  StateSet plantmarking;
1391  SupBuechiConUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen);
1392  // compute restrictive feedback
1393  std::map< Idx , EventSet> feedback;
1394  ControlledBuechiLiveness(rResGen, rCAlph, plantmarking, feedback);
1395  // apply restrictive feedback
1396  StateSet::Iterator sit = rResGen.StatesBegin();
1397  StateSet::Iterator sit_end = rResGen.StatesEnd();
1398  for(;sit!=sit_end;++sit) {
1399  const EventSet& pattern = feedback[*sit];
1400  TransSet::Iterator tit = rResGen.TransRelBegin(*sit);
1401  TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit);
1402  while(tit!=tit_end) {
1403  if(pattern.Exists(tit->Ev)) { tit++; continue;};
1404  rResGen.ClrTransition(tit++);
1405  }
1406  }
1407  // cosmetic trim
1408  rResGen.Trim();
1409 
1410 #ifdef FAUDES_CODE
1411  // during development: test controllability and livenes
1412  if(!IsControllable(rPlantGen,rCAlph,rResGen)) {
1413  throw Exception("BuechiCon(..)", "ERROR: controllability test failed", 500);
1414  }
1415  if(!IsBuechiRelativelyClosed(rPlantGen,rResGen)) {
1416  throw Exception("BuechiCon(..)", "ERROR: rel. top. closedness test failed", 500);
1417  }
1418 #endif
1419 
1420  // record name
1421  rResGen.Name(CollapsString("BuechiCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1422 }
1423 
1424 // BuechiCon for Systems:
1425 // uses and maintains controllablity from plant
1427  const System& rPlantGen,
1428  const Generator& rSpecGen,
1429  Generator& rResGen) {
1430  // prepare result
1431  Generator* pResGen = &rResGen;
1432  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1433  pResGen= rResGen.New();
1434  }
1435  // execute
1436  BuechiCon(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
1437  // copy all attributes of input alphabet
1438  pResGen->EventAttributes(rPlantGen.Alphabet());
1439  // copy result
1440  if(pResGen != &rResGen) {
1441  pResGen->Move(rResGen);
1442  delete pResGen;
1443  }
1444 }
1445 
1446 
1447 // SupBuechiConNorm(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen)
1449  const Generator& rPlantGen,
1450  const EventSet& rCAlph,
1451  const EventSet& rOAlph,
1452  const Generator& rSpecGen,
1453  Generator& rResGen)
1454 {
1455  // consitenct check
1456  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen);
1457  // execute
1458  std::map< Idx , Idx> constates;
1459  std::map< Idx , EventSet> feedback;
1460  StateSet plantmarking;
1461  SupBuechiConNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, constates, feedback, rResGen);
1462  // record name
1463  rResGen.Name(CollapsString("SupBuechiConNorm(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1464 }
1465 
1466 
1467 // SupBuechiConNorm for Systems:
1468 // uses and maintains controllablity from plant
1470  const System& rPlantGen,
1471  const Generator& rSpecGen,
1472  Generator& rResGen) {
1473  // prepare result
1474  Generator* pResGen = &rResGen;
1475  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1476  pResGen= rResGen.New();
1477  }
1478  // execute
1479  SupBuechiConNorm(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(),rSpecGen,*pResGen);
1480  // copy all attributes of input alphabet
1481  pResGen->EventAttributes(rPlantGen.Alphabet());
1482  // copy result
1483  if(pResGen != &rResGen) {
1484  pResGen->Move(rResGen);
1485  delete pResGen;
1486  }
1487 }
1488 
1489 // BuechiConNrm(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen)
1491  const Generator& rPlantGen,
1492  const EventSet& rCAlph,
1493  const EventSet& rOAlph,
1494  const Generator& rSpecGen,
1495  Generator& rResGen)
1496 {
1497 
1498  // consitency check
1499  ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen);
1500  // compute supremal closed-loop behaviour
1501  StateSet plantmarking;
1502  std::map< Idx , Idx> cxmap;
1503  std::map< Idx , EventSet> feedback;
1504  SupBuechiConNormUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, cxmap, feedback, rResGen);
1505  // compute restrictive feedback
1506  ControlledBuechiLiveness(rResGen, rCAlph, plantmarking, cxmap, feedback);
1507  // apply restrictive feedback
1508  StateSet::Iterator sit = rResGen.StatesBegin();
1509  StateSet::Iterator sit_end = rResGen.StatesEnd();
1510  for(;sit!=sit_end;++sit) {
1511  // Idx cx = cxmap[*sit]; etc ...
1512  const EventSet& pattern = feedback[*sit];
1513  TransSet::Iterator tit = rResGen.TransRelBegin(*sit);
1514  TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit);
1515  while(tit!=tit_end) {
1516  if(pattern.Exists(tit->Ev)) { tit++; continue;};
1517  rResGen.ClrTransition(tit++);
1518  }
1519  }
1520  // trim (?)
1521  BuechiTrim(rResGen);
1522 //#ifdef FAUDES_CODE
1523  // during development: test controllability, normality and livenes
1524  if(!IsControllable(rPlantGen,rCAlph,rResGen)) {
1525  throw Exception("BuechiConNorm(..)", "ERROR: controllability test failed", 500);
1526  }
1527  if(!IsBuechiRelativelyClosed(rPlantGen,rResGen)) {
1528  throw Exception("BuechiConNorm(..)", "ERROR: rel. top. closedness test failed", 500);
1529  }
1530  Generator prK=rResGen;
1531  MarkAllStates(prK);
1532  Generator prL=rPlantGen;
1533  prL.Trim();
1534  MarkAllStates(prL);
1535  if(!IsNormal(prL,rOAlph,prK)){
1536  throw Exception("BuechiConNorm(..)", "ERROR: prefix normality test failed", 500);
1537  }
1538 //#endif
1539 
1540  // record name
1541  rResGen.Name(CollapsString("BuechiConNorm(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
1542 }
1543 
1544 // BuechiConNorm for Systems
1545 // uses and maintains controllablity from plant
1547  const System& rPlantGen,
1548  const Generator& rSpecGen,
1549  Generator& rResGen) {
1550  // prepare result
1551  Generator* pResGen = &rResGen;
1552  if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
1553  pResGen= rResGen.New();
1554  }
1555  // execute
1556  BuechiConNorm(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(), rSpecGen,*pResGen);
1557  // copy all attributes of input alphabet
1558  pResGen->EventAttributes(rPlantGen.Alphabet());
1559  // copy result
1560  if(pResGen != &rResGen) {
1561  pResGen->Move(rResGen);
1562  delete pResGen;
1563  }
1564 }
1565 
1566 
1567 
1568 } // name space
#define FD_WPC(cntnow, contdone, message)
#define FD_WARN(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:1787
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2180
virtual void Clear(void)
Definition: cfl_baseset.h:1962
Iterator End(void) const
Definition: cfl_baseset.h:1956
virtual void RestrictSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2129
virtual void InsertSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2052
Iterator Begin(void) const
Definition: cfl_baseset.h:1951
Idx Size(void) const
Definition: cfl_baseset.h:1782
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)
bool IsBuechiRelativelyClosed(const Generator &rGenPlant, const Generator &rGenCand)
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)
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.33h --- 2025.06.18 --- c++ api documentaion by doxygen