omg_rabinctrl.cpp
Go to the documentation of this file.
1/** @file omg_rabinctrl.cpp Controller synthesis for Rabin automata */
2
3
4/*
5FAU Discrete Event Systems Library (libFAUDES)
6
7Copyright (C) 2025 Thomas Moor
8
9This library is free software; you can redistribute it and/or
10modify it under the terms of the GNU Lesser General Public
11License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version.
13
14This library is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public
20License along with this library; if not, write to the Free Software
21Foundation, 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
37namespace faudes {
38
39/*
40*****************************************************************
41*****************************************************************
42*****************************************************************
43
44Implementation of the fixpoint iteration proposed by Thistle/Wonham
45in "Control of w-Automata, Church's Problem, and the Emptiness Problem
46for Tree w-Automata", 1992.
47
48The iteration is ran on a transitions structure with two independent
49acceptance conditions, one Rabin and one Buechi. The result is the so
50so called controllable set, i.e., the set of states for which there
51exit individual control patterns such that in the controlled system,
52the Buechi acceptance condition (think of plant liveness properties)
53implies the Rabin acceptance condition (think of specification
54liveness requirements).
55
56At the current stage we only address specifications with a single
57Rabin pair, as this is our current use case.
58
59*****************************************************************
60*****************************************************************
61*****************************************************************
62*/
63
64/*
65Base class for my operators to hold context
66*/
68protected:
69 /** record context references */
76 /** record control patterns */
77 bool mRecCtrl=false;
79public:
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/*
120Inverse dynamics operator theta
121
122Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
123Problem for Tree w-Automata", 1992, Def 8.2:
124
125theta(X1,X2) = "the set of states, from which the automaton can be controlled to
126enter X1 union X2 in a single transition without being prevented from entering X1."
127
128Rephrase: X1 is the target T, X1 union X2 is the domain D; control such that immediate
129successors stay within within D and there is the chance to enter the T.
130
131We use "Z1/Z2" argument names to avoid confusion with libFAUDES naming conventions.
132*/
134public:
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 };
146protected:
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/*
186Inverse dynamics operator theta-tilde
187
188Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
189Problem 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
193We first implement the core formula without the nu/mu iteration and then apply nu/mu.
194We use "Y1/Y2/Y3/Y4" --> "Z1/Z2" argument names
195*/
197public:
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 };
209protected:
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);
225 };
226};
227
228
229/*
230Inverse dynamics operator theta tilde, inner mu iteration
231*/
233protected:
234 /** additional context */
237public:
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 };
251protected:
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/*
266Inverse dynamics operator theta tilde, outer nu iteration
267*/
269protected:
270 /** additional context */
273public:
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 };
287protected:
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/*
313P-reach operator
314
315Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
316Problem for Tree w-Automata", 1992, Def 8.4
317
318p-reach(X1,X2)= mu X3 . theta-tilde(X1,X) union theta-tilde((X1 u X2 u X3, I_p))
319
320We first implement the core formular without the nu/mu iteration, and then do the
321mu iteration
322
323We use "U1/U2/U3"
324*/
326 /** additional context */
328 RabinAcceptance::CIterator mRPit;
329public:
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 };
343protected:
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 */
375protected:
376 /** have additional context */
379public:
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 };
393protected:
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/*
408Controllable subset
409
410Cite Thistle/Wonham "Control of w-Automata, Church's Problem, and the Emptiness
411Problem for Tree w-Automata", 1992, Def 8.5
412
413CA = mu X1 nu X2 . p-reach(X1, X2 * Rp)
414
415We 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;
421public:
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 };
434protected:
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 */
453protected:
454 /** have additional context */
457public:
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 };
471protected:
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 */
498protected:
499 /** have additional context */
502public:
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 };
515protected:
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
535API wrappers to compute the controllability prefix. The latter is
536defined by Thistle/Wonham in "Supervision of Infinite Behavior of
537Discrete-Event Systems, 1994. It is the star-language which consists
538of all words such that thereafter a controller exits to enforce
539the specification. The controllability prefix relates to the
540controllable set as follows:
541
542Given a plant L and a specification E subseteq L, assume we have
543a transition systems such that L is accepted by a Buechi acceptance
544condition and E is appected by a Rabin aceptance condition. We refer
545to this as the candidate. The controllable set of the candidate then
546marks 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
631API wrappers for the supremal omega-controllable sublanguage.
632
633The supremal controllable sublanguage relates to the controllability
634prefix as follows.
635
636Given a plant L and a specification E, set up the candidate and
637compute the controllability prexis CFX. Then
638
639K := lim sup-closed-sublanguage(CFX) cap E
640
641is the supremal omega-controllable sublanguage of E.
642
643Thistle/Wonham give in " Supervision of Infinite Behavior of Discrete-Event",
6441994, the slightly different formula
645
646K := lim sup-closed-and-controllabe--sublanguage(CFX) cap E,
647
648but since only controllable envents can exit CFX to pre L both
649formulae 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 }
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
725API wrappers for controller syntheis.
726
727Technically, neither the supremal omega-controllable sublanguage
728K nor the controllility prefix CFX are controllers. But CFX lends
729itself as a basis to extract a controller. We provide two variants.
730
731a)
732The greedy controller will attempts to achieve yat another R-state
733as fast as possible. This is a rather restrictive policy but it does
734the job.
735
736b)
737Given a lower bound specification A, let the plant run freely
738until it exits pre A. Then apply the greedy controller. This
739requires the relative closure of A w.r.t the plant to be within
740K
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
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
bool Exists(const Idx &rIndex) const
bool Insert(const Idx &rIndex)
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)
TaIndexSet< EventSet > & Controller(void)
RabinInvDynOperator(const vGenerator &gen, const TransSetX2EvX1 &revtrans, const EventSet &sigctrl)
const TransSetX2EvX1 & rRevTransRel
virtual const StateSet & Domain(void) const
const TaIndexSet< EventSet > & Controller(void) const
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)
StateSet & RSet(void)
StateSet & ISet(void)
std::vector< std::string > mArgNames
StateSetVector::Position mArgCount
void Evaluate(StateSetVector &rArgs, StateSet &rRes) const
virtual const T & At(const Position &pos) const
StateSet PredecessorStates(Idx x2) const
Iterator Begin(void) const
Iterator End(void) const
const TaStateSet< StateAttr > & States(void) const
virtual void Move(TaGenerator &rGen)
const TaEventSet< EventAttr > & Alphabet(void) const
const ATransSet & TransRel(void) const
virtual TaIndexSet & Assign(const TBaseSet< Idx > &rSrc)
const Attr & Attribute(const Idx &rElem) const
EventSet ControllableEvents(void) const
virtual TrGenerator & Assign(const Type &rSource)
virtual void RestrictStates(const StateSet &rStates)
void RabinAcceptance(const faudes::RabinAcceptance &rRabAcc)
TrGenerator * New(void) const
void Write(const Type *pContext=0) const
virtual bool Equal(const Type &rOther) const
Definition cfl_types.cpp:89
void AssignByReference(vBaseVector &rSourceVector)
virtual void PushBack(const Type &rElem)
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 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
virtual void Clear(void)
Iterator End(void) const
virtual void InsertSet(const TBaseSet &rOtherSet)
Iterator Begin(void) const
virtual bool Erase(const T &rElem)
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen