omg_rabinctrl.cpp
Go to the documentation of this file.
1 /** @file omg_rabinctrl.cpp Controller synthesis for Rabin automata */
2 
3 
4 /*
5 FAU Discrete Event Systems Library (libFAUDES)
6 
7 Copyright (C) 2025 Thomas Moor
8 
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13 
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18 
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23 
24 
25 
26 #include "omg_rabinctrl.h"
27 #include "omg_rabinfnct.h"
28 #include "syn_include.h"
29 
30 // local debug via FD_DF
31 //#undef FD_DF
32 //#define FD_DF(m) FD_WARN(m)
33 
34 // local debug via FAUDES_DEBUG_RABINCTRL
35 //#define FAUDES_DEBUG_RABINCTRL
36 
37 namespace faudes {
38 
39 /*
40 *****************************************************************
41 *****************************************************************
42 *****************************************************************
43 
44 Implementation of the fixpoint iteration proposed by Thistle/Wonham
45 in "Control of w-Automata, Church's Problem, and the Emptiness Problem
46 for Tree w-Automata", 1992.
47 
48 The iteration is ran on a transitions structure with two independent
49 acceptance conditions, one Rabin and one Buechi. The result is the so
50 so called controllable set, i.e., the set of states for which there
51 exit individual control patterns such that in the controlled system,
52 the Buechi acceptance condition (think of plant liveness properties)
53 implies the Rabin acceptance condition (think of specification
54 liveness requirements).
55 
56 At the current stage we only address specifications with a single
57 Rabin pair, as this is our current use case.
58 
59 *****************************************************************
60 *****************************************************************
61 *****************************************************************
62 */
63 
64 /*
65 Base class for my operators to hold context
66 */
68 protected:
69  /** record context references */
70  const vGenerator& rGen;
71  const StateSet& rDomain;
76  /** record control patterns */
77  bool mRecCtrl=false;
79 public:
80  /** construct to record context */
82  const vGenerator& gen, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
83  :
85  rGen(gen),
86  rDomain(gen.States()),
87  rMarkedStates(gen.MarkedStates()),
88  rTransRel(gen.TransRel()),
89  rRevTransRel(revtrans),
90  mSigmaCtrl(sigctrl),
91  mRecCtrl(false)
92  {
93  Name("void base class rabin-inv-dynamics operator");
94  mArgCount=0;
95  };
96  /** overaall stateset */
97  virtual const StateSet& Domain(void) const {
98  return rDomain;
99  }
100  /** access control flag */
101  void RecCtrl(bool on) { mRecCtrl=on; }
102  bool RecCtrl(void) { return mRecCtrl; }
103  /** acces control pattern */
105  const TaIndexSet<EventSet>& Controller(void) const { return mController; }
106  void ClrCtrl(void) { mController.Clear(); }
107  void InsCtrl(const RabinInvDynOperator& rOther) {
108  if(!mRecCtrl) return;
109  const TaIndexSet<EventSet>& otherctrl=rOther.Controller();
110  IndexSet::Iterator sit=otherctrl.Begin();
111  IndexSet::Iterator sit_end=otherctrl.End();
112  for(;sit!=sit_end;++sit)
113  if(!mController.Exists(*sit))
114  mController.Insert(*sit,otherctrl.Attribute(*sit));
115  }
116 };
117 
118 
119 /*
120 Inverse dynamics operator theta
121 
122 Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
123 Problem for Tree w-Automata", 1992, Def 8.2:
124 
125 theta(X1,X2) = "the set of states, from which the automaton can be controlled to
126 enter X1 union X2 in a single transition without being prevented from entering X1."
127 
128 Rephrase: X1 is the target T, X1 union X2 is the domain D; control such that immediate
129 successors stay within within D and there is the chance to enter the T.
130 
131 We use "Z1/Z2" argument names to avoid confusion with libFAUDES naming conventions.
132 */
134 public:
135  /** construct to record context */
137  const vGenerator& gen, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
138  :
139  RabinInvDynOperator(gen,revtrans,sigctrl)
140  {
141  FD_DF("RabinInvDynTheta(): instantiated for " << rGen.Name());
142  Name("theta([Z1,Z2])");
143  mArgNames= std::vector<std::string>{"Z1","Z2"};
144  mArgCount=2;
145  };
146 protected:
147  /** loop local vars */
149  /** actual operator implementation */
150  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
151  // convenience accesors
152  const StateSet& Z1=rArgs.At(0);
153  const StateSet& Z2=rArgs.At(1);
154  // do operate
156  StateSet::Iterator sit=rRes.Begin();
157  StateSet::Iterator sit_end=rRes.End();
158  while(sit!=sit_end){
159  if(mRecCtrl) mDisable.Clear();
161  TransSet::Iterator tit_end=rTransRel.End(*sit);
162  bool enterZ1 = false;
163  bool exitZ12 = false;
164  for(;tit!=tit_end;++tit){
165  // successor is in Z1: will not disable, found evidence to enter Z1
166  if(Z1.Exists(tit->X2)) {enterZ1=true; continue;}
167  // successor is in Z2: will not disable
168  if(Z2.Exists(tit->X2)) {continue;}
169  // sucessor is neither in Z1 nor Z2: need to disable
170  if(!mSigmaCtrl.Exists(tit->Ev)){exitZ12 = true; break;}
171  // record controls
172  if(mRecCtrl) mDisable.Insert(tit->Ev);
173  }
174  // failed
175  if(!enterZ1 || exitZ12) {rRes.Erase(sit++); continue;}
176  // success
177  if(mRecCtrl) mController.Insert(*sit,rGen.Alphabet()-mDisable);
178  ++sit;
179  }
180 
181  };
182 };
183 
184 
185 /*
186 Inverse dynamics operator theta-tilde
187 
188 Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
189 Problem for Tree w-Automata", 1992, Def 8.3:
190 
191 "theta_tilde(X1,X2)=nu X3 mu X4 theta( X1 + (X4 - R), (X3 - R) * X2 ) ")
192 
193 We first implement the core formula without the nu/mu iteration and then apply nu/mu.
194 We use "Y1/Y2/Y3/Y4" --> "Z1/Z2" argument names
195 */
197 public:
198  /** construct to record context */
200  const vGenerator& gen, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
201  :
202  RabinInvDynTheta(gen,revtrans,sigctrl)
203  {
204  FD_DF("RabinInvDynThetaTildeCore(): instantiated for " << rGen.Name());
205  Name("theta_tilde_core([Y1,Y2,Y3,Y4])");
206  mArgNames= std::vector<std::string>{"Y1","Y2","Y3","Y4"};
207  mArgCount=4;
208  };
209 protected:
210  /** actual operator implementation */
211  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
212  // convenience acsesors
213  const StateSet& Y1=rArgs.At(0);
214  const StateSet& Y2=rArgs.At(1);
215  const StateSet& Y3=rArgs.At(2);
216  const StateSet& Y4=rArgs.At(3);
217  StateSetVector args;
218  args.Size(2);
219  StateSet& Z1=args.At(0);
220  StateSet& Z2=args.At(1);
221  // do operate
222  Z1= Y1 + (Y4 - rMarkedStates);
223  Z2= Y2 * (Y3 - rMarkedStates);
224  RabinInvDynTheta::DoEvaluate(args,rRes);
225  };
226 };
227 
228 
229 /*
230 Inverse dynamics operator theta tilde, inner mu iteration
231 */
233 protected:
234  /** additional context */
237 public:
238  /** construct to record context */
240  const vGenerator& gen, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
241  :
242  RabinInvDynOperator(gen,revtrans,sigctrl),
243  mThetaCore(gen,revtrans,sigctrl),
245  {
246  FD_DF("RabinInvDynThetaTildeInner(): instantiated for " << rGen.Name());
247  Name("theta_tilde_inner_mu([Y1,Y2,Y3])");
248  mArgNames= std::vector<std::string>{"Y1","Y2","Y3"};
249  mArgCount=3;
250  };
251 protected:
252  /** actual operator implementation */
253  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
254  // pass on ctrl record flag
257  // run mu iteration
258  mMuThetaCore.Evaluate(rArgs, rRes);
259  // merge controller
261  };
262 };
263 
264 
265 /*
266 Inverse dynamics operator theta tilde, outer nu iteration
267 */
269 protected:
270  /** additional context */
273 public:
274  /** construct to record context */
276  const vGenerator& gen, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
277  :
278  RabinInvDynOperator(gen,revtrans,sigctrl),
279  mMuThetaCore(gen,revtrans,sigctrl),
281  {
282  FD_DF("RabinInvDynThetaTilde(): instantiated for " << rGen.Name());
283  Name("theta_tilde([Y1,Y2])");
284  mArgNames= std::vector<std::string>{"Y1","Y2"};
285  mArgCount=2;
286  };
287 protected:
288  /** actual operator implementation */
289  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
290  // plain fixpoint, dont record in inner mu
291  mMuThetaCore.RecCtrl(false);
292  mNuMuThetaCore.Evaluate(rArgs, rRes);
293  // if we have been asked to record, run mu again with nu-var set to fixpoint
294  if(mRecCtrl) {
295  StateSetVector args;
296  args.AssignByReference(rArgs);
297  args.PushBack(&rRes);
298  mMuThetaCore.RecCtrl(true);
299  StateSet dummy;
300  mMuThetaCore.Evaluate(args,dummy);
302 #ifdef FAUDES_DEBUG
303  if(!dummy.Equal(rRes)) {
304  FD_ERR("RabinInvDynThetaTilde: internal errror in secondary run of mu iteration")
305  }
306 #endif
307  }
308  };
309 };
310 
311 
312 /*
313 P-reach operator
314 
315 Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
316 Problem for Tree w-Automata", 1992, Def 8.4
317 
318 p-reach(X1,X2)= mu X3 . theta-tilde(X1,X) union theta-tilde((X1 u X2 u X3, I_p))
319 
320 We first implement the core formular without the nu/mu iteration, and then do the
321 mu iteration
322 
323 We use "U1/U2/U3"
324 */
326  /** additional context */
328  RabinAcceptance::CIterator mRPit;
329 public:
330  /** construct to record context */
332  const RabinAutomaton& raut, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
333  :
334  RabinInvDynOperator(raut,revtrans,sigctrl),
335  mThetaTilde(raut,revtrans,sigctrl),
336  mRPit(raut.RabinAcceptance().Begin())
337  {
338  FD_DF("RabinInvDynPReachCore(): instantiated for " << rGen.Name());
339  Name("p_reach_core([U1,U2,U3)");
340  mArgNames= std::vector<std::string>{"U1","U2","U3"};
341  mArgCount=3;
342  };
343 protected:
344  /** actual operator implementation */
345  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
346  // pass on rec flag
349  // convenience accessors
350  const StateSet& U1=rArgs.At(0);
351  const StateSet& U2=rArgs.At(1);
352  const StateSet& U3=rArgs.At(2);
353  StateSetVector args;
354  args.Size(2);
355  StateSet& Y1=args.At(0);
356  StateSet& Y2=args.At(1);
357  // do operate a
358  Y1=U1;
359  Y2=Domain();
360  mThetaTilde.Evaluate(args,rRes);
362  // do operate b
363  Y1=U1+U2+U3;
364  Y2=mRPit->ISet();
365  StateSet rhs;
366  mThetaTilde.Evaluate(args,rhs);
368  rRes.InsertSet(rhs);
369  //std::cout << "p_reach_core: ctrl #" << mController.Size() << std::endl;
370  };
371 };
372 
373 /** p-reach operator, mu iteration */
375 protected:
376  /** have additional context */
379 public:
380  /** construct to record context */
382  const RabinAutomaton& raut, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
383  :
384  RabinInvDynOperator(raut,revtrans,sigctrl),
385  mPReachCore(raut,revtrans,sigctrl),
387  {
388  FD_DF("RabinInvDynPReach(): instantiated for " << rGen.Name());
389  Name("p_reach([O1,O2])");
390  mArgNames= std::vector<std::string>{"O1","O2"};
391  mArgCount=2;
392  };
393 protected:
394  /** actual operator implementation */
395  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
396  // pass on ctrl record flag
399  // run mu iteration
400  mMuPReachCore.Evaluate(rArgs, rRes);
401  // merge controller
403  //std::cout << "p_reach: ctrl #" << mController.Size() << std::endl;
404  };
405 };
406 
407 /*
408 Controllable subset
409 
410 Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
411 Problem for Tree w-Automata", 1992, Def 8.5
412 
413 CA = mu X1 nu X2 . p-reach(X1, X2 * Rp)
414 
415 We first implement the core formula without the mu/nu iteration, and then do the mu/nu.
416 
417 */
419  /** additional context */
420  RabinAcceptance::CIterator mRPit;
421 public:
422  /** construct to record context */
424  const RabinAutomaton& raut, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
425  :
426  RabinInvDynPReach(raut,revtrans,sigctrl),
427  mRPit(raut.RabinAcceptance().Begin())
428  {
429  FD_DF("RabinInvDynCtrlCore(): instantiated for " << rGen.Name());
430  Name("ctrl_core([X1,X2])");
431  mArgNames= std::vector<std::string>{"X1","X2"};
432  mArgCount=2;
433  };
434 protected:
435  /** actual operator implementation */
436  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
437  // convenience accessors
438  const StateSet& X1=rArgs.At(0);
439  const StateSet& X2=rArgs.At(1);
440  StateSetVector args;
441  args.Size(2);
442  StateSet& O1=args.At(0);
443  StateSet& O2=args.At(1);
444  // do operate
445  O1=X1;
446  O2=X2 * mRPit->RSet();
448  };
449 };
450 
451 /** controllable set, inner nu iteration */
453 protected:
454  /** have additional context */
457 public:
458  /** construct to record context */
460  const RabinAutomaton& raut, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
461  :
462  RabinInvDynOperator(raut,revtrans,sigctrl),
463  mCtrlCore(raut,revtrans,sigctrl),
465  {
466  FD_DF("RabinInvDynCtrlInner(): instantiated for " << rGen.Name());
467  Name("ctrl_inner_nu([X1])");
468  mArgNames= std::vector<std::string>{"X1"};
469  mArgCount=1;
470  };
471 protected:
472  /** actual operator implementation */
473  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
474  // plain fixpoint, dont record
475  mCtrlCore.RecCtrl(false);
476  mNuCtrlCore.Evaluate(rArgs, rRes);
477  // if we have been asked to record, nu-var set to fixpoint
478  if(mRecCtrl) {
479  StateSetVector args;
480  args.AssignByReference(rArgs);
481  args.PushBack(&rRes);
482  mCtrlCore.RecCtrl(true);
483  StateSet dummy;
484  mCtrlCore.Evaluate(args,dummy);
486 #ifdef FAUDES_DEBUG
487  if(!dummy.Equal(rRes)) {
488  FD_ERR("RabinInvDynCtrlInner: internal errror in secondary run of mu iteration")
489  }
490 #endif
491  std::cout << "ctrl_inner: ctrl #" << mController.Size() << std::endl;
492  }
493  };
494 };
495 
496 /** controllable set, outer mu iteration */
498 protected:
499  /** have additional context */
502 public:
503  /** construct to record context */
505  const RabinAutomaton& raut, const TransSetX2EvX1& revtrans, const EventSet& sigctrl)
506  :
507  RabinInvDynOperator(raut,revtrans,sigctrl),
508  mNuCtrlCore(raut,revtrans,sigctrl),
510  {
511  FD_DF("RabinInvDynCtrl(): instantiated for " << rGen.Name());
512  Name("ctrl()");
513  mArgCount=0;
514  };
515 protected:
516  /** actual operator implementation */
517  virtual void DoEvaluate(StateSetVector& rArgs, StateSet& rRes) {
518  // pass on ctrl record flag
521  // run mu iteration
522  mMuNuCtrlCore.Evaluate(rArgs, rRes);
523  // merge controller
525  std::cout << "ctrl: ctrl #" << mController.Size() << std::endl;
526  };
527 };
528 
529 
530 /*
531 *****************************************************************
532 *****************************************************************
533 *****************************************************************
534 
535 API wrappers to compute the controllability prefix. The latter is
536 defined by Thistle/Wonham in "Supervision of Infinite Behavior of
537 Discrete-Event Systems, 1994. It is the star-language which consists
538 of all words such that thereafter a controller exits to enforce
539 the specification. The controllability prefix relates to the
540 controllable set as follows:
541 
542 Given a plant L and a specification E subseteq L, assume we have
543 a transition systems such that L is accepted by a Buechi acceptance
544 condition and E is appected by a Rabin aceptance condition. We refer
545 to this as the candidate. The controllable set of the candidate then
546 marks the controllability prefix on the same transition structur.
547 
548 
549 *****************************************************************
550 *****************************************************************
551 *****************************************************************
552 */
553 
554 // API
556  const RabinAutomaton& rRAut, const EventSet& rSigmaCtrl,
557  StateSet& rCtrlPfx)
558 {
559  // can only handle one Rabin pair
560  if(rRAut.RabinAcceptance().Size()!=1){
561  std::stringstream errstr;
562  errstr << "the current implementation requires exactly one Rabin pair";
563  throw Exception("RabinCtrlPfx", errstr.str(), 80);
564  }
565  // set up various helper
566  TransSetX2EvX1 revtrans(rRAut.TransRel());
567  EventSet sigctrl(rSigmaCtrl);
568  // have operator
569  RabinInvDynCtrl ctrl(rRAut,revtrans,sigctrl);
570  // run
571  ctrl.Evaluate(rCtrlPfx);
572 };
573 
574 
575 // API
577  const RabinAutomaton& rRAut, const EventSet& rSigmaCtrl,
578  TaIndexSet<EventSet>& rController)
579 {
580  // can only handle one Rabin pair
581  if(rRAut.RabinAcceptance().Size()!=1){
582  std::stringstream errstr;
583  errstr << "the current implementation requires exactly one Rabin pair";
584  throw Exception("RabinCtrlPfx", errstr.str(), 80);
585  }
586  // set up various helper
587  TransSetX2EvX1 revtrans(rRAut.TransRel());
588  EventSet sigctrl(rSigmaCtrl);
589  // have operator
590  RabinInvDynCtrl ctrl(rRAut,revtrans,sigctrl);
591  ctrl.RecCtrl(true);
592  // run
593  StateSet ctrlpfx;
594  ctrl.Evaluate(ctrlpfx);
595  rController.Assign(ctrl.Controller());
596 };
597 
598 
599 // API void RabinCtrlPfx(
601  const RabinAutomaton& rRAut, const EventSet& rSigmaCtrl,
602  Generator& rResGen)
603 {
604  // prepare result
605  Generator* pResGen = &rResGen;
606  if(dynamic_cast<RabinAutomaton*>(&rResGen)== &rRAut) {
607  pResGen= rResGen.New();
608  }
609  pResGen->Clear();
610  pResGen->Name(CollapsString("CtrlPfx("+rRAut.Name()+")"));
611 
612  // do run
613  StateSet ctrlpfx;
614  RabinCtrlPfx(rRAut,rSigmaCtrl,ctrlpfx);
615  pResGen->Assign(rRAut);
616  pResGen->InjectMarkedStates(ctrlpfx);
617  pResGen->Trim();
618 
619  // copy result
620  if(pResGen != &rResGen) {
621  pResGen->Move(rResGen);
622  delete pResGen;
623  }
624 }
625 
626 /*
627 *****************************************************************
628 *****************************************************************
629 *****************************************************************
630 
631 API wrappers for the supremal omega-controllable sublanguage.
632 
633 The supremal controllable sublanguage relates to the controllability
634 prefix as follows.
635 
636 Given a plant L and a specification E, set up the candidate and
637 compute the controllability prexis CFX. Then
638 
639 K := lim sup-closed-sublanguage(CFX) cap E
640 
641 is the supremal omega-controllable sublanguage of E.
642 
643 Thistle/Wonham give in " Supervision of Infinite Behavior of Discrete-Event",
644 1994, the slightly different formula
645 
646 K := lim sup-closed-and-controllabe--sublanguage(CFX) cap E,
647 
648 but since only controllable envents can exit CFX to pre L both
649 formulae should yield the same result.
650 
651 *****************************************************************
652 *****************************************************************
653 *****************************************************************
654 */
655 
656 // API warpper
658  const Generator& rBPlant,
659  const EventSet& rCAlph,
660  const RabinAutomaton& rRSpec,
661  RabinAutomaton& rRes)
662 {
663  // consitenct check
664  ControlProblemConsistencyCheck(rBPlant, rCAlph, rRSpec);
665  // prepare result
666  bool snames= rBPlant.StateNamesEnabled() && rRSpec.StateNamesEnabled() && rRes.StateNamesEnabled();
667  RabinAutomaton* pRes = &rRes;
668  if(dynamic_cast<Generator*>(pRes)== &rBPlant || pRes== &rRSpec) {
669  pRes= rRes.New();
670  }
671  // execute: set up closed loop candidate
672  pRes->Assign(rRSpec);
673  pRes->ClearMarkedStates();
674  Automaton(*pRes);
675  RabinBuechiProduct(*pRes,rBPlant,*pRes);
676  // execute: compute controllability prefix
677  StateSet ctrlpfx;
678  RabinCtrlPfx(*pRes,rCAlph,ctrlpfx);
679  // execute: trim
680  pRes->ClearMarkedStates();
681  pRes->InsMarkedStates(ctrlpfx);
682  SupClosed(*pRes,*pRes);
683  pRes->ClearMarkedStates();
684  pRes->RestrictStates(pRes->States()); // fix Rabin pairs
685  // record name
686  pRes->Name(CollapsString("SupRabinCon(("+rBPlant.Name()+"),("+rRSpec.Name()+"))"));
687  // copy result
688  if(pRes != &rRes) {
689  pRes->Move(rRes);
690  delete pRes;
691  }
692 }
693 
694 
695 // SupRabinCon for Systems:
696 // uses and maintains controllablity from plant
698  const System& rBPlant,
699  const RabinAutomaton& rRSpec,
700  RabinAutomaton& rRes)
701 {
702  // prepare result
703  RabinAutomaton* pRes = &rRes;
704  if(dynamic_cast<Generator*>(pRes)== &rBPlant || pRes== &rRSpec) {
705  pRes= rRes.New();
706  }
707  pRes->StateNamesEnabled(rRes.StateNamesEnabled());
708  // execute
709  SupRabinCon(rBPlant, rBPlant.ControllableEvents(),rRSpec,*pRes);
710  // copy all attributes of input alphabet
711  pRes->EventAttributes(rBPlant.Alphabet());
712  // copy result
713  if(pRes != &rRes) {
714  pRes->Move(rRes);
715  delete pRes;
716  }
717 }
718 
719 
720 /*
721 *****************************************************************
722 *****************************************************************
723 *****************************************************************
724 
725 API wrappers for controller syntheis.
726 
727 Technically, neither the supremal omega-controllable sublanguage
728 K nor the controllility prefix CFX are controllers. But CFX lends
729 itself as a basis to extract a controller. We provide two variants.
730 
731 a)
732 The greedy controller will attempts to achieve yat another R-state
733 as fast as possible. This is a rather restrictive policy but it does
734 the job.
735 
736 b)
737 Given a lower bound specification A, let the plant run freely
738 until it exits pre A. Then apply the greedy controller. This
739 requires the relative closure of A w.r.t the plant to be within
740 K
741 
742 *****************************************************************
743 *****************************************************************
744 *****************************************************************
745 */
746 
747 
748 // API warpper
750  const Generator& rBPlant,
751  const EventSet& rCAlph,
752  const RabinAutomaton& rRSpec,
753  Generator& rRes)
754 {
755  // consitency check
756  ControlProblemConsistencyCheck(rBPlant, rCAlph, rRSpec);
757 
758  // execute: set up closed loop candidate
759  bool snames= rBPlant.StateNamesEnabled() && rRSpec.StateNamesEnabled() && rRes.StateNamesEnabled();
760  RabinAutomaton cand;
761  cand.Assign(rRSpec);
762  cand.StateNamesEnabled(snames);
763  cand.ClearMarkedStates();
764  Automaton(cand);
765  RabinBuechiProduct(cand,rBPlant,cand);
766 
767  // execute: compute controllability prefix incl greedy controller
768  TaIndexSet<EventSet> controller;
769  RabinCtrlPfx(cand,rCAlph,controller);
770 
771  // execute: trim to generate pre supcon
772  Generator gcand=cand;
773  gcand.ClearMarkedStates();
774  gcand.InsMarkedStates(controller);
775  SupClosed(gcand,gcand);
776  gcand.ClearMarkedStates();
777 
778  // cosmetic: recover plant Buechi acceptance
779  StateSet pbuechi = cand.MarkedStates() * gcand.States();
780  gcand.InsMarkedStates(pbuechi);
781 
782  // execute: apply control patterns
783  TransSet::Iterator tit=gcand.TransRelBegin();
784  Idx cx=0;
785  const EventSet* pctrlpat=nullptr;
786  while(tit!=gcand.TransRelEnd()) {
787  if(cx!=tit->X1) {
788  cx=tit->X1;
789  pctrlpat=nullptr;
790  if(controller.Exists(cx))
791  pctrlpat=&controller.Attribute(cx);
792  }
793  if(pctrlpat==nullptr) {
794  FD_ERR("RabinCtrl: greedy: controller incomplete");
795  }
796  if(pctrlpat->Exists(tit->Ev)) {
797  ++tit;
798  } else {
799  gcand.ClrTransition(tit++);
800  }
801  }
802 
803  // execute: polish
804  gcand.Accessible();
805  gcand.Move(rRes);
806  rRes.Name(CollapsString("RabinCtrl(("+rBPlant.Name()+"),("+rRSpec.Name()+"))"));
807 }
808 
809 // API warpper
811  const Generator& rBPlant,
812  const EventSet& rCAlph,
813  const Generator& rGLSpec,
814  const RabinAutomaton& rRUSpec,
815  Generator& rRes)
816 {
817  // consitency check
818  ControlProblemConsistencyCheck(rBPlant, rCAlph, rRUSpec);
819  ControlProblemConsistencyCheck(rBPlant, rCAlph, rGLSpec);
820 
821  // have alphabet
822  const EventSet& sigma=rBPlant.Alphabet();
823 
824  // execute: set up ctrlpfx
825  bool snames= false;
826  RabinAutomaton cand;
827  cand.Assign(rRUSpec);
828  cand.StateNamesEnabled(snames);
829  cand.ClearMarkedStates();
830  Automaton(cand);
831  RabinBuechiProduct(cand,rBPlant,cand);
832 
833  // execute: compute controllability prefix incl greedy controller
834  TaIndexSet<EventSet> controller;
835  RabinCtrlPfx(cand,rCAlph,controller);
836 #ifdef FAUDES_DEBUG_RABINCTRL
837  controller.Write("tmp_rbc_controller.xml");
838 #endif
839 
840  // execute: trim to obtain pre SupCon
841  Generator gcand=cand;
842  gcand.ClearMarkedStates();
843  gcand.InsMarkedStates(controller);
844  SupClosed(gcand,gcand);
845  gcand.ClearMarkedStates();
846 #ifdef FAUDES_DEBUG_RABINCTRL
847  gcand.Write("tmp_rbc_supcon.gen");
848 #endif
849 
850  // todo: test lim LSpec cap L subseteq SupCon
851  // (currently we do this implicitly when applyiny controlpatterns
852  // so we should be fine ?)
853 
854  // excute: compose with LSpec given as generated language
855  Generator lspec=rGLSpec;
856  lspec.ClearMarkedStates();
857  Idx ds=Automaton(lspec);
859  aProduct(lspec,gcand,cmap,rRes);
860 #ifdef FAUDES_DEBUG_RABINCTRL
861  rRes.Write("tmp_rbc_product.gen");
862 #endif
863 
864  // execute: apply control patterns on exit of lspec;
866  Idx cx=0;
867  Idx csx=0;
868  Idx ccx=0;
869  bool doctrl=false;
870  const EventSet* pctrlpat=nullptr;
871  while(tit!=rRes.TransRelEnd()) {
872  // new state, update control pattern
873  if(cx!=tit->X1) {
874  cx=tit->X1;
875  pctrlpat=nullptr;
876  csx = cmap.Arg1State(tit->X1);
877  ccx = cmap.Arg2State(tit->X1);
878  if(controller.Exists(ccx))
879  pctrlpat=&controller.Attribute(ccx);
880  // record: if we are outside lspec, the greedy controller takes action
881  doctrl = (csx==ds);
882  // figure issue: we shall apply control but have no control-pattern
883  if(doctrl && (pctrlpat==nullptr)) {
884  FD_ERR("RabinCtrl: with rGLSpec: controller incomplete");
885  }
886  // figure issue: if we are in lspec, we shall be in ctrlpfx
887  if( (csx!=ds) && (!controller.Exists(ccx)) ) {
888  EmptyLanguage(sigma,rRes);
889  }
890  }
891  // wont apply control: fine, let run
892  if(!doctrl) {
893  ++tit;
894  continue;
895  }
896  // apply that control
897  if(!pctrlpat->Exists(tit->Ev)) {
898  rRes.ClrTransition(tit++);
899  } else {
900  ++tit;
901  }
902  }
903 
904  // cosmetic: install plant Buechi marking
905  StateSet::Iterator sit=rRes.StatesBegin();
906  for(; sit!=rRes.StatesEnd(); ++sit) {
907  Idx ccx = cmap.Arg2State(*sit);
908  if(cand.ExistsMarkedState(ccx))
909  rRes.InsMarkedState(*sit);
910  }
911 
912  // execute: polish
913  rRes.Accessible();
914  rRes.Name(CollapsString("RabinCtrl(("+rBPlant.Name()+"),("+rRUSpec.Name()+"))"));
915 }
916 
917 
918 // API warpper
920  const System& rBPlant,
921  const RabinAutomaton& rRSpec,
922  Generator& rRes)
923 {
924  // prepare result
925  Generator* pRes = &rRes;
926  if(dynamic_cast<System*>(pRes)== &rBPlant || dynamic_cast<RabinAutomaton*>(pRes)== &rRSpec) {
927  pRes= rRes.New();
928  }
929  // execute
930  RabinCtrl(rBPlant, rBPlant.ControllableEvents(),rRSpec,*pRes);
931  // copy all attributes of input alphabet
932  pRes->EventAttributes(rBPlant.Alphabet());
933  // copy result
934  if(pRes != &rRes) {
935  pRes->Move(rRes);
936  delete pRes;
937  }
938 }
939 
940 // API warpper
942  const System& rBPlant,
943  const Generator& rBLSpec,
944  const RabinAutomaton& rRUSpec,
945  Generator& rRes)
946 {
947  // prepare result
948  Generator* pRes = &rRes;
949  bool copy=false;
950  if(dynamic_cast<System*>(pRes)== &rBPlant) copy=true;
951  if(dynamic_cast<RabinAutomaton*>(pRes)== &rRUSpec) copy=true;
952  if(dynamic_cast<Generator*>(pRes)== &rBLSpec) copy=true;
953  if(copy) pRes= rRes.New();
954  // execute
955  RabinCtrl(rBPlant, rBPlant.ControllableEvents(),rBLSpec,rRUSpec,*pRes);
956  // copy all attributes of input alphabet
957  pRes->EventAttributes(rBPlant.Alphabet());
958  // copy result
959  if(pRes != &rRes) {
960  pRes->Move(rRes);
961  delete pRes;
962  }
963 }
964 
965 } // namespace faudes
966 
#define FD_DF(message)
#define FD_ERR(message)
const std::string & Name(void) const
Definition: cfl_types.cpp:422
bool Exists(const Idx &rIndex) const
bool Insert(const Idx &rIndex)
Idx Arg1State(Idx s12) const
Idx Arg2State(Idx s12) const
RabinAcceptance::CIterator mRPit
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynCtrlCore(const RabinAutomaton &raut, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
RabinInvDynCtrlInner(const RabinAutomaton &raut, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
RabinInvDynCtrlCore mCtrlCore
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynCtrlInner mNuCtrlCore
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynCtrl(const RabinAutomaton &raut, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
TaIndexSet< EventSet > mController
void InsCtrl(const RabinInvDynOperator &rOther)
virtual const StateSet & Domain(void) const
RabinInvDynOperator(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
const TaIndexSet< EventSet > & Controller(void) const
const StateSet & rMarkedStates
const TransSetX2EvX1 & rRevTransRel
TaIndexSet< EventSet > & Controller(void)
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinAcceptance::CIterator mRPit
RabinInvDynThetaTilde mThetaTilde
RabinInvDynPReachCore(const RabinAutomaton &raut, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynPReach(const RabinAutomaton &raut, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
RabinInvDynPReachCore mPReachCore
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynThetaTildeCore(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
RabinInvDynThetaTildeInner(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynThetaTildeCore mThetaCore
RabinInvDynThetaTildeInner mMuThetaCore
RabinInvDynThetaTilde(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
virtual void DoEvaluate(StateSetVector &rArgs, StateSet &rRes)
RabinInvDynTheta(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
std::vector< std::string > mArgNames
Definition: syn_ctrlpfx.h:122
StateSetVector::Position mArgCount
Definition: syn_ctrlpfx.h:119
void Evaluate(StateSetVector &rArgs, StateSet &rRes) const
Definition: syn_ctrlpfx.cpp:43
virtual const T & At(const Position &pos) const
StateSet PredecessorStates(Idx x2) const
Iterator Begin(void) const
Iterator End(void) const
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
const TaStateSet< StateAttr > & States(void) const
virtual void Move(TaGenerator &rGen)
const TaEventSet< EventAttr > & Alphabet(void) const
const ATransSet & TransRel(void) const
const Attr & Attribute(const Idx &rElem) const
Definition: cfl_indexset.h:559
virtual TaIndexSet & Assign(const TBaseSet< Idx > &rSrc)
Definition: cfl_indexset.h:653
EventSet ControllableEvents(void) const
virtual TrGenerator & Assign(const Type &rSource)
Definition: omg_rabinaut.h:283
virtual void RestrictStates(const StateSet &rStates)
Definition: omg_rabinaut.h:355
void RabinAcceptance(const faudes::RabinAcceptance &rRabAcc)
Definition: omg_rabinaut.h:326
TrGenerator * New(void) const
Definition: omg_rabinaut.h:300
void Write(const Type *pContext=0) const
Definition: cfl_types.cpp:145
virtual bool Equal(const Type &rOther) const
Definition: cfl_types.cpp:89
void AssignByReference(vBaseVector &rSourceVector)
virtual void PushBack(const Type &rElem)
Idx Size(void) const
StateSet::Iterator StatesBegin(void) const
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
virtual void Move(vGenerator &rGen)
virtual vGenerator & Assign(const Type &rSrc)
TransSet::Iterator TransRelBegin(void) const
void ClrTransition(Idx x1, Idx ev, Idx x2)
virtual vGenerator * New(void) const
void ClearMarkedStates(void)
void InjectMarkedStates(const StateSet &rNewMarkedStates)
void InsMarkedStates(const StateSet &rStates)
StateSet::Iterator StatesEnd(void) const
TransSet::Iterator TransRelEnd(void) const
virtual void EventAttributes(const EventSet &rEventSet)
bool StateNamesEnabled(void) const
virtual void Clear(void)
bool ExistsMarkedState(Idx index) const
const StateSet & States(void) const
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 InsertSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2194
Iterator Begin(void) const
Definition: cfl_baseset.h:2093
virtual bool Erase(const T &rElem)
Definition: cfl_baseset.h:2226
Idx Automaton(Generator &rGen, const EventSet &rAlphabet)
void aProduct(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void EmptyLanguage(const EventSet &rAlphabet, Generator &rResGen)
void SupRabinCon(const Generator &rBPlant, const EventSet &rCAlph, const RabinAutomaton &rRSpec, RabinAutomaton &rRes)
void RabinBuechiProduct(const RabinAutomaton &rRAut, const Generator &rBAut, RabinAutomaton &rRes)
void RabinCtrlPfx(const RabinAutomaton &rRAut, const EventSet &rSigmaCtrl, StateSet &rCtrlPfx)
void RabinCtrl(const Generator &rBPlant, const EventSet &rCAlph, const RabinAutomaton &rRSpec, Generator &rRes)
uint32_t Idx
void ControlProblemConsistencyCheck(const GeneratorVector &rPlantGenVec, const EventSet &rConAlph, const GeneratorVector &rSpecGenVec)
bool SupClosed(const Generator &rK, Generator &rResult)
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91

libFAUDES 2.33l --- 2025.09.16 --- c++ api documentaion by doxygen