omg_rabinfnct.cpp
Go to the documentation of this file.
1 /** @file omg_rabinfnct.cpp
2 
3 Operations regarding omega languages accepted by Rabin automata
4 
5 */
6 
7 /* FAU Discrete Event Systems Library (libFAUDES)
8 
9 Copyright (C) 2025 Thomas Moor
10 
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15 
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
20 
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
24 
25 
26 
27 #include "omg_rabinfnct.h"
28 
29 
30 namespace faudes {
31 
32 // RabinLiveStates
33 // compute states from a rabin pair that are not livelocks/deadlocks
35  const TransSet& rTransRel,
36  const TransSetX2EvX1& rRevTransRel,
37  const RabinPair& rRPair,
38  StateSet& rInv)
39 {
40  // convenience accessors
41  const StateSet& iset=rRPair.ISet();
42  const StateSet& rset=rRPair.RSet();
43  // initialise optimistic candidate of life states
44  rInv=iset;
45  // iterate for overall fixpoint
46  bool fix=false;
47  while(!fix) {
48  // record size to detect change
49  std::size_t invsz=rInv.Size();
50  // nu-iteration to restrict rInv to an existential forward invariant
51  bool nufix=false;
52  StateSet nudel;
53  while(!nufix) {
54  nudel.Clear();
55  StateSet::Iterator sit=rInv.Begin();
56  StateSet::Iterator sit_end=rInv.End();
57  while(sit!=sit_end) {
58  if((rTransRel.SuccessorStates(*sit) * rInv).Empty())
59  nudel.Insert(*sit);
60  ++sit;
61  }
62  rInv.EraseSet(nudel);
63  nufix=nudel.Empty();
64  }
65  // mu-iteration to obtain existential backward reach from rset
66  StateSet breach=rInv*rset;
67  StateSet todo=breach;
68  bool mufix=false;
69  StateSet muins;
70  while(!mufix) {
71  muins.Clear();
72  StateSet::Iterator sit=todo.Begin();
73  StateSet::Iterator sit_end=todo.End();
74  while(sit!=sit_end) {
75  muins.InsertSet(rRevTransRel.PredecessorStates(*sit));
76  ++sit;
77  }
78  muins.RestrictSet(rInv);
79  muins.EraseSet(breach);
80  breach.InsertSet(muins);
81  todo=muins;
82  mufix=muins.Empty();
83  }
84  // restrict rInv to breach
85  rInv=rInv*breach;
86  // sense change
87  if(invsz == rInv.Size()) fix=true;
88  }
89  // one more mu-iteration to obtain existential backward reach from inv
90  bool mufix=false;
91  StateSet todo=rInv;
92  StateSet muins;
93  while(!mufix) {
94  muins.Clear();
95  StateSet::Iterator sit=todo.Begin();
96  StateSet::Iterator sit_end=todo.End();
97  while(sit!=sit_end) {
98  muins.InsertSet(rRevTransRel.PredecessorStates(*sit));
99  ++sit;
100  }
101  muins.EraseSet(rInv);
102  rInv.InsertSet(muins);
103  todo=muins;
104  mufix=muins.Empty();
105  }
106  // done
107 }
108 
109 
110 // RabinLiveStates API wrapper
112  const vGenerator& rRAut,
113  const RabinPair& rRPair,
114  StateSet& rInv)
115 {
116  // convenience accessor
117  const TransSet& transrel=rRAut.TransRel();
118  TransSetX2EvX1 revtransrel(transrel);
119  // run algorithm
120  RabinLiveStates(transrel,revtransrel,rRPair,rInv);
121 }
122 
123 
124 // RabinLiveStates API wrapper
125 void RabinLiveStates(const RabinAutomaton& rRAut, StateSet& rInv) {
126  // convenience accessor
127  const RabinAcceptance& raccept=rRAut.RabinAcceptance();
128  const TransSet& transrel=rRAut.TransRel();
129  TransSetX2EvX1 revtransrel(transrel);
130  // pessimistic candidate for the trim set
131  rInv.Clear();
132  // iterate over Rabin pairs
133  StateSet inv;
134  RabinAcceptance::CIterator rit=raccept.Begin();
135  for(;rit!=raccept.End();++rit) {
136  RabinLiveStates(transrel,revtransrel,*rit,inv);
137  rInv.InsertSet(inv);
138  }
139 }
140 
141 
142 // RabinTrimSet
143 // (returns the sets that conbtribute to the Rabin accepted omega-language)
144 void RabinTrimSet(const RabinAutomaton& rRAut, StateSet& rTrim) {
145  // get live states
146  RabinLiveStates(rRAut,rTrim);
147  // only reachable states contribute
148  rTrim.RestrictSet(rRAut.AccessibleSet());
149 }
150 
151 // RabinTrim
152 // (return True if result contains at least one initial state and at least one non-trivial Rabin pair)
153 bool RabinTrim(RabinAutomaton& rRAut) {
154  // make the automaton accessible first
155  rRAut.Accessible();
156  // convenience accessor
157  RabinAcceptance& raccept=rRAut.RabinAcceptance();
158  const TransSet& transrel=rRAut.TransRel();
159  const TransSetX2EvX1 revtransrel(transrel);
160  // trim each Rabin pair to its live states
161  StateSet alive;
162  StateSet plive;
163  RabinAcceptance::Iterator rit=raccept.Begin();
164  for(;rit!=raccept.End();++rit) {
165  RabinLiveStates(transrel,revtransrel,*rit,plive);
166  rit->RestrictStates(plive);
167  alive.InsertSet(plive);
168  }
169  // remove obviously redundant (could do better here)
170  raccept.EraseDoublets();
171  // trim automaton to live states
172  rRAut.RestrictStates(alive);
173  // figure result
174  bool res=true;
175  if(!rRAut.InitStates().Empty()) res =false;
176  return res;
177 }
178 
179 // rti wrapper
180 bool RabinTrim(const RabinAutomaton& rRAut, RabinAutomaton& rRes) {
181  rRes=rRAut;
182  return RabinTrim(rRes);
183 }
184 
185 
186 // Rabin-Buechi product (lifting individual acceptence conditions, languages not affaected
187 // if arguments are full))
188 void RabinBuechiAutomaton(const RabinAutomaton& rRAut, const Generator& rBAut, RabinAutomaton& rRes) {
189  // prepare result
190  RabinAutomaton* pRes = &rRes;
191  if(&rRes== &rRAut || &rRes== &rBAut) {
192  pRes= rRes.New();
193  }
194  // utils
195  StateSet::Iterator sit;
196  StateSet::Iterator sit_end;
197  std::map< std::pair<Idx,Idx>, Idx>::iterator cit;
198  std::map< std::pair<Idx,Idx>, Idx> cmap;
199  // transition product
200  Product(rRAut,rBAut,cmap,*pRes);
201  // set conversion rRAut-state to set of new states
202  std::map< Idx , StateSet > rmap;
203  cit=cmap.begin();;
204  for(;cit!=cmap.end();++cit)
205  rmap[cit->first.first].Insert(cit->second);
206  // copy and fix Rabin acceptance
207  pRes->RabinAcceptance().Clear();
208  RabinAcceptance::CIterator rit=rRAut.RabinAcceptance().Begin();;
209  RabinAcceptance::CIterator rit_end=rRAut.RabinAcceptance().End();;
210  for(;rit!=rit_end;++rit) {
211  RabinPair rpair;
212  sit=rit->RSet().Begin();
213  sit_end=rit->RSet().End();
214  for(;sit!=sit_end;++sit)
215  rpair.RSet().InsertSet(rmap[*sit]);
216  sit=rit->ISet().Begin();
217  sit_end=rit->ISet().End();
218  for(;sit!=sit_end;++sit)
219  rpair.ISet().InsertSet(rmap[*sit]);
220  pRes->RabinAcceptance().Insert(rpair);
221  }
222  // set conversion rBAut-state to set of new states
223  std::map< Idx , StateSet > bmap;
224  cit=cmap.begin();;
225  for(;cit!=cmap.end();++cit)
226  bmap[cit->first.second].Insert(cit->second);
227  // set buechi marking
228  sit=rBAut.MarkedStatesBegin();
229  sit_end=rBAut.MarkedStatesEnd();
230  for(;sit!=sit_end;++sit)
231  pRes->InsMarkedStates(bmap[*sit]);
232  // copy result
233  if(pRes != &rRes) {
234  pRes->Move(rRes);
235  delete pRes;
236  }
237 }
238 
239 
240 // helper class for omega compositions
241 class RPState {
242 public:
243  // minimal interface
244  RPState() {};
245  RPState(const Idx& rq1, const Idx& rq2, const bool& rf) :
246  q1(rq1), q2(rq2), m1required(rf), mresolved(false) {};
247  std::string Str(void) { return ToStringInteger(q1)+"|"+
249  // order
250  bool operator < (const RPState& other) const {
251  if (q1 < other.q1) return(true);
252  if (q1 > other.q1) return(false);
253  if (q2 < other.q2) return(true);
254  if (q2 > other.q2) return(false);
255  if (!m1required && other.m1required) return(true);
256  if (m1required && !other.m1required) return(false);
257  if (!mresolved && other.mresolved) return(true);
258  return(false);
259  }
260  // member variables
264  bool mresolved;
265 };
266 
267 
268 // product of rabin and buechi automata, langugae intersection (only one rabin pair)
269 void RabinBuechiProduct(const RabinAutomaton& rRAut, const Generator& rBAut, RabinAutomaton& rRes) {
270  // we can only handle one Rabin pair
271  if(rRAut.RabinAcceptance().Size()!=1){
272  std::stringstream errstr;
273  errstr << "the current implementation requires exactly one Rabin pair";
274  throw Exception("RabinBuechiProduct", errstr.str(), 80);
275  }
276 
277  // prepare result
278  RabinAutomaton* pRes = &rRes;
279  if(&rRes== &rRAut || &rRes== &rBAut) {
280  pRes= rRes.New();
281  }
282  pRes->Clear();
283  pRes->Name(CollapsString(rRAut.Name()+".x."+rBAut.Name()));
284 
285  // create res alphabet
286  pRes->InsEvents(rRAut.Alphabet());
287  pRes->InsEvents(rBAut.Alphabet());
288 
289  // pick the one Rabin pair we care and prepare result
290  RabinPair rpair= *(rRAut.RabinAcceptance().Begin());
291  rpair.RSet().RestrictSet(rpair.ISet());
292  pRes->RabinAcceptance().Size(1);
293  RabinPair& resrpair= *(pRes->RabinAcceptance().Begin());
294  resrpair.Clear();
295 
296  // reverse composition map
297  std::map< RPState, Idx> reverseCompositionMap;
298  // todo stack
299  std::stack< RPState > todo;
300  // current pair, new pair
301  RPState currentstates, newstates;
302  // state
303  Idx tmpstate;
304  StateSet::Iterator lit1, lit2;
305  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
306  std::map< RPState, Idx>::iterator rcit;
307  // push all combinations of initial states on todo stack
308  FD_DF("RabinBuechiProduct: push initial states to todo:");
309  for(lit1 = rRAut.InitStatesBegin(); lit1 != rRAut.InitStatesEnd(); ++lit1) {
310  for(lit2 = rBAut.InitStatesBegin(); lit2 != rBAut.InitStatesEnd(); ++lit2) {
311  currentstates = RPState(*lit1, *lit2, true);
312  todo.push(currentstates);
313  Idx tmpstate=pRes->InsInitState();
314  reverseCompositionMap[currentstates] = tmpstate;
315  FD_DF("RabinRabinBuechiProduct: " << currentstates.Str() << " -> " << tmpstate);
316  // figure, whether this state should be in the invariant
317  if(rpair.ISet().Exists(currentstates.q1))
318  resrpair.ISet().Insert(tmpstate);
319  // copy buechi marking
320  if(rBAut.ExistsMarkedState(currentstates.q2))
321  pRes->SetMarkedState(tmpstate);
322  }
323  }
324 
325  // start algorithm
326  FD_DF("RabinBuechiProduct: processing reachable states:");
327  while (! todo.empty()) {
328  // allow for user interrupt
329  LoopCallback();
330  // get next reachable state from todo stack
331  currentstates = todo.top();
332  todo.pop();
333  FD_DF("RabinBuechiProduct: processing (" << currentstates.Str() << " -> " << reverseCompositionMap[currentstates]);
334  // iterate over all rRAut transitions
335  tit1 = rRAut.TransRelBegin(currentstates.q1);
336  tit1_end = rRAut.TransRelEnd(currentstates.q1);
337  for(; tit1 != tit1_end; ++tit1) {
338  // find transition in rBAut
339  tit2 = rBAut.TransRelBegin(currentstates.q2, tit1->Ev);
340  tit2_end = rBAut.TransRelEnd(currentstates.q2, tit1->Ev);
341  for (; tit2 != tit2_end; ++tit2) {
342  newstates = RPState(tit1->X2, tit2->X2,currentstates.m1required);
343  // figure whether marking was resolved
344  if(currentstates.m1required) {
345  if(rpair.RSet().Exists(currentstates.q1))
346  newstates.m1required=false;
347  } else {
348  if(rpair.ISet().Exists(currentstates.q1))
349  if(rBAut.ExistsMarkedState(currentstates.q2))
350  newstates.m1required=true;
351  }
352  // add to result and todo list if composition state is new
353  rcit = reverseCompositionMap.find(newstates);
354  if(rcit == reverseCompositionMap.end()) {
355  todo.push(newstates);
356  tmpstate = pRes->InsState();
357  // figure, whether this state should be recurrent
358  if(!newstates.m1required)
359  if(rBAut.ExistsMarkedState(newstates.q2))
360  resrpair.RSet().Insert(tmpstate);
361  // figure, whether this state should be invariant
362  if(rpair.ISet().Exists(newstates.q1))
363  resrpair.ISet().Insert(tmpstate);
364  // copy buechi marking
365  if(rBAut.ExistsMarkedState(newstates.q2))
366  pRes->SetMarkedState(tmpstate);
367  // record new state
368  reverseCompositionMap[newstates] = tmpstate;
369  FD_DF("RabinBuechiProduct: todo push: (" << newstates.Str() << ") -> " << reverseCompositionMap[newstates]);
370  }
371  else {
372  tmpstate = rcit->second;
373  }
374  pRes->SetTransition(reverseCompositionMap[currentstates],
375  tit1->Ev, tmpstate);
376  FD_DF("RabinBuechiProduct: add transition to new generator: " <<
377  pRes->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
378  }
379  }
380  }
381 
382  FD_DF("RabinBuechiProduct: recurrent states: " << pRes->StatesToString(resrpair.RSet()));
383 
384 
385  // fix statenames ...
386  if(rRAut.StateNamesEnabled() && rBAut.StateNamesEnabled() && pRes->StateNamesEnabled())
387  for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
388  Idx x1=rcit->first.q1;
389  Idx x2=rcit->first.q2;
390  bool m1requ=rcit->first.m1required;
391  Idx x12=rcit->second;
392  if(!pRes->ExistsState(x12)) continue;
393  std::string name1= rRAut.StateName(x1);
394  if(name1=="") name1=ToStringInteger(x1);
395  std::string name2= rBAut.StateName(x2);
396  if(name2=="") name1=ToStringInteger(x2);
397  std::string name12 = name1 + "|" + name2;
398  if(m1requ) name12 += "|r1m";
399  else name12 +="|r2m";
400  name12=pRes->UniqueStateName(name12);
401  pRes->StateName(x12,name12);
402  }
403 
404  // .. or clear them (?)
405  if(!(rRAut.StateNamesEnabled() && rBAut.StateNamesEnabled() && pRes->StateNamesEnabled()))
406  pRes->StateNamesEnabled(false);
407 
408  // copy result
409  if(pRes != &rRes) {
410  pRes->Move(rRes);
411  delete pRes;
412  }
413 }
414 
415 
416 
417 } // namespace faudes
418 
#define FD_DF(message)
const std::string & Name(void) const
Definition: cfl_types.cpp:422
RPState(const Idx &rq1, const Idx &rq2, const bool &rf)
bool operator<(const RPState &other) const
std::string Str(void)
StateSet & RSet(void)
Definition: omg_rabinacc.h:68
virtual void Clear(void)
StateSet & ISet(void)
Definition: omg_rabinacc.h:84
Iterator End(void)
Iterator Begin(void)
StateSet PredecessorStates(Idx x2) const
StateSet SuccessorStates(Idx x1) const
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
virtual void Clear(void)
virtual void Move(TaGenerator &rGen)
const TaEventSet< EventAttr > & Alphabet(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const ATransSet & TransRel(void) const
virtual void RestrictStates(const StateSet &rStates)
Definition: omg_rabinaut.h:353
void RabinAcceptance(const faudes::RabinAcceptance &rRabAcc)
Definition: omg_rabinaut.h:324
TrGenerator * New(void) const
Definition: omg_rabinaut.h:298
virtual void EraseDoublets(void)
StateSet::Iterator InitStatesBegin(void) const
const TransSet & TransRel(void) const
const EventSet & Alphabet(void) const
std::string StatesToString(void) const
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
void InsEvents(const EventSet &events)
void InsMarkedStates(const StateSet &rStates)
StateSet AccessibleSet(void) const
bool ExistsState(Idx index) const
StateSet::Iterator MarkedStatesBegin(void) const
std::string TStr(const Transition &rTrans) const
std::string StateName(Idx index) const
TransSet::Iterator TransRelEnd(void) const
StateSet::Iterator MarkedStatesEnd(void) const
void SetMarkedState(Idx index)
bool StateNamesEnabled(void) const
StateSet::Iterator InitStatesEnd(void) const
bool ExistsMarkedState(Idx index) const
std::string UniqueStateName(const std::string &rName) const
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
virtual void EraseSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2107
Idx Size(void) const
Definition: cfl_baseset.h:1782
void Product(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void RabinTrimSet(const RabinAutomaton &rRAut, StateSet &rTrim)
void RabinBuechiAutomaton(const RabinAutomaton &rRAut, const Generator &rBAut, RabinAutomaton &rRes)
bool RabinTrim(RabinAutomaton &rRAut)
void RabinBuechiProduct(const RabinAutomaton &rRAut, const Generator &rBAut, RabinAutomaton &rRes)
void RabinLiveStates(const TransSet &rTransRel, const TransSetX2EvX1 &rRevTransRel, const RabinPair &rRPair, StateSet &rInv)
uint32_t Idx
void LoopCallback(bool pBreak(void))
Definition: cfl_utils.cpp:679
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91

libFAUDES 2.33h --- 2025.06.18 --- c++ api documentaion by doxygen