pev_abstraction.cpp
Go to the documentation of this file.
1 /** @file pev_abstraction.cpp Conflict preserving abstractions */
2 
3 
4 /* FAU Discrete Event Systems Library (libfaudes)
5 
6  Copyright (C) 2023 Yiheng Tang
7  Copyright (C) 2025 Thomas Moor
8  Exclusive copyright is granted to Klaus Schmidt
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Lesser General Public
12  License as published by the Free Software Foundation; either
13  version 2.1 of the License, or (at your option) any later version.
14 
15  This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public
21  License along with this library; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23 
24 
25 #include "corefaudes.h"
26 #include "pev_pgenerator.h"
27 #include "pev_sparallel.h"
28 #include "pev_abstraction.h"
29 
30 
31 namespace faudes {
32 
33 /*
34 ************************************
35 Implementation of class Candidate
36 ************************************
37 */
38 
39 // Merge equivalent classes, i.e. perform quotient abstraction
40 // (this implementation works fine with a small amount of small equiv classes)
42  Generator& rGen,
43  TransSetX2EvX1& rRevTrans,
44  const std::list< StateSet >& rClasses,
45  const EventSet& silent
46  )
47 {
48  // iterators
49  StateSet::Iterator sit;
50  StateSet::Iterator sit_end;
54  TransSet::Iterator tit_end;
55  std::map<Idx,Idx> result;
56  // record for delayed delete
57  StateSet delstates;
58  // iterate classes
59  std::list< StateSet >::const_iterator qit=rClasses.begin();
60  for(;qit!=rClasses.end();++qit) {
61  sit=qit->Begin();
62  sit_end=qit->End();
63  Idx q1=*(sit++); // this than denotes the name of quotient
64  result.insert({q1,q1});
65  for(;sit!=sit_end;++sit){
66  Idx q2=*sit;
67  result.insert({q2,q1});
68  // merge outgoing transitions form q2 to q1
69  tit = rGen.TransRelBegin(q2);
70  tit_end = rGen.TransRelEnd(q2);
71  for(;tit!=tit_end;++tit) {
72  // // if X2 of this transition is still in this class with a silent ev, skip -- we shall do selfloop removal extern
73  // if (silent.Exists(tit->Ev) && (*qit).Exists(tit->X2)) continue;
74  rGen.SetTransition(q1,tit->Ev,tit->X2);
75  rRevTrans.Insert(q1,tit->Ev,tit->X2);
76  }
77  // merge incomming transitions form q2 to q1
78  rit = rRevTrans.BeginByX2(q2);
79  rit_end = rRevTrans.EndByX2(q2);
80  for(;rit!=rit_end;++rit) {
81  // // if X1 of this transition is still in this class with a silent ev, skip -- we shall do selfloop removal extern
82  // if (silent.Exists(rit->Ev) && (*qit).Exists(rit->X1)) continue;
83  rGen.SetTransition(rit->X1,rit->Ev,q1);
84  rRevTrans.Insert(rit->X1,rit->Ev,q1);
85  }
86  // fix marking: if q2 was not marked, need to un-mark q1 (original by Michael Meyer)
87  // if(!(rGen.ExistsMarkedState(q2)))
88  // rGen.ClrMarkedState(q1);
89  // fix marking: if q2 was marked, so becomes q1 (quotient by the books)
90  if(rGen.ExistsMarkedState(q2))
91  rGen.InsMarkedState(q1);
92  // fix initial states: if q2 was initial, so becomes q1
93  if((rGen.ExistsInitState(q2)))
94  rGen.InsInitState(q1);
95  // log for delete
96  delstates.Insert(q2);
97  }
98  }
99  // do delete
100  rGen.DelStates(delstates);
101 
102  // update mergemap (only used for counter example)
103  std::map<Idx,Idx>::iterator mit = mMergeMap.begin();
104  for(;mit!=mMergeMap.end();mit++){
105  std::list< StateSet >::const_iterator classit = rClasses.begin();
106  for (;classit!=rClasses.end();classit++){
107  if ((*classit).Exists(mit->second)){
108  // this shall be consistent with codes above, in that the Idx of quotient class
109  // is always the FIRST member of the class. Here is something to notice: StateSet
110  // is based on TBaseSet, whose core is the std::set which is automatically sorted.
111  // This means, as long as the eqclass is not inserted with new elements (note the
112  // input rClasses is const), the first element of the class will not change, i.e.
113  // always the "smallest" element.
114  mit->second = *(*classit).Begin();
115  break;
116  }
117  }
118  }
119 }
120 
121  // Compute extended transition relation '=>', i.e. relate each two states that
122 // can be reached by one non-slilent event and an arbitrary amount of silent
123 // events befor/after the non-silent event
124 //
125 // Note: currently all silent events are treated equivalent, as if they
126 // had been substituted by a single silent event "tau"; we should perform
127 // this substitution beforehand.
128 // YT: the original implementation is replaced by the following new iteration
129 // where for each iteration we only consider those new augmented transitions.
130 
131 // but it seem that the codes is not obviously getting faster.
132 
133 void Candidate::ExtendedTransRel(const Generator& rGen, const EventSet& rSilentAlphabet, TransSet& rXTrans) {
134 
135  // HELPERS:
136  TransSet::Iterator tit1;
137  TransSet::Iterator tit1_end;
138  TransSet::Iterator tit2;
139  TransSet::Iterator tit2_end;
140  TransSet newtrans;
141 
142  // initialize result with original transitionrelation
143  rXTrans=rGen.TransRel();
144  newtrans = rGen.TransRel(); // initialize iteration
145  // loop for fixpoint
146  while(!newtrans.Empty()) {
147  // store new transitions for next iteration
148  TransSet nextnewtrans;
149  // loop over all transitions in newtrans
150  tit1=newtrans.Begin();
151  tit1_end=newtrans.End();
152  for(;tit1!=tit1_end; ++tit1) {
153  // if it is silent add transition to non silent successor directly
154  if(rSilentAlphabet.Exists(tit1->Ev)) {
155  tit2=rXTrans.Begin(tit1->X2);
156  tit2_end=rXTrans.End(tit1->X2);
157  for(;tit2!=tit2_end; ++tit2) {
158  // if(!rSilentAlphabet.Exists(tit2->Ev)) // tmoor 18-09-2019
159  if (!rXTrans.Exists(tit1->X1,tit2->Ev,tit2->X2))
160  nextnewtrans.Insert(tit1->X1,tit2->Ev,tit2->X2);
161  }
162  }
163  // if it is not silent add transition to silent successor directly
164  else {
165  tit2=rXTrans.Begin(tit1->X2);
166  tit2_end=rXTrans.End(tit1->X2);
167  for(;tit2!=tit2_end; ++tit2) {
168  if(rSilentAlphabet.Exists(tit2->Ev)){
169  if (!rXTrans.Exists(tit1->X1,tit1->Ev,tit2->X2))
170  nextnewtrans.Insert(tit1->X1,tit1->Ev,tit2->X2);
171  }
172  }
173  }
174  }
175  // insert new transitions
176  rXTrans.InsertSet(nextnewtrans);
177  // update trans for next iteration.
178  newtrans = nextnewtrans;
179  }
180 }
181 
183  FD_DF("ObservationEquivalentQuotient(): prepare for t#"<<g.TransRelSize());
184 
185  // have extendend/reverse-ordered transition relations
186  TransSetX2EvX1 rtrans;
187  g.TransRel().ReSort(rtrans);
188 
189  Generator xg(g); // a copy of input g, which will be augmented with some fancy transitions
190  TransSet xtrans;
191  ExtendedTransRel(xg,silent,xtrans);
192  FD_DF("ObservationEquivalentQuotient(): ext. trans t#"<<xtrans.Size());
193 
194  // figure observation equivalent states
195  std::list< StateSet > eqclasses;
196  xg.InjectTransRel(xtrans);
197  // install silent selfloops
198  if (!silent.Empty()){
199  StateSet::Iterator sit = xg.StatesBegin();
200  for(;sit!=xg.StatesEnd();sit++){
201  EventSet::Iterator eit = silent.Begin();
202  xg.SetTransition(*sit,*eit,*sit);
203  }
204  }
205  ComputeBisimulationCTA(xg,eqclasses);
206 
207 
208  // merge classes
209  FD_DF("ObservationEquivalentQuotient(): merging classes #"<< eqclasses.size());
210  MergeEquivalenceClasses(g,rtrans,eqclasses,silent);
211 
212  FD_DF("ObservationEquivalentQuotient(): done with t#"<<g.TransRelSize());
213 }
214 
215 // perform quotient construction for reverse obsevation equivalence with active tau,
216 // see C. Pilbrow and R. Malik 2015. Current algorithm is perhaps suboptimal as it
217 // install a total new generator copy with all transitions reversed. Then the normal
218 // bisim-algorithm is performed, where eqclasses are refined to such that all states
219 // in a class has active tau event.
221  Generator rev_g; // have a copy to reverse all trans
222  rev_g.InsEvents(g.Alphabet());
223  rev_g.InsStates(g.States());
224 
225  // install reversed transition
227  TransSet::Iterator tit_end = g.TransRelEnd();
228  for(;tit!=tit_end;tit++){
229  rev_g.SetTransition(tit->X2,tit->Ev,tit->X1);
230  }
231 
232  // implement explicit "reverse_omega" for original initial states
233  Idx rev_omega = rev_g.InsEvent("_REV_OMEGA_");
234  Idx rev_dummy_omega = rev_g.InsEvent("_REV_DUMMY_OMEGA_");
235  Idx rev_terminal = rev_g.InsState("_REV_TERMINAL_");
236  rev_g.SetTransition(rev_terminal,rev_dummy_omega,rev_terminal);
237  StateSet::Iterator sit = g.InitStatesBegin();
238  StateSet::Iterator sit_end = g.InitStatesEnd();
239  for(;sit!=sit_end;sit++){
240  rev_g.SetTransition(*sit,rev_omega,rev_terminal);
241  }
242 
243  // figure out eqclasses, see e.g. ObservationEquivalentQuotient
244  TransSet xtrans;
245  ExtendedTransRel(rev_g,silent,xtrans);
246  rev_g.InjectTransRel(xtrans);
247  if (!silent.Empty()){
248  StateSet::Iterator sit2 = rev_g.StatesBegin();
249  StateSet::Iterator sit2_end = rev_g.StatesEnd();
250  for(;sit2!=sit2_end;sit2++){
251  rev_g.SetTransition(*sit2,*silent.Begin(),*sit2);
252  }
253  }
254  std::list<StateSet> eqclasses;
255  ComputeBisimulationCTA(rev_g,eqclasses);
256 
257  // refine eqclasses in that all states in a class has outgoing tau
258  std::list<StateSet> eqclasses_fine; // store result in new list, as some classes may be directly abandoned
259  std::list<StateSet>::iterator classit = eqclasses.begin();
260  std::list<StateSet>::iterator classit_end = eqclasses.end();
261  for (;classit!=classit_end;classit++){
262  StateSet newclass; // record refined class
263  StateSet::Iterator sit2 = classit->Begin();
264  StateSet::Iterator sit2_end = classit->End();
265  for(;sit2!=sit2_end;sit2++){
266  if (!(g.ActiveEventSet(*sit2) * silent).Empty()) newclass.Insert(*sit2);
267  }
268  if (newclass.Size()>=2) eqclasses_fine.push_back(newclass); // only store non-trivial classes
269  }
270 
271 
272  // merge refined eqclasses
273  TransSetX2EvX1 rtrans;
274  g.TransRel().ReSort(rtrans);
275  MergeEquivalenceClasses(g,rtrans,eqclasses_fine,silent);
276 
277 }
278 
279 // Performs weak observation equivalent abstraction;
280 // This is a re-imp of ObservationEquivalentQuotient in that we delete silent transitions
281 // after transition augmentation. FURHTERMORE, WE SHALL NOTICE that the resulting quotient
282 // is not built on input generator, but on the saturated generator with all tau deleted.
284  FD_DF("ObservationEquivalentQuotient(): prepare for t#"<<g.TransRelSize());
285 
286  // have extendend/reverse-ordered transition relations
287 
288  TransSet xtrans;
289  ExtendedTransRel(g,silent,xtrans);
290  FD_DF("ObservationEquivalentQuotient(): ext. trans t#"<<xtrans.Size());
291 
292  // remove silent events from extended transition relation
293  // yt: in weak observation equivalence, see e.g. Rong Su et al. (2010),
294  // only non-empty transitions are relevant
295  xtrans.RestrictEvents(g.Alphabet()-silent);
296 
297  // figure observation equivalent states
298  std::list< StateSet > eqclasses;
299  g.InjectTransRel(xtrans);
300  ComputeBisimulationCTA(g,eqclasses);
301  // merge classes
302  TransSetX2EvX1 rtrans;
303  g.TransRel().ReSort(rtrans);
304  FD_DF("ObservationEquivalentQuotient(): merging classes #"<< eqclasses.size());
305  MergeEquivalenceClasses(g,rtrans,eqclasses,silent); // here silent as input is dummy
306 
307  FD_DF("ObservationEquivalentQuotient(): done with t#"<<g.TransRelSize());
308 }
309 
310 // compute the incoming trans set of a state in a saturated
311 // and tau-removed generator. Instead of directly return a
312 // set of TransSet, a set of pair <Idx (source state), Idx (ev)>
313 // is returned for a better performance, hopefully. Moreover,
314 // for the sake of reachability from some intial state, a special pair
315 // <0,0> indicates that this state can be silently reached from some
316 // initial state.
318  const Generator& rGen,
319  const EventSet& silent,
320  const Idx& state,
321  std::set<std::pair<Idx, Idx>>& result){
322  result.clear(); // initialize result
323  TransSetX2EvX1 rtrans;
324  rGen.TransRel().ReSort(rtrans);
325  std::stack<Idx> todo; // states to process
326  std::set<Idx> visited; // states processed
327  todo.push(state);
328  visited.insert(state);
329 
330  while (!todo.empty()){
331  Idx cstate = todo.top();
332  todo.pop();
333 
334  // a "flag" indicating that this state can be silently reached by
335  // some initial state, see remark at the beginning
336  if (rGen.InitStates().Exists(cstate))
337  result.insert({0,0});
338  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(cstate);
339  TransSetX2EvX1::Iterator rtit_end = rtrans.EndByX2(cstate);
340  for(;rtit!=rtit_end;rtit++){
341  if (!silent.Exists(rtit->Ev))
342  result.insert({rtit->X1,rtit->Ev});
343  else{
344  if (visited.find(rtit->X1) == visited.end()){
345  todo.push(rtit->X1);
346  visited.insert(rtit->X1);
347  }
348  }
349  }
350  }
351 }
352 
353 // compute the non-silent active events of a given generator.
354 // this algo is similar to IncomingTransSet, but we shall notice
355 // that IncomingTransSet record the source state as well but here not.
357  const Generator &rGen,
358  const EventSet &silent,
359  const Idx &state,
360  EventSet &result){
361  result.Clear(); // initialize result
362  std::stack<Idx> todo; // states to process
363  std::set<Idx> visited; // states processed (stack shall also work)
364  todo.push(state);
365  visited.insert(state);
366 
367  while (!todo.empty()){
368  Idx cstate = todo.top();
369  todo.pop();
370 
371  TransSet::Iterator rtit = rGen.TransRelBegin(cstate);
372  TransSet::Iterator rtit_end = rGen.TransRelEnd(cstate);
373  for(;rtit!=rtit_end;rtit++){
374  if (!silent.Exists(rtit->Ev))
375  result.Insert(rtit->Ev);
376  else{
377  if (visited.find(cstate) == visited.end()){
378  todo.push(rtit->X2);
379  visited.insert(rtit->X2);
380  }
381  }
382  }
383  }
384 }
385 
386 // Active events rule; see cited literature 3.2.1
387 // Note: this is a re-write of Michael Meyer's implementation to refer to the
388 // ext. transistion relation, as indicated by the literature.
389 // YT: Now it also partly supports Enabled Continuation Rule, see C. Pilbrow and R. Malik 2015
391  Generator& g,
392  const EventSet& silent){
393  // convenient typedef for incoming trans. This is for the incoming eq partition and,
394  // instead of directly set up std::set<TransSet>, we hope the set of pairs<Idx(source state), Idx(ev)>
395  // will perform better.
396  typedef std::set<std::pair<Idx,Idx>> TransSetX1Ev;
397 
398  // start the incoming equivalence partition
399  StateSet::Iterator sit = g.StatesBegin();
400  StateSet::Iterator sit_end = g.StatesEnd();
401 
402  // set up a map <incoming transset->class> to fast access incoming transset
403  // of existing classes. This map is only meant to check incoming equivalence.
404  std::map<TransSetX1Ev,StateSet> incomingeqclasses;
405  std::map<TransSetX1Ev,StateSet>::iterator mit;
406  for(;sit!=sit_end;sit++){
407  TransSetX1Ev rec_income;
408  IncomingTransSet(g,silent,*sit,rec_income);
409  mit = incomingeqclasses.find(rec_income);
410  if (mit != incomingeqclasses.end()){ // existing class found
411  mit->second.Insert(*sit);
412  }
413  else { // no class for this state found
414  StateSet newclass;
415  newclass.Insert(*sit);
416  incomingeqclasses.insert({rec_income,newclass});
417  }
418  }
419 
420  // Following the explanation in Chapter 4.2 of C. Pilbrow and R. Malik 2015,
421  // we first merge states via ActiveEventsRule. Then the incoming eq classes
422  // will be updated, then merge states via EnabledContinuationRule.
423  // And we avoid the the second time of ActiveEventsRule, which is acturally
424  // suggested in the aforementioned paper
425 
426  std::list<StateSet> eqclasses; // store result
427  TransSetX2EvX1 rtrans; // convenient declaration for MergeEqClasses
428 
429  // 1 - ActiveEventsRule
430  mit = incomingeqclasses.begin();
431  for (;mit!=incomingeqclasses.end();mit++){
432  StateSet fineclass; // refined class
433  StateSet::Iterator sit = mit->second.Begin();
434  fineclass.Insert(*sit);
435  EventSet activeevs;
436  ActiveNonTauEvs(g,silent,*sit,activeevs); // xg: exclude tau
437  StateSet::Iterator sit_compare = sit;
438  sit_compare++;
439  while(sit_compare!=mit->second.End()){
440  EventSet activeevs_compare;
441  ActiveNonTauEvs(g,silent,*sit,activeevs_compare);
442  if (activeevs_compare==activeevs){
443  fineclass.Insert(*sit_compare);
444  StateSet::Iterator todelete = sit_compare;
445  sit_compare++;
446  mit->second.Erase(todelete);
447  }
448  else sit_compare++;
449  }
450  if (fineclass.Size()>1) eqclasses.push_back(fineclass);
451  }
452  g.TransRel().ReSort(rtrans);
453  MergeEquivalenceClasses(g,rtrans,eqclasses,silent);
454 
455  // 2 - EnabledContinuationRule
456  eqclasses.clear();
457  rtrans.Clear();
458  mit = incomingeqclasses.begin();
459  for (;mit!=incomingeqclasses.end();mit++){
460  StateSet fineclass; // refined class
461  StateSet::Iterator sit = mit->second.Begin();
462  while(sit!=mit->second.End()){
463  if (!(g.ActiveEventSet(*sit) * silent).Empty()){ // g: has outgoing tau
464  fineclass.Insert(*sit);
465  // (this #if is actually unnecessary if we dont apply ActiveEventsRule again)
466  if (fineclass.Size()>1){ // fineclass is untrivial
467  StateSet::Iterator todelete = sit;
468  sit++;
469  mit->second.Erase(todelete);
470  }
471  else sit++;
472  }
473  else sit++;
474  }
475  if (fineclass.Size()>1) eqclasses.push_back(fineclass);
476  }
477  g.TransRel().ReSort(rtrans);
478  MergeEquivalenceClasses(g,rtrans,eqclasses,silent);
479 }
480 
481 
482 
483 // simple function removing tau self loops
486  TransSet::Iterator tit_end = g.TransRelEnd();
487  while(tit!=tit_end){
488  if (tit->X1 == tit->X2 && silent.Exists(tit->Ev)) g.ClrTransition(tit++);
489  else tit++;
490  }
491 }
492 
493 // as a special case of observation equivalence, states on a tau-loop are all equivalent
494 // and can be merged to a single state. This step is preferred to be done before
495 // (weak) observation equivalence, as they require transition saturation which is quite
496 // expensive.
498 
499  TransSetX2EvX1 rtrans;
500  g.TransRel().ReSort(rtrans);
501 
502  // have a generator copy where only silent transitions are preserved
503  Generator copyg(g);
504  TransSet::Iterator tit = copyg.TransRel().Begin();
505  while (tit!=copyg.TransRelEnd()){
506  if (!silent.Exists(tit->Ev)) // if not a silent trans, delete
507  copyg.ClrTransition(tit++);
508  else tit++;
509  }
510 
511  // compute eqclass and merge on original generator
512  std::list<StateSet> eqclasses;
513  StateSet dummy;
514  ComputeScc(copyg,eqclasses,dummy);
515 
516  // delete trivial eqclasses (yt: I dont want to hack into the computescc function)
517  std::list<StateSet>::iterator sccit = eqclasses.begin();
518  while (sccit!=eqclasses.end()){
519  if ((*sccit).Size()==1) eqclasses.erase(sccit++);
520  else sccit++;
521  }
522 
523  MergeEquivalenceClasses(g,rtrans,eqclasses,silent);
524 }
525 
526 // Certain conflicts. see cited literature 3.2.3
527 // -- remove outgoing transitions from not coaccessible states
529  StateSet notcoaccSet=g.States()-g.CoaccessibleSet();
530  StateSet::Iterator sit=notcoaccSet.Begin();
531  StateSet::Iterator sit_end=notcoaccSet.End();
532  for(;sit!=sit_end;++sit){
534  TransSetX1EvX2::Iterator tit_end=g.TransRelEnd(*sit);
535  for(;tit!=tit_end;) g.ClrTransition(tit++);
536  //FD_DF("RemoveCertainConflictA: remove outgoing from state "<<*sit);
537  }
538 }
539 
540 // Certain conflicts. see cited literature 3.2.3
541 // -- remove outgoing transitions from states that block by a silent event
543  FD_DF("BlockingSilentEvent(): prepare for t#"<<g.TransRelSize());
544  StateSet coacc=g.CoaccessibleSet();
545  StateSet sblock;
546  TransSet::Iterator tit;
547  TransSet::Iterator tit_end;
548  StateSet::Iterator sit;
549  StateSet::Iterator sit_end;
550  // loop all transitions to figure certain blocking states
551  tit=g.TransRelBegin();
552  tit_end=g.TransRelEnd();
553  for(;tit!=tit_end;++tit) {
554  if(silent.Exists(tit->Ev))
555  if(!coacc.Exists(tit->X2))
556  sblock.Insert(tit->X1);
557  }
558  // unmark blocking states and eliminate possible future
559  sit=sblock.Begin();
560  sit_end=sblock.End();
561  for(;sit!=sit_end;++sit) {
562  g.ClrMarkedState(*sit);
563  tit=g.TransRelBegin(*sit);
564  tit_end=g.TransRelEnd(*sit);
565  for(;tit!=tit_end;)
566  g.ClrTransition(tit++);
567  }
568  FD_DF("BlockingSilentEvent(): done with t#"<<g.TransRelSize());
569 }
570 
571 // Certain conflicts. see cited literature 3.2.3
572 // -- merge all states that block to one representative
574  StateSet notcoacc=g.States()-g.CoaccessibleSet();
575  // bail out on trovial case
576  if(notcoacc.Size()<2) return;
577  // have a new state
578  Idx qnc=g.InsState();
579  // fix init status
580  if((notcoacc * g.InitStates()).Size()>0)
581  g.SetInitState(qnc);
582  // fix transitions
584  TransSet::Iterator tit_end=g.TransRelEnd();
585  for(;tit!=tit_end;++tit){
586  if(notcoacc.Exists(tit->X2))
587  g.SetTransition(tit->X1,tit->Ev,qnc);
588  }
589  // delete original not coacc
590  g.DelStates(notcoacc);
591 }
592 
593 // Certain conflicts. see cited literature 3.2.3
594 // -- if a transition blocks, remove all transitions from the same state with the same label
596  FD_DF("BlockingEvent(): prepare for t#"<<g.TransRelSize());
597  StateSet coacc=g.CoaccessibleSet();
598  TransSet::Iterator tit;
599  TransSet::Iterator tit_end;
600  TransSet::Iterator dit;
601  TransSet::Iterator dit_end;
602  TransSet deltrans;
603  // loop all transitions to figure transitions to blocking states
604  tit=g.TransRelBegin();
605  tit_end=g.TransRelEnd();
606  for(;tit!=tit_end;++tit) {
607  // silent events are treated by a separat rule;
608  if(silent.Exists(tit->Ev)) continue;
609  // look for transitions that block
610  if(coacc.Exists(tit->X1)) continue;
611  if(coacc.Exists(tit->X2)) continue;
612  // consider all transitions with the same event to block
613  dit=g.TransRelBegin(tit->X1,tit->Ev);
614  dit_end=g.TransRelEnd(tit->X1,tit->Ev);
615  for(;dit!=dit_end;++dit) {
616  // keep selfloops (Michael Meyer)
617  if(dit->X1==dit->X2) continue;
618  // rcord to delete later
619  deltrans.Insert(*dit);
620  }
621  }
622  // delete transitions
623  dit=deltrans.Begin();
624  dit_end=deltrans.End();
625  for(;dit!=dit_end;++dit)
626  g.ClrTransition(*dit);
627  FD_DF("BlockingEvent(): done with t#"<<g.TransRelSize());
628 }
629 
630 // Only silent incomming rule; see cited literature 3.2.4
631 // Note: input generator must be silent-SCC-free
632 // Note: this is a complete re-re-write and needs testing for more than one candidates
634 
635  // figure states with only silent incomming transitions
636  // note: Michael Meyer proposed to only consider states with at least two incomming
637  // events -- this was dropped in the re-write
638  StateSet cand=g.States()-g.InitStates(); // note the initial state set is preserved
640  TransSet::Iterator tit_end = g.TransRelEnd();
641  for(;tit!=tit_end;++tit)
642  if(!silent.Exists(tit->Ev)) cand.Erase(tit->X2);
643 
644  // bail out on trivial
645  if(cand.Size()==0) {
646  return;
647  }
648 
649  StateSet::Iterator sit = cand.Begin();
650  StateSet::Iterator sit_end = cand.End();
651  while (sit!=sit_end){
652  TransSet::Iterator tit2 = g.TransRelBegin(*sit);
653  TransSet::Iterator tit2_end = g.TransRelEnd(*sit);
654  for (;tit2!=tit2_end;tit2++){
655  if (silent.Exists(tit2->Ev)){
656  break;
657  }
658  }
659 
660  if (tit2!=tit_end) { // there is at least one tau outgoing
661  // redirect transitions
662  TransSetX2EvX1 rtrans;
663  g.TransRel().ReSort(rtrans);
664  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit);
665  TransSetX2EvX1::Iterator rtit_end = rtrans.EndByX2(*sit);
666  for(;rtit!=rtit_end;rtit++){
667  TransSet::Iterator tit3 = g.TransRelBegin(*sit);
668  TransSet::Iterator tit3_end = g.TransRelEnd(*sit);
669  for (;tit3!=tit3_end;tit3++){
670  g.SetTransition(rtit->X1,tit3->Ev,tit3->X2);
671  }
672  }
673  StateSet::Iterator todelete = sit;
674  sit++;
675  g.DelState(*todelete);
676  }
677  else sit++;
678  }
679 
680  // yt: interestingly, according to the discussion with R. Malik,
681  // we do not need to assign the merge map information in this step -- this is counter-intuitive
682  // meaning that the deleted state has its merge map unchanged, but it will never be used because
683  // this state is "skipped" and thus can never be the final state of a counter example. Thus, it
684  // will not be utilized by line 12 of Algo 1, R. Malik and S. Ware 2018. Note we need the merge map
685  // only when executing line 12 of Algo 1.
686 
687 }
688 
689 
690 // Only silent outgoing rule; see cited literature 3.2.5
691 // Note: input generator must be silent-SCC-free
693  StateSet::Iterator sit = g.StatesBegin();
694  StateSet::Iterator sit_end = g.StatesEnd();
695  while(sit!=sit_end){
696  // figure out whether this state is only silent outgoing
697  if (g.MarkedStates().Exists(*sit)) {sit++;continue;}
698  TransSet::Iterator tit2 = g.TransRelBegin(*sit);
699  TransSet::Iterator tit2_end = g.TransRelEnd(*sit);
700  if (tit2==tit2_end) {sit++;continue;} // sit points to a deadend state (nonmarked state without outgoing trans)
701  for (;tit2!=tit2_end;tit2++){
702  if (!silent.Exists(tit2->Ev)) break;
703  }
704  if (tit2 != tit2_end) {sit++;continue;} // sit has non-silent outgoing trans
705 
706  // sit has passed the test. relink outgoing transitions of predecessor
707  TransSetX2EvX1 rtrans;
708  g.TransRel().ReSort(rtrans);
709  // (repair intial state quicker by first iterate outgoing trans)
710  tit2 = g.TransRelBegin(*sit);
711  tit2_end = g.TransRelEnd(*sit);
712  for (;tit2!=tit2_end;tit2++){
713  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit); // incoming trans to *sit
714  TransSetX2EvX1::Iterator rtit_end = rtrans.EndByX2(*sit);
715  for (;rtit!=rtit_end;rtit++){
716  g.SetTransition(rtit->X1,rtit->Ev,tit2->X2);
717  }
718  if (g.ExistsInitState(*sit))
719  g.SetInitState(tit2->X2);
720  }
721  StateSet::Iterator todelete = sit;
722  sit++;
723  g.DelState(*todelete);
724  }
725 }
726 
729  EventSet msilentevs=mGenRaw.Alphabet()*silent;
730  if(msilentevs.Empty()){
732  return;
733  }
734  Idx tau=*(msilentevs.Begin());
735  SetTau(tau);
736  SetSilentevs(msilentevs);
737  msilentevs.Erase(tau); // from now on, msilentevs exclude tau
738  silent.EraseSet(msilentevs);
739  if (msilentevs.Empty()){// in this case, only one 1 silent event is set to tau and no need to hide
741  return;
742  }
745  for(;tit!=tit_end;) {
746  if(!msilentevs.Exists(tit->Ev)) {++tit; continue;}
747  Transition t(tit->X1,tau,tit->X2);
748  mGenHidden.ClrTransition(tit++);
751  }
754 }
755 
757  // hide must be performed beforehand.
758  // we use tau itself as silent event set to
759  // access abstraction algorithms
760  HidePrivateEvs(silent);
761  EventSet tau;
762  if (mtau!=0)
763  tau.Insert(mtau);
764 
765  // current codes does not support counterexample computation for certain conflicts.
766  // Anyway, in R. Malik and S. Ware 2018, it shows no definitely postive result
767  // when considering certain conf in counter example computation due to the fact
768  // that we need to compute paralle product at each step of iteration. Furthermore,
769  // we would like to have counter example which goes into the blocking zone as
770  // far as possible, namely ends up at either a deadlocking state or a state in a livelock
771  // -- this also contradicts with certain conflicts conceptionally.
772 
773  // ***************** abstraction rules *******************
776  // OnlySilentIncoming(mGenMerged,tau);
777  // OnlySilentOutgoing(mGenMerged,tau);
780  // ReverseObservationEquivalentQuotient(mGenMerged,tau);
781 }
782 
783 
784 /*
785 ************************************
786 END: Candidate
787 ************************************
788 */
789 
790 
791 
792 
793 
794 void PrintEventTable(const pGenerator& rPGen){
795  EventSet::Iterator eit = rPGen.AlphabetBegin();
796  for(;eit!=rPGen.AlphabetEnd();eit++)
797  std::cout<<"EvName: "<<rPGen.EventName(*eit)<<"\t\t"<<"Index:"<<ToStringInteger(*eit)
798  <<"\t\t"<<"Priority: "<<ToStringInteger(rPGen.EventAttribute(*eit).Priority())<<std::endl;
799 }
800 
801 void PrintEqclasses(const std::list<StateSet>& rEqclasses){
802  std::list<StateSet>::const_iterator eqit = rEqclasses.begin();
803  for(;eqit!=rEqclasses.end();eqit++){
804  StateSet::Iterator sit = eqit->Begin();
805  std::cout<<"[";
806  for(;sit!=eqit->End();sit++){
807  std::cout<<ToStringInteger(*sit)+"\t";
808  }
809  std::cout<<"]"<<std::endl;
810  }
811 
812 }
813 
815  Idx omega = rPGen.InsEvent("_OMEGA_");
816  Idx omega_terminal = rPGen.InsEvent("_OMEGA_TERMINAL_");
817 
818  // Handle event prioriy
819  const Idx lowest = rPGen.GlobalAttribute().LowestPriority() + 1; // YT-2025-04
820  rPGen.EventAttributep(omega)->Priority(lowest);
821  rPGen.EventAttributep(omega_terminal)->Priority(lowest);
822  rPrios.InsPriority("_OMEGA_",lowest);
823  rPrios.InsPriority("_OMEGA_TERMINAL_",lowest);
824  Idx terminal = rPGen.InsState("_TERMINAL_");
825  rPGen.SetTransition(terminal,omega_terminal,terminal);
826  StateSet::Iterator sit = rPGen.MarkedStatesBegin();
827  for(;sit!=rPGen.MarkedStatesEnd();sit++){
828  rPGen.SetTransition(*sit,omega,terminal);
829  }
830  rPGen.SetMarkedState(terminal); // cosmetic
831 
832  // handle fairness constraints
833  EventSet fairc;
834  fairc.Insert(omega);
835  fairc.Insert(omega_terminal);
836  FairnessConstraints fair;
837  fair.Append(fairc);
838  rPGen.GlobalAttributep()->Fairness(fair);
839 }
840 
841 
842 // convenient wrapper to show priority of each event
843 void WritePrio (const pGenerator& rPGen){
844  EventSet::Iterator eit = rPGen.AlphabetBegin();
845  for(;eit!=rPGen.AlphabetEnd();eit++){
846  std::cout<< rPGen.EventName(*eit) << "\t\t";
847  std::cout<<ToStringInteger(rPGen.EventAttribute(*eit).Priority())<<std::endl;
848  }
849 }
850 
851 // shaping priosities for specified preempting events (retains unreachable states)
852 void ShapeUpsilon(vGenerator& rGen, const EventPriorities& rPrios, const EventSet& rUpsilon){
853  Idx lowest = rPrios.LowestPriority();
854  StateSet::Iterator sit = rGen.StatesBegin();
855  for(;sit!=rGen.StatesEnd();sit++){
856  // figure gighest enabled priority
857  Idx highest = lowest;
858  TransSet::Iterator tit = rGen.TransRelBegin(*sit);
859  TransSet::Iterator tit_end = rGen.TransRelEnd(*sit);
860  for(;tit!=tit_end; ++tit){
861  Idx prio=rPrios.Priority(tit->Ev);
862  if(prio > highest)
863  if(rUpsilon.Exists(tit->Ev))
864  highest = prio;
865  }
866  // bail out if all enabled events are of lowest priority
867  if(highest == lowest) continue;
868  // remove preempted transitions
869  tit = rGen.TransRelBegin(*sit);
870  tit_end = rGen.TransRelEnd(*sit);
871  while(tit!=tit_end) {
872  if(rPrios.Priority(tit->Ev)<highest){
873  if(rPrios.SymbolicName(tit->Ev)=="_OMEGA_")
874  rGen.ClrMarkedState(tit->X1); // unmark if remove omega transition, cosmetic
875  rGen.ClrTransition(tit++);
876  } else {
877  ++tit;
878  }
879  }
880  }
881 }
882 
883 // API using pGenerator
884 void ShapeUpsilon(pGenerator& rPGen, const EventSet& rUpsilon){
885  const EventPriorities prios=rPGen.Priorities();
886  ShapeUpsilon(rPGen,prios,rUpsilon);
887 }
888 
889 // API ordinary shaping by priority, incl. removal of unreachable states
890 void ShapePriorities(vGenerator& rGen, const EventPriorities& rPrios){
891  ShapeUpsilon(rGen,rPrios,rGen.Alphabet());
892  rGen.Accessible();
893 }
894 
895 // API ordinary shaping by priority, incl. removal of unreachable states
897  const EventPriorities prios=rPGen.Priorities();
898  ShapeUpsilon(rPGen,prios,rPGen.Alphabet());
899  rPGen.Accessible();
900 }
901 
902 
903 
904 
905 // shape by set of preempting events only (TM2025: need this old version to compile/link example)
906 void ShapePreemption(Generator& rGen, const EventSet &pevs){
907  StateSet::Iterator sit = rGen.StatesBegin();
908  StateSet::Iterator sit_end = rGen.StatesEnd();
909  for(;sit!=sit_end; sit++){
910  if ((rGen.ActiveEventSet(*sit) * pevs).Empty()) continue; // not a preemptive state
911  TransSet::Iterator tit = rGen.TransRelBegin(*sit);
912  TransSet::Iterator tit_end = rGen.TransRelEnd(*sit);
913 
914  while(tit!=tit_end){
915  if (pevs.Exists(tit->Ev)) tit++;
916  else rGen.ClrTransition(tit++);
917  }
918  }
919  rGen.Accessible();
920  rGen.Name("S(" + rGen.Name() + ")");
921 }
922 
923 
924 // require WF!
925 void RemoveRedSilentSelfloops (pGenerator& rPGen, const EventSet& rSilent){
926  TransSet::Iterator tit=rPGen.TransRelBegin();
927  while(tit!=rPGen.TransRelEnd()){
928  if (tit->X1!=tit->X2) {tit++; continue;}
929  if (!rSilent.Exists(tit->Ev)) {tit++; continue;}
930  TransSet::Iterator tit2 = rPGen.TransRelBegin(tit->X1);
931  for(;tit2!=rPGen.TransRelEnd(tit->X1);tit2++){
932  if (rSilent.Exists(tit2->Ev) && tit2->X2 != tit->X1)
933  break;
934  }
935  if (tit2!=rPGen.TransRelEnd(tit->X1)){
936  rPGen.ClrTransition(tit++);
937  }
938  else tit++;
939  }
940 }
941 
942 // OLD NOTE: EXCLUDE unprioritised events, since this function evaluates the potential
943 // of a transition being preempted by NonsilHigherThen events.
945  const EventSet& rSilent,
946  const Idx& rState,
947  const Idx& rK){
948  EventSet result;
949  if(rK==rPGen.HighestPriority()) return result;
950  result = rPGen.ActiveEventSet(rState);
951  EventSet::Iterator eit = result.Begin();
952  while(eit!=result.End()){
953  if(!rSilent.Exists(*eit))
954  if(rPGen.Priority(*eit) > rK) {
955  eit++;
956  continue;
957  }
958  result.Erase(eit++);
959  }
960  return result;
961 }
962 
963 // find the silent event at given priority.
964 Idx SilentEvAtPrio(const pGenerator& rPGen, const EventSet& rSilent, const Idx& rK){
965  EventSet::Iterator eit = rPGen.AlphabetBegin();
966  for(;eit!=rPGen.AlphabetEnd();eit++){
967  if (!rSilent.Exists(*eit)) continue;
968  if (rPGen.Priority(*eit)==rK) return *eit;
969  }
970  throw Exception("SilentEvAtPrio()", "no such event found", 599);
971  return 0;
972 }
973 
975  pGenerator& rPGen,
976  const EventSet& rSilent,
977  const std::map< StateSet, Idx >& rLivelocks,
978  const std::list< StateSet >& rClasses)
979 {
980  FD_DF("MergeEquivalenceClasses()");
981  TransSetX2EvX1 rtrans;
982  rPGen.TransRel().ReSort(rtrans);
983  // iterators
984  StateSet::Iterator sit;
985  StateSet::Iterator sit_end;
987  TransSetX2EvX1::Iterator rtit_end;
988  TransSet::Iterator tit;
989  TransSet::Iterator tit_end;
990  // record for delayed delete
991  StateSet delstates;
992  // iterate classes
993  std::list< StateSet >::const_iterator qit=rClasses.begin();
994  for(;qit!=rClasses.end();++qit) {
995  sit=qit->Begin();
996  sit_end=qit->End();
997  Idx q1=*(sit++); // this than denotes the name of quotient, i.e.[q1]
998  for(;sit!=sit_end;++sit){
999  Idx q2=*sit;
1000  // merge outgoing transitions form q2 to q1
1001  tit = rPGen.TransRelBegin(q2);
1002  tit_end = rPGen.TransRelEnd(q2);
1003  for(;tit!=tit_end;++tit) {
1004  // skip silent self-loop (handled later)
1005  if (qit->Exists(tit->X2)&&rSilent.Exists(tit->Ev))
1006  continue;
1007  rPGen.SetTransition(q1,tit->Ev,tit->X2);
1008  rtrans.Insert(q1,tit->Ev,tit->X2);
1009  }
1010  // merge incomming transitions form q2 to q1
1011  rtit = rtrans.BeginByX2(q2);
1012  rtit_end = rtrans.EndByX2(q2);
1013  for(;rtit!=rtit_end;++rtit) {
1014  // skip silent self-loop (handled later)
1015  if (qit->Exists(rtit->X1)&&rSilent.Exists(rtit->Ev))
1016  continue;
1017  rPGen.SetTransition(rtit->X1,rtit->Ev,q1);
1018  rtrans.Insert(rtit->X1,rtit->Ev,q1);
1019  }
1020  if(rPGen.ExistsMarkedState(q2))
1021  rPGen.InsMarkedState(q1);
1022  if((rPGen.ExistsInitState(q2)))
1023  rPGen.InsInitState(q1);
1024  delstates.Insert(q2);
1025  }
1026  // handle livelock selfloop
1027  std::map<StateSet,Idx>::const_iterator livelockit = rLivelocks.find(*qit);
1028  if(livelockit!=rLivelocks.end()){
1029  rPGen.SetTransition(*(qit->Begin()),livelockit->second,*(qit->Begin()));
1030  }
1031  }
1032  // do delete
1033  rPGen.DelStates(delstates);
1034 }
1035 
1036 
1037 // return a generator with silent transitions only (non silent are REMOVED, not hidden)
1038 // p -i-> q (i for prio) implies that there is a transition p => q on which the lowest priorit
1039 // (maximal value) is i.
1040 // NOTE: generates tau_0 self-loops.
1041 void SaturateLowestPrio(const pGenerator& rPGen, const EventSet& rSilent, pGenerator& rResult){
1042  FD_DF("SaturateLowestPrio()");
1043  rResult=rPGen;
1044  // only preserve silent transitions
1045  TransSet::Iterator tit = rResult.TransRelBegin();
1046  while (tit!=rResult.TransRelEnd()){
1047  if (!rSilent.Exists(tit->Ev)) // if not a silent trans, delete
1048  rResult.ClrTransition(tit++);
1049  else tit++;
1050  }
1051 
1052  if (rSilent.Empty()) return;
1053  // HELPERS:
1054  TransSet::Iterator tit1;
1055  TransSet::Iterator tit1_end;
1056  TransSet::Iterator tit2;
1057  TransSet::Iterator tit2_end;
1058 
1059  // initialize result with original transitionrelation
1060  TransSet xTrans=rResult.TransRel();
1061  TransSet newtrans = xTrans; // initialize iteration
1062  // loop for fixpoint
1063  while(!newtrans.Empty()) {
1064  // store new transitions for next iteration
1065  TransSet nextnewtrans;
1066  // loop over all transitions in newtrans
1067  tit1=newtrans.Begin();
1068  tit1_end=newtrans.End();
1069  for(;tit1!=tit1_end; ++tit1) {
1070  tit2=xTrans.Begin(tit1->X2);
1071  tit2_end=xTrans.End(tit1->X2);
1072  for(;tit2!=tit2_end; ++tit2) {
1073  // saturate the lower priority silent transition
1074  // copy first tit1's event
1075  if (rResult.Priority(tit1->Ev)<rResult.Priority(tit2->Ev)){
1076  if (!xTrans.Exists(tit1->X1,tit1->Ev,tit2->X2))
1077  nextnewtrans.Insert(tit1->X1,tit1->Ev,tit2->X2);
1078  }
1079  else{
1080  if (!xTrans.Exists(tit1->X1,tit2->Ev,tit2->X2))
1081  nextnewtrans.Insert(tit1->X1,tit2->Ev,tit2->X2);
1082  }
1083  }
1084  }
1085  // insert new transitions
1086  xTrans.InsertSet(nextnewtrans);
1087  // update trans for next iteration.
1088  newtrans = nextnewtrans;
1089  }
1090  rResult.InjectTransRel(xTrans);
1091 
1092  // install self loops of tau_inf on all states
1093  StateSet::Iterator sit = rPGen.StatesBegin();
1094  StateSet::Iterator sit_end = rPGen.StatesEnd();
1095  for(;sit!=sit_end;sit++){
1096  rResult.SetTransition(*sit,SilentEvAtPrio(rPGen,rSilent,rPGen.HighestPriority()),*sit);
1097  }
1098 }
1099 
1100 // saturate the transition (x)=epsilon=>->_Sig:k where
1101 // Sig is the set of active events of x if mode == 0, or
1102 // also include the successive =epsilon=>_0 part if mode==1
1103 void SaturatePDelayed(const pGenerator& rPGen,
1104  const EventSet& rSilent,
1105  const bool& _mode,
1106  pGenerator& rResult){
1107  rResult=rPGen;
1108 
1109  if (rSilent.Empty()) return;
1110  FD_DF("SaturatePDelayed()");
1111  // HELPERS:
1112  TransSet::Iterator tit1;
1113  TransSet::Iterator tit1_end;
1114  TransSet::Iterator tit2;
1115  TransSet::Iterator tit2_end;
1116 
1117  // initialize result with all self loops
1118  TransSet xTrans;
1119  StateSet::Iterator sit = rPGen.StatesBegin();
1120  Int kmin = rPGen.LowestPriority();
1121  Int kmax = rPGen.HighestPriority();
1122  for(;sit!=rPGen.StatesEnd();sit++){
1123  Int k;
1124  for(k=kmin;k<=kmax;k++){
1125  xTrans.Insert(*sit,SilentEvAtPrio(rPGen,rSilent,k),*sit);
1126  }
1127  }
1128  TransSet newtrans = xTrans; // initialize iteration
1129  // loop for fixpoint
1130  while(!newtrans.Empty()) {
1131  // store new transitions for next iteration
1132  TransSet nextnewtrans;
1133  // loop over all transitions in newtrans
1134  tit1=newtrans.Begin();
1135  tit1_end=newtrans.End();
1136  for(;tit1!=tit1_end; ++tit1) {
1137  if (_mode==0 && !rSilent.Exists(tit1->Ev)) continue; // in mode 0, do not saturate non-sil trans
1138  tit2=rPGen.TransRelBegin(tit1->X2);
1139  tit2_end=rPGen.TransRelEnd(tit1->X2);
1140  Idx tit1EvPrio = rPGen.Priority(tit1->Ev);
1141  for(;tit2!=tit2_end; ++tit2) {
1142  Idx tit2EvPrio = rPGen.Priority(tit2->Ev);
1143  // saturate the lower priority silent transition
1144  // copy first tit1's event
1145  if (rSilent.Exists(tit2->Ev)){ // if the next trans is silent
1146  if (rSilent.Exists(tit1->Ev)){ // both tit1's ev and tit2's are silent
1147  // to saturate, if must be at priority not lower than tit1's ev, and the
1148  // active ev inclusion must hold
1149  if (tit2EvPrio >= tit1EvPrio
1150  && NonsilHigherThen(rPGen,rSilent,tit2->X1,tit1EvPrio)<=NonsilHigherThen(rPGen,rSilent,tit1->X1,tit1EvPrio)){
1151  if (!xTrans.Exists(tit1->X1,tit1->Ev,tit2->X2))
1152  nextnewtrans.Insert(tit1->X1,tit1->Ev,tit2->X2);
1153  }
1154  }
1155  else if (_mode==1){ // tit1 not silent, then only saturate in mode1
1156  if (tit2EvPrio == 0){
1157  if (!xTrans.Exists(tit1->X1,tit1->Ev,tit2->X2))
1158  nextnewtrans.Insert(tit1->X1,tit1->Ev,tit2->X2);
1159  }
1160  }
1161  }
1162  else{ // the next transition is not silent
1163  // we also need to check that tit1 is silent
1164  if (rSilent.Exists(tit1->Ev)
1165  && tit2EvPrio <= tit1EvPrio
1166  && NonsilHigherThen(rPGen,rSilent,tit2->X1,tit1EvPrio)<=NonsilHigherThen(rPGen,rSilent,tit1->X1,tit1EvPrio)){
1167  if (!xTrans.Exists(tit1->X1,tit2->Ev,tit2->X2)){
1168  if (_mode==0)
1169  xTrans.Insert(tit1->X1,tit2->Ev,tit2->X2); // no need to iterate again in mode 0
1170  else
1171  nextnewtrans.Insert(tit1->X1,tit2->Ev,tit2->X2);
1172  }
1173  }
1174  }
1175  }
1176  }
1177  // insert new transitions
1178  xTrans.InsertSet(nextnewtrans);
1179  // update trans for next iteration (saturation front)
1180  newtrans = nextnewtrans;
1181  }
1182  rResult.InjectTransRel(xTrans);
1183 }
1184 
1185 
1186 // detect livelocks and store in rResult. rResult is a map of livelock->the SILENT EV whose priority describes the livelo
1187 // NOTE: WELL-FORMEDNESS REQUIRED!
1188 void DetectLiveLocks(const pGenerator &rPGen, const EventSet &rSilent, std::map<StateSet, Idx>& rResult){
1189  FD_DF("DetectLiveLocks()");
1190  rResult.clear();
1191 
1192  // have a generator copy where only silent transitions are preserved
1193  pGenerator copyg(rPGen);
1194  TransSet::Iterator tit = copyg.TransRel().Begin();
1195  while (tit!=copyg.TransRelEnd()){
1196  if (!rSilent.Exists(tit->Ev)) // if not a silent trans, delete
1197  copyg.ClrTransition(tit++);
1198  else tit++;
1199  }
1200 
1201  // compute eqclass and merge on original generator
1202  std::list<StateSet> eqclasses;
1203  StateSet dummy;
1204  ComputeScc(copyg,eqclasses,dummy);
1205 
1206  // delete spurious SCCs which are: trivial but non-selflooping, loop but with silent exit
1207  // note: well-formedness required
1208  std::list<StateSet>::const_iterator sccit = eqclasses.begin();
1209  for (;sccit!=eqclasses.end();sccit++){
1210  if ((*sccit).Size()==1){
1211  EventSet activesil = rPGen.ActiveEventSet(*sccit->Begin()) * rSilent;
1212  if (!activesil.Empty()) {
1213  TransSet::Iterator tit = rPGen.TransRelBegin(*sccit->Begin(),*activesil.Begin());
1214  for (;tit!=rPGen.TransRelEnd(*sccit->Begin(),*activesil.Begin());tit++){
1215  if (tit->X2!=tit->X1){ // there is a silent exit (regardless the existence of a sil selfloop)
1216  break;
1217  }
1218  }
1219  if (tit==rPGen.TransRelEnd(*sccit->Begin(),*activesil.Begin())){ // break was not executed
1220  rResult[*sccit] = *activesil.Begin();
1221  }
1222  }
1223  }
1224  else{ // a SCC with at least two states
1225  StateSet::Iterator sit = sccit->Begin();
1226  Idx livelockprio = rPGen.HighestPriority(); // initialise livelock lowest priority
1227  bool skip = false; // set to true if *sccit is not a livelock
1228  for(;sit!=sccit->End();sit++){
1229  EventSet activesil = rPGen.ActiveEventSet(*sit) * rSilent;
1230  if (!activesil.Empty()) {
1231  TransSet::Iterator tit = rPGen.TransRelBegin(*sit,*activesil.Begin());
1232  for (;tit!=rPGen.TransRelEnd(*sit,*activesil.Begin());tit++){
1233  if (!(*sccit).Exists(tit->X2)){ // there is a silent exit
1234  skip = true;
1235  break;
1236  }
1237  }
1238  if (skip) break;
1239  Idx newprio = rPGen.Priority(*activesil.Begin());
1240  if (newprio<livelockprio) livelockprio = newprio;
1241  }
1242  }
1243  if (!skip){
1244  rResult[*sccit] = SilentEvAtPrio(rPGen,rSilent,livelockprio);
1245  }
1246  }
1247  }
1248 }
1249 
1250 
1251 // typedef of incoming transitions. The 3 elements in the tuple are referred to as:
1252 // 0: from which state (=0 as "any initial state")
1253 // 1: via which (non-silent) event (=0 as "silently from any initial state")
1254 // 2: all silent prio events, each of which is denotes a hookarrow transition
1255 typedef std::map<std::pair<Idx, Idx>, EventSet> IncTransSet;
1256 
1257 // compute the incoming non-tau trans set of a state in a saturated
1258 // and tau-removed generator. Instead of directly return a
1259 // set of TransSet, a set of pair <Idx (source state), Idx (ev)>
1260 // is returned for a better performance, hopefully. Moreover,
1261 // for the sake of reachability from some intial state, a special pair
1262 // <0,0> indicates that this state can be silently reached from some
1263 // initial state.
1264 // ******input arguments:
1265 // rClosureFull: a result from SaturatePDelay with mode = 0, i.e. closure of =>->_Sig:k
1266 // rClosureLowest: a restricted result of SaturateLowestPrio
1267 // ******return bool: false if some silent pred has higher prio non-sil ev
1269  const pGenerator& rPGen,
1270  const pGenerator& rClosureFull,
1271  const pGenerator& rClosureLowest,
1272  const TransSetX2EvX1& rtrans_full,
1273  const TransSetX2EvX1& rtrans_lowest,
1274  const EventSet& rSilent,
1275  const Idx& rState,
1276  IncTransSet& rResult){
1277  FD_DF("IncommingTransSet()");
1278  TransSetX2EvX1 trans_lowest = rtrans_lowest;
1279  rResult.clear();
1280  // 1. test if there are silent pred with higher prio non-sil ev
1281  // if a silent pred can execute tau, then (due to wf) this tau must reach
1282  // rState.
1283  TransSetX2EvX1::Iterator rtit = rtrans_full.BeginByX2(rState);
1284  for(;rtit!=rtrans_full.EndByX2(rState);rtit++){
1285  if (!rSilent.Exists(rtit->Ev)) continue;
1286  EventSet activesil = rPGen.ActiveEventSet(rtit->X1) * rSilent;
1287  if (activesil.Empty()) continue;
1288  Idx k = rPGen.Priority(*activesil.Begin());
1289  if (!NonsilHigherThen(rPGen,rSilent,rtit->X1,k).Empty()) return false; // abort if test fails
1290  }
1291  // 2. test passed. compute incoming transset
1292  TransSetX2EvX1::Iterator rtit_lowest = trans_lowest.BeginByX2(rState);
1293  for (;rtit_lowest!=trans_lowest.EndByX2(rState);rtit_lowest++){
1294  EventSet ks;
1295  ks.Insert(rtit_lowest->Ev);
1296  // collect all possible hookarrows to rtit->X2
1297  TransSet::Iterator tit = rClosureLowest.TransRelBegin(rtit_lowest->X1);
1298  for(;tit!=rClosureLowest.TransRelEnd(rtit_lowest->X1);tit++){
1299  if (tit->X2 != rtit_lowest->X2
1300  || tit->Ev == rtit_lowest->Ev) continue; // skip self or wrong successor
1301  ks.Insert(tit->Ev);
1302  trans_lowest.Erase(*tit); // this cannot be the same as rtit, so OK
1303  }
1304  // find all non-sil predeccessors (or check if is initial state)
1305  if (rClosureFull.InitStates().Exists(rtit_lowest->X1)){
1306  std::pair<Idx,Idx> cstate = std::make_pair(0,0);
1307  IncTransSet::iterator visited = rResult.find(cstate);
1308  if(visited == rResult.end()){
1309  rResult[cstate] = ks;
1310  }
1311  else{
1312  rResult[cstate].InsertSet(ks);
1313  }
1314  }
1315  TransSetX2EvX1::Iterator rtit_original = rtrans_full.BeginByX2(rtit_lowest->X1);
1316  for(;rtit_original != rtrans_full.EndByX2(rtit_lowest->X1);rtit_original++){
1317  if (rSilent.Exists(rtit_original->Ev)) continue; // skip silent event
1318  std::pair<Idx,Idx> cstate = std::make_pair(rtit_original->X1,rtit_original->Ev);
1319  IncTransSet::iterator visited = rResult.find(cstate);
1320  if(visited == rResult.end()){
1321  rResult[cstate] = ks;
1322  }
1323  else{
1324  rResult[cstate].InsertSet(ks);
1325  }
1326  }
1327  }
1328  return true; // TM2025
1329 }
1330 
1331 // return eq classes of =_inc. Instead of returning list of state sets,
1332 // this function retunrs a map where the keys are the (source state, (non-tau)event) - pairs
1333 // and the value of each key is the corresponding eq class. Effectively, the keys are just
1334 // for efficient internal search of existing classes and will not be utilised in any other
1335 // functions which requies incoming eq (they will only need the values)
1336 void IncomingEquivalentClasses(const pGenerator& rPGen, const EventSet& rSilent, std::list<StateSet>& rResult){
1337  FD_DF("IncommingEquivalent()");
1338  // Preparation: saturate closureFull and closureLowest (necessary for incomingtransset)
1339  pGenerator closurefull;
1340  SaturatePDelayed(rPGen,rSilent,0,closurefull); // do not saturate the successive 0 part
1341  pGenerator closurelowest;
1342  // since hookarrow does not want the silent transitions to have active higher priority events
1343  pGenerator rPGen_shaped(rPGen);
1344  ShapePriorities(rPGen_shaped);
1345  SaturateLowestPrio(rPGen_shaped,rSilent,closurelowest);
1346 
1347  TransSetX2EvX1 trans_lowest; // buffer the rev trans of closurelowest
1348  closurelowest.TransRel().ReSort(trans_lowest);
1349  TransSetX2EvX1 trans_full; // buffer the rev trans of original gen
1350  closurefull.TransRel().ReSort(trans_full);
1351 
1352  // start the incoming equivalence partition
1353  StateSet::Iterator sit = rPGen.StatesBegin();
1354  StateSet::Iterator sit_end = rPGen.StatesEnd();
1355  // set up a map <incoming transset->class> to fast access incoming transset
1356  // of existing classes. This map is only meant to check incoming equivalence.
1357  std::map<IncTransSet,StateSet> incomingeqclasses;
1358  std::map<IncTransSet,StateSet>::iterator mit;
1359  for(;sit!=sit_end;sit++){
1360  IncTransSet rec_income;
1361  bool ok = IncomingTransSet(rPGen,closurefull,closurelowest,trans_full,trans_lowest,rSilent,*sit,rec_income);
1362  if (!ok) continue;
1363  if (rec_income.empty()) continue; // this should be redundant, as covered by "ok" above
1364  mit = incomingeqclasses.find(rec_income);
1365  if (mit != incomingeqclasses.end()){ // existing class found
1366  mit->second.Insert(*sit);
1367  }
1368  else { // no class for this state found
1369  StateSet newclass;
1370  newclass.Insert(*sit);
1371  incomingeqclasses[rec_income] = newclass;
1372  }
1373  }
1374 
1375  // return non-trivial classes
1376  rResult.clear();
1377  mit = incomingeqclasses.begin();
1378  for(;mit!=incomingeqclasses.end();mit++){
1379  if (mit->second.Size()>1) rResult.push_back(mit->second);
1380  }
1381 }
1382 
1383 // partition according to active events rule (AE) or silent continuation rule (SC)
1384 void AESCClasses(const pGenerator& rPGen, const EventSet& rSilent, std::list<StateSet>& rResult){
1385  FD_DF("AESCClasses()");
1386  rResult.clear();
1387  std::map<StateSet, Idx> livelocks; // only need keys, values are livelock prios which are irrelevant
1388  DetectLiveLocks(rPGen,rSilent,livelocks);
1389  //
1390  std::list<StateSet> inceq;
1391  IncomingEquivalentClasses(rPGen,rSilent,inceq); //prepartition inceq into result. then refine
1392  std::list<StateSet>::const_iterator inceqit = inceq.begin();
1393  // refine each inceq class
1394  for(;inceqit!=inceq.end();inceqit++){
1395  // never equalise states in livelocks
1396  std::map<StateSet,Idx>::const_iterator livelocksit = livelocks.begin();
1397  for(;livelocksit!=livelocks.end();livelocksit++){
1398  if (!(livelocksit->first * (*inceqit)).Empty())
1399  break;
1400  }
1401  if (livelocksit!=livelocks.end())
1402  continue;
1403  StateSet todo = *inceqit;
1404  // refine this eq class
1405  while (!todo.Empty()){
1406  Idx cstate = *todo.Begin();
1407  todo.Erase(todo.Begin());
1408  StateSet newclass;
1409  newclass.Insert(cstate);
1410  EventSet activesil = rPGen.ActiveEventSet(cstate)*rSilent;
1411  if (activesil.Empty()){ // no active silent evs. try AE
1412  StateSet::Iterator sit = todo.Begin();
1413  while(sit!=todo.End()){
1414  if (rPGen.ActiveEventSet(*sit) == rPGen.ActiveEventSet(cstate)){
1415  newclass.Insert(*sit);
1416  todo.Erase(sit++);
1417  }
1418  else
1419  sit++;
1420  }
1421  }
1422  else{ // then try SC
1423  StateSet::Iterator sit = todo.Begin();
1424  while(sit!=todo.End()){
1425  Idx tauprio = rPGen.Priority(*activesil.Begin());
1426  if ((rPGen.ActiveEventSet(*sit)*rSilent) == activesil // same active silent event
1427  &&
1428  NonsilHigherThen(rPGen,rSilent,*sit,tauprio).Size()+ NonsilHigherThen(rPGen,rSilent,cstate,tauprio).Size()==0){
1429  newclass.Insert(*sit);
1430  todo.Erase(sit++);
1431  }
1432  else
1433  sit++;
1434  }
1435  }
1436  if (newclass.Size()>1) rResult.push_back(newclass);
1437  }
1438  }
1439 }
1440 
1441 void MergeAESC(pGenerator& rPGen, const EventSet& rSilent){
1442  std::map<StateSet, Idx> livelocks;
1443  DetectLiveLocks(rPGen,rSilent,livelocks);
1444  std::list<StateSet> eqclasses;
1445  AESCClasses(rPGen, rSilent, eqclasses);
1446  MergeEquivalenceClasses(rPGen,rSilent,livelocks,eqclasses);
1447 }
1448 
1449 // saturate pwb by connecting =>_<k (with target state not having tau<k) and =>_Sig:k closure
1450 void SaturatePWB(const pGenerator& rPGen,
1451  const EventSet& rSilent,
1452  pGenerator& rResult){
1453  FD_DF("SaturatePWB()");
1454  rResult = rPGen;
1455  pGenerator closurelowest;
1456  SaturateLowestPrio(rPGen,rSilent,closurelowest);
1457  pGenerator closurefull;
1458  SaturatePDelayed(rPGen,rSilent, 1,closurefull);
1459  // figure out the highest possible k for =>_<k (with target not tau<k) transitions for each two states
1460  TransSet resulttrans; // put saturated trans here. Inject to rResult eventually
1461  StateSet::Iterator sit = closurelowest.StatesBegin();
1462  for(;sit!=closurelowest.StatesEnd();sit++){
1463  StateSet visitedtarget; // buffer a set of visited target states of transitions from sit
1464  TransSet::Iterator tit_lowest = closurelowest.TransRelBegin(*sit);
1465  for(;tit_lowest!=closurelowest.TransRelEnd(*sit);tit_lowest++){
1466  if (visitedtarget.Exists(tit_lowest->X2))
1467  continue;
1468  visitedtarget.Insert(tit_lowest->X2);
1469  // find the highest lowest priority to tit->X2 (X2 not >k not treated yet)
1470  Idx highest = rPGen.Priority(tit_lowest->Ev);
1471  if(highest<rPGen.HighestPriority()){
1472  TransSet::Iterator tit2_lowest = closurelowest.TransRelBegin(*sit);
1473  for(;tit2_lowest!=closurelowest.TransRelEnd(*sit);tit2_lowest++){
1474  if (tit2_lowest->X2 != tit_lowest->X2) continue;
1475  Idx newprio = rPGen.Priority(tit2_lowest->Ev);
1476  if (newprio > highest) highest = newprio;
1477  if (highest==rPGen.HighestPriority()) break;
1478  }
1479  }
1480  // now check if X2 cannot >k, if k<maxprio
1481  // in the following, highest's meaning is changed to "the highest k tit allows for successive transitions"
1482  bool ismax = (highest==rPGen.HighestPriority()); // highest = max is a special case
1483  // (does not need ++ to allow successive maxprio trans)
1484  highest--; // for highest \neq maxprio, the highest allowed prioity is actually highest--
1485  Idx lowest = rPGen.LowestPriority(); // allowed lowest priority, changed if some tau is active on X2
1486  EventSet activesil = rPGen.ActiveEventSet(tit_lowest->X2) * rSilent;
1487  if (!activesil.Empty()){
1488  Idx k_activesil = rPGen.Priority(*activesil.Begin());
1489  lowest = k_activesil;
1490  // bail out when transition extension is already impossible
1491  if (!ismax && lowest > highest) continue;
1492  }
1493  // now we have the lowest k allowed. Check for possible trans extension from closurefull
1494  TransSet::Iterator tit_full = closurefull.TransRelBegin(tit_lowest->X2); // sit is tit->X1
1495  for(;tit_full!=closurefull.TransRelEnd(tit_lowest->X2);++tit_full){
1496  Idx k_succ = rPGen.Priority(tit_full->Ev);
1497  if ((k_succ >= lowest && k_succ <= highest)
1498  || (ismax && k_succ==rPGen.HighestPriority())){ // its OK!
1499  resulttrans.Insert(*sit,tit_full->Ev,tit_full->X2);
1500  }
1501  }
1502  }
1503  }
1504  rResult.InjectTransRel(resulttrans);
1505 }
1506 
1507 void MergePWB(pGenerator& rPGen, const EventSet& rSilent){
1508  std::map<StateSet, Idx> livelocks;
1509  DetectLiveLocks(rPGen,rSilent,livelocks);
1510  pGenerator pwbclosure;
1511  SaturatePWB(rPGen,rSilent,pwbclosure);
1512  std::list<StateSet> eqclasses;
1513  ComputeBisimulation(pwbclosure,eqclasses);
1514  MergeEquivalenceClasses(rPGen,rSilent,livelocks,eqclasses);
1515 }
1516 
1517 
1518 void RedundantSilentStep(pGenerator& rPGen, const EventSet& rSilent){
1519  FD_DF("RedundantSilentStep()");
1520  TransSetX2EvX1 rtrans;
1521  rPGen.TransRel().ReSort(rtrans);
1522  StateSet::Iterator sit = rPGen.StatesBegin();
1523  while(sit!=rPGen.StatesEnd()){
1524  if ((rPGen.InitStates() + rPGen.MarkedStates()).Exists(*sit)) {sit++;continue;}
1525  TransSet::Iterator tit = rPGen.TransRelBegin(*sit);
1526  Idx count = 0;
1527  for(;tit!=rPGen.TransRelEnd(*sit);tit++){
1528  count++;
1529  }
1530  if (count!=1) {sit++;continue;} // only have one outgoing trans
1531  tit = rPGen.TransRelBegin(*sit);
1532  if (!rSilent.Exists(tit->Ev)) {sit++;continue;} // and this trans must be silent
1533  // are all incoming trans silent with no higher priority?
1534  Idx k = rPGen.Priority(tit->Ev);
1535  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit);
1536  for(;rtit!=rtrans.EndByX2(*sit);rtit++){
1537  if (!rSilent.Exists(rtit->Ev)) break;
1538  if (rPGen.Priority(rtit->Ev)>=k) break;
1539  }
1540  if (rtit!=rtrans.EndByX2(*sit)) {sit++;continue;}
1541  // sit qualified. Remove and redirect transition
1542  rtit=rtrans.BeginByX2(*sit);
1543  for(;rtit!=rtrans.EndByX2(*sit);rtit++){
1544  rPGen.SetTransition(rtit->X1,rtit->Ev,tit->X2);
1545  }
1546  StateSet::Iterator todelete = sit++;
1547  rPGen.DelState(*todelete);
1548  // update rtrans
1549  rtrans.Clear();
1550  rPGen.TransRel().ReSort(rtrans);
1551  }
1552 }
1553 
1554 // input automaton should be redundant silent loop free
1555 void OnlySilentIncoming(pGenerator& rPGen, const EventSet& rSilent, const StateSet& rLivelocks){
1556  FD_DF("OnlySilentIncomming()");
1557  // figure states with only silent incomming transitions
1558  TransSetX2EvX1 rtrans;
1559  rPGen.TransRel().ReSort(rtrans);
1560  // pre-filter uncapable states
1561  StateSet cand=rPGen.States()-rPGen.InitStates()-rLivelocks; // lasily exclude initial states
1562  TransSet::Iterator tit = rPGen.TransRelBegin();
1563  TransSet::Iterator tit_end = rPGen.TransRelEnd();
1564  for(;tit!=tit_end;++tit){
1565  if(!rSilent.Exists(tit->Ev)
1566  || rPGen.Priority(tit->Ev)!=rPGen.HighestPriority()) cand.Erase(tit->X2);
1567  }
1568  // bail out on trivial
1569  if(cand.Size()==0) return;
1570 
1571  StateSet::Iterator sit = cand.Begin();
1572  StateSet::Iterator sit_end = cand.End();
1573  while (sit!=sit_end){
1574  TransSet::Iterator tit2 = rPGen.TransRelBegin(*sit);
1575  TransSet::Iterator tit2_end = rPGen.TransRelEnd(*sit);
1576  for (;tit2!=tit2_end;tit2++){
1577  if (rSilent.Exists(tit2->Ev)&&rPGen.Priority(tit2->Ev)==rPGen.HighestPriority()){
1578  break;
1579  }
1580  }
1581  if (tit2!=tit2_end) { // there is at least one tau_max outgoing
1582  // redirect transitions
1583  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit);
1584  TransSetX2EvX1::Iterator rtit_end = rtrans.EndByX2(*sit);
1585  for(;rtit!=rtit_end;rtit++){
1586  TransSet::Iterator tit3 = rPGen.TransRelBegin(*sit);
1587  TransSet::Iterator tit3_end = rPGen.TransRelEnd(*sit);
1588  for (;tit3!=tit3_end;tit3++){
1589  if (rtit->X1 == tit3->X2 && rSilent.Exists(tit3->Ev)) continue; // avoid generating silent self loop
1590  rPGen.SetTransition(rtit->X1,tit3->Ev,tit3->X2);
1591  }
1592  // if the state to delete is marked, then pred-state should be marked as well
1593  if (rPGen.ExistsMarkedState(*sit))
1594  rPGen.SetMarkedState(rtit->X1);
1595  }
1596  StateSet::Iterator todelete = sit++;
1597  rPGen.DelState(*todelete);
1598  }
1599  else sit++;
1600 
1601  // update rtrans
1602  rtrans.Clear();
1603  rPGen.TransRel().ReSort(rtrans);
1604  }
1605 }
1606 
1607 void OnlySilentOutgoing(pGenerator& rPGen, const EventSet& rSilent, const StateSet& rLivelocks){
1608  FD_DF("OnlySilentOutgoing()");
1609  TransSetX2EvX1 rtrans;
1610  rPGen.TransRel().ReSort(rtrans);
1611  StateSet::Iterator sit = rPGen.StatesBegin();
1612  StateSet::Iterator sit_end = rPGen.StatesEnd();
1613  while(sit!=sit_end){
1614  // figure out whether this state is only silent outgoing
1615  if ((rPGen.MarkedStates()+rLivelocks).Exists(*sit)) {sit++;continue;}
1616  TransSet::Iterator tit2 = rPGen.TransRelBegin(*sit);
1617  TransSet::Iterator tit2_end = rPGen.TransRelEnd(*sit);
1618  if (tit2==tit2_end) {sit++;continue;} // sit points to a deadend state (nonmarked state without outgoing trans)
1619  for (;tit2!=tit2_end;tit2++){
1620  if (!rSilent.Exists(tit2->Ev)) break;// sit has non-silent outgoing trans
1621  if (rPGen.Priority(tit2->Ev)!=rPGen.HighestPriority()) break; // must be with prio = max
1622  }
1623  if (tit2 != tit2_end) {sit++;continue;}
1624 
1625  // sit has passed the test. relink outgoing transitions of predecessor
1626  // (repair initial state quicker by first iterate outgoing trans)
1627  tit2 = rPGen.TransRelBegin(*sit);
1628  tit2_end = rPGen.TransRelEnd(*sit);
1629  for (;tit2!=tit2_end;tit2++){
1630  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit); // incoming trans to *sit
1631  TransSetX2EvX1::Iterator rtit_end = rtrans.EndByX2(*sit);
1632  for (;rtit!=rtit_end;rtit++){
1633  if (rtit->X1 == tit2->X2 && rSilent.Exists( rtit->Ev)) continue; // avoid generating silent self loop
1634  rPGen.SetTransition(rtit->X1,rtit->Ev,tit2->X2);
1635  }
1636  if (rPGen.ExistsInitState(*sit))
1637  rPGen.SetInitState(tit2->X2);
1638  }
1639  StateSet::Iterator todelete = sit++;
1640  rPGen.DelState(*todelete);
1641 
1642  // update rtrans
1643  rtrans.Clear();
1644  rPGen.TransRel().ReSort(rtrans);
1645  }
1646 }
1647 
1648 // return the set of set of strongly coacc states depending on
1649 // the fairness constraints.
1650 // NOTE: this shall be considered as a member function of pGenerator,
1651 // to reimplement
1653  FD_DF("StronglyCoaccessibleSet()");
1654  Generator copy = rPGen;
1655  copy.Accessible();
1656  StateSet result = copy.States();
1658  for(;fpos<rPGen.GlobalAttribute().Fairness().Size();++fpos) {
1659  const EventSet& fair = rPGen.GlobalAttribute().Fairness().At(fpos);
1660  copy.ClearMarkedStates();
1661  StateSet::Iterator sit = copy.StatesBegin();
1662  for(;sit!=copy.StatesEnd();sit++){
1663  // if a state can execute a fair event, it's "marked" for this fairness constraint
1664  if(!(copy.ActiveEventSet(*sit) * fair).Empty()){
1665  copy.SetMarkedState(*sit);
1666  }
1667  }
1668  result = result * copy.CoaccessibleSet(); //this is the ordinary function for marked states
1669  }
1670  return result;
1671 }
1672 
1673 // Certain conflicts. see cited literature 3.2.3
1674 // -- remove outgoing transitions from not coaccessible states
1676  FD_DF("RemoveNonCoaccessible()");
1677  StateSet notcoacc=rPGen.States()-StronglyCoaccessibleSet(rPGen);
1678  StateSet::Iterator sit=notcoacc.Begin();
1679  StateSet::Iterator sit_end=notcoacc.End();
1680  for(;sit!=sit_end;++sit){
1681  TransSet::Iterator tit=rPGen.TransRelBegin(*sit);
1682  TransSet::Iterator tit_end=rPGen.TransRelEnd(*sit);
1683  while(tit!=tit_end)
1684  rPGen.ClrTransition(tit++);
1685  }
1686  rPGen.Accessible();
1687 }
1688 
1689 // Certain conflicts. see cited literature 3.2.3
1690 // -- remove outgoing transitions from states that block by a silent event
1691 void BlockingSilentEvent(pGenerator& rPGen,const EventSet& rSilent){
1692  FD_DF("BlockingSilentEvent(): prepare for t#"<<rPGen.TransRelSize());
1693  StateSet coacc=StronglyCoaccessibleSet(rPGen);
1694  StateSet sblock; // states with outgoing silent event with highest active priority and leads to block
1695  TransSet::Iterator tit;
1696  TransSet::Iterator tit_end;
1697  StateSet::Iterator sit;
1698  StateSet::Iterator sit_end;
1699  // loop all transitions to figure certain blocking states
1700  tit=rPGen.TransRelBegin();
1701  tit_end=rPGen.TransRelEnd();
1702  for(;tit!=tit_end;++tit) {
1703  if(rSilent.Exists(tit->Ev))
1704  if(!coacc.Exists(tit->X2)){
1705  // is this silent event with the highest priority at this state?
1706  EventSet active = rPGen.ActiveEventSet(tit->X1);
1707  EventSet::Iterator eit = active.Begin();
1708  Idx highest = rPGen.LowestPriority();
1709  for(;eit!=active.End();eit++){
1710  if (rPGen.Priority(*eit)>highest)
1711  highest = rPGen.Priority(*eit);
1712  }
1713  if(rPGen.Priority(tit->Ev)==highest)
1714  sblock.Insert(tit->X1);
1715  }
1716  }
1717  // unmark blocking states and eliminate possible future
1718  sit=sblock.Begin();
1719  sit_end=sblock.End();
1720  for(;sit!=sit_end;++sit) {
1721  rPGen.ClrMarkedState(*sit);
1722  tit=rPGen.TransRelBegin(*sit);
1723  tit_end=rPGen.TransRelEnd(*sit);
1724  while(tit!=tit_end)
1725  rPGen.ClrTransition(tit++);
1726  }
1727  rPGen.Accessible();
1728  FD_DF("BlockingSilentEvent(): done with t#"<<rPGen.TransRelSize());
1729 }
1730 
1731 // -- merge all states that block to one representative
1733  FD_DF("MergeNonCoaccessible()");
1734  StateSet notcoacc=rPGen.States()-StronglyCoaccessibleSet(rPGen);
1735  // bail out on trivial case
1736  if(notcoacc.Size()<2) return;
1737  // bail out with blocking init state
1738  if((notcoacc * rPGen.InitStates()).Size()>0){
1739  rPGen.DelStates(rPGen.States());
1740  Idx qnc = rPGen.InsState();
1741  rPGen.SetInitState(qnc);
1742  return;
1743  }
1744  // have a new state
1745  Idx qnc=rPGen.InsState();
1746  // fix transitions by iterating over predecessors of notcoacc
1747  TransSetX2EvX1 rtrans;
1748  rPGen.TransRel().ReSort(rtrans);
1749  StateSet::Iterator sit = notcoacc.Begin();
1750  for(;sit!=notcoacc.End();sit++){
1751  TransSetX2EvX1::Iterator rtit = rtrans.BeginByX2(*sit);
1752  for(;rtit!=rtrans.EndByX2(*sit);rtit++){
1753  rPGen.SetTransition(rtit->X1,rtit->Ev,qnc);
1754  }
1755  }
1756  // delete original not coacc
1757  rPGen.DelStates(notcoacc);
1758 }
1759 
1760 
1761 // -- if a transition blocks, remove all transitions from the same state with the same label
1762 void BlockingEvent(pGenerator& rPGen,const EventSet& rSilent){
1763  FD_DF("BlockingEvent(): prepare for t#"<<rPGen.TransRelSize());
1764  StateSet coacc=StronglyCoaccessibleSet(rPGen);
1765  StateSet notcoacc = rPGen.States()-coacc;
1766  TransSetX2EvX1 rtrans;
1767  rPGen.TransRel().ReSort(rtrans);
1768  TransSet::Iterator tit;
1769  TransSet::Iterator tit_end;
1770  StateSet::Iterator sit;
1771  StateSet::Iterator sit_end;
1773  TransSetX2EvX1::Iterator rtit_end;
1774  TransSet deltrans;
1775  // loop over notcoacc (normally smaller than coacc) and find coacc pred
1776  sit = notcoacc.Begin();
1777  sit_end = notcoacc.End();
1778  for(;sit!=sit_end;sit++){
1779  rtit = rtrans.BeginByX2(*sit);
1780  rtit_end = rtrans.EndByX2(*sit);
1781  for(;rtit!=rtit_end;rtit++){
1782  if (rSilent.Exists(rtit->Ev)) continue; // silent blocking evs are handled elsewhere
1783  if (!coacc.Exists(rtit->X1)) continue; // incoming trans from coacc
1784  // current rtit is such that X1 is coacc but X2 is not, Ev is nonsilent
1785  // record transitions from the X1 with the same event BUT not rtit
1786  tit = rPGen.TransRelBegin(rtit->X1);
1787  tit_end = rPGen.TransRelEnd(rtit->X1);
1788  for(;tit!=tit_end;tit++){
1789  if(tit->X2 == rtit->X2) continue; // skip for tit==rtit
1790  if(tit->Ev == rtit->Ev)
1791  deltrans.Insert(*tit);
1792  }
1793  }
1794  }
1795  // delete transitions
1796  tit=deltrans.Begin();
1797  tit_end=deltrans.End();
1798  for(;tit!=tit_end;++tit)
1799  rPGen.ClrTransition(*tit);
1800  FD_DF("BlockingEvent(): done with t#"<<rPGen.TransRelSize());
1801 }
1802 
1804  pGenerator& rPGen,
1805  const EventSet& rSilent){
1806  if (rSilent.Empty()) return;
1807  FD_DF("PConflictPreservingAbstraction()");
1808  // preparation: augment fictive silent events if not existing in rPGen's alphabet
1809  EventSet augsilent = rSilent;
1810  // record silent ev priorities
1811  std::set<Idx> existingsil_k;
1812  EventSet::Iterator eit = rSilent.Begin(); // NOTE: rSilent should be a subset of rPGen.Alphabet
1813  for(;eit!=rSilent.End();eit++)
1814  existingsil_k.insert(rPGen.Priority(*eit));
1815  // loop over all silentevent priorities
1816  std::set<Idx>::iterator kit=existingsil_k.begin();
1817  for(;kit!=existingsil_k.end();++kit) {
1818  Idx k=*kit;
1819  FD_DF("PConflictPreservingAbstraction(): prio "<<k);
1820  std::string silevname = ":::" + ToStringInteger(k);
1821  if(rPGen.Alphabet().Exists(silevname)){
1822  std::stringstream errstr;
1823  errstr << "Alphabet of '" << rPGen.Name() << "' inculdes reserved symbolic name " << silevname;
1824  throw Exception("PConflictPreservingAbstraction", errstr.str(), 599);
1825  }
1826  Idx silev = rPGen.InsEvent(silevname);
1827  rPGen.Priority(silev,k);
1828  augsilent.Insert(silev);
1829  }
1830  ShapeUpsilon(rPGen,augsilent); // enforce well-formedness
1831  rPGen.Accessible();
1832  FD_DF("PConflictPreservingAbstraction(): loop A done");
1833 
1834 
1835  // certain conflicts
1836  // ******************NOTE: empty fairness constraints = trivial Nonblocking!
1837  if (rPGen.GlobalAttribute().Fairness().Size()>0){ // cosmetically skip
1838  BlockingEvent(rPGen,augsilent);
1839  BlockingSilentEvent(rPGen,augsilent);
1840  RemoveNonCoaccessibleOut(rPGen);
1841  MergeNonCoaccessible(rPGen);
1842  }
1843  // redundant silent step rule
1844  RedundantSilentStep(rPGen,augsilent); // quick, may produce silent selfloop, guarantee well-formedness
1845  // only silent in/out rules
1846  RemoveRedSilentSelfloops(rPGen,augsilent); // no redundant silent loops any more
1847  std::map<StateSet,Idx> livelocks;
1848  DetectLiveLocks(rPGen,augsilent,livelocks);
1849  StateSet skipstates;
1850  std::map<StateSet,Idx>::const_iterator livelockit = livelocks.begin();
1851  for(;livelockit!=livelocks.end();++livelockit){
1852  skipstates.InsertSet(livelockit->first);
1853  }
1854  OnlySilentIncoming(rPGen,augsilent,skipstates);
1855  OnlySilentOutgoing(rPGen,augsilent,skipstates);
1856  // AESC and PWB
1857  MergePWB(rPGen,augsilent);
1858  MergeAESC(rPGen,augsilent);
1859 
1860  // cosmetically set clean state names
1861  rPGen.SetDefaultStateNames();
1862 
1863  // OPTIONAL: remove augmented silent events
1864  EventSet remove = augsilent - rSilent;
1865  if (!remove.Empty())
1866  rPGen.DelEvents(remove);
1867  FD_DF("PConflictPreservingAbstraction(): done");
1868 }
1869 
1870 bool IsHideable(const pGenerator& rPGen,
1871  const EventSet& rSilent,
1872  const Transition& rTrans){
1873  FD_DF("IsHidable()");
1874  if (!rSilent.Exists(rTrans.Ev)) return false; // this is not a silent event at all (e.g. _OMEGA_)
1875  FairnessConstraints relevant; // collect all fairness constraints containing rTrans->Ev
1877  for(;fpos<rPGen.GlobalAttribute().Fairness().Size();++fpos){
1878  const EventSet& fair = rPGen.GlobalAttribute().Fairness().At(fpos);
1879  if(fair.Exists(rTrans.Ev))
1880  relevant.Append(fair);
1881  }
1882  if (relevant.Empty()) return true; // this event is not in any fairness constraint
1883  // get the =>_Sig:k closure from rTrans->X2
1884  StateSet todo;
1885  StateSet visited;
1886  const Idx k = rPGen.Priority(rTrans.Ev);
1887  const EventSet x1active = NonsilHigherThen(rPGen,rSilent,rTrans.X1,k);
1888  if (NonsilHigherThen(rPGen,rSilent,rTrans.X2,k)<=x1active){
1889  todo.Insert(rTrans.X2);
1890  }
1891  while (!todo.Empty()){
1892  Idx cstate = *todo.Begin();
1893  todo.Erase(todo.Begin());
1894  visited.Insert(cstate);
1895  FairnessConstraints relevant_copy = relevant; // buffer a copy of relevant fairness constraints
1896  StateSet todo_new; // buffer a state set for qualified silent successors
1897  TransSet::Iterator tit = rPGen.TransRelBegin(cstate);
1898  for(;tit!=rPGen.TransRelEnd(cstate);tit++){
1899  if (!rSilent.Exists(tit->Ev)) continue;
1900  if (rPGen.Priority(tit->Ev) <k) continue; // required both for colouring or silent successor
1901  if (*tit == rTrans) continue;
1902  // how many relevant fairness constraints are satisfied?
1904  for(;fpos<relevant_copy.Size();++fpos){
1905  const EventSet& fair = relevant_copy.At(fpos);
1906  if (fair.Exists(tit->Ev)){
1907  relevant_copy.Erase(fpos); // remove when this fairness cons is satisfied
1908  continue;
1909  }
1910  fpos++;
1911  }
1912  if (relevant_copy.Empty()) return true;
1913  // is tit->X2 a suitable silent successor?
1914  if (NonsilHigherThen(rPGen,rSilent,tit->X2,k)<=x1active){
1915  todo_new.Insert(tit->X2);
1916  }
1917  }
1918  todo.InsertSet(todo_new - visited);
1919  }
1920  return false;
1921 }
1922 
1923 // substitute all private events with a new event with the same priority
1924 // while also fix the private event set rPrivate
1925 // THE fairness version
1926 // pUnhideable: a set of always unhideable events
1928  EventSet& rPrivate,
1929  EventPriorities& rPrios,
1930  Idx& rTau,
1931  const EventSet* pUnHideable = nullptr){
1932  EventSet result;
1933  EventSet msilentevs=rPGen.Alphabet() * rPrivate;
1934  if(msilentevs.Empty()){
1935  return result;
1936  }
1937  FD_DF("HidePrivateEvs(): HP " << rPGen.HighestPriority() << " LP " << rPGen.LowestPriority());
1938  // install tau events to alphabet
1939  std::vector<Idx> tauevs; // buffer a vector for fast search. Position index = priority
1940  tauevs.reserve(rPGen.HighestPriority()+1);
1941  Idx k = rPGen.LowestPriority();
1942  for(;k<=rPGen.HighestPriority();++k){
1943  FD_DF("HidePrivateEvs(): prio " << k);
1944  std::string tauevname = "__TAU"+ToStringInteger(rTau)+":"+ToStringInteger(k);
1945  if (rPGen.Alphabet().Exists(tauevname)){
1946  std::stringstream errstr;
1947  errstr << "Alphabet of '" << rPGen.Name() << "' inculdes reserved symbolic name "<< tauevname;
1948  throw Exception("HidePrivateEvs", errstr.str(), 599);
1949  }
1950  Idx tauev = rPGen.InsEvent(tauevname);
1951  tauevs.push_back(tauev); // the index coincides the k mius offset value
1952  result.Insert(tauev);
1953  rPGen.Priority(tauev,k);
1954  rPrios.InsPriority(tauev,k);
1955  }
1956  rTau++; // updates tau index
1957  TransSet::Iterator tit = rPGen.TransRelBegin();
1958  EventSet unhideable;
1959  if (pUnHideable != nullptr) unhideable = *pUnHideable;
1960  while(tit!=rPGen.TransRelEnd()){
1961  if (!IsHideable(rPGen,msilentevs+result,*tit)||result.Exists(tit->Ev)||unhideable.Exists(tit->Ev)){
1962  tit++;
1963  continue;
1964  }
1965  Transition trans(tit->X1,tauevs.at(rPGen.LowestPriority()+rPGen.Priority(tit->Ev)),tit->X2);
1966  rPGen.SetTransition(trans);
1967  rPGen.ClrTransition(tit++);
1968  }
1969  rPrivate.EraseSet(msilentevs); // benefits other automata
1970  FD_DF("HidePrivateEvs(): done");
1971  return result;
1972 }
1973 
1974 // monolithic fairness check
1975 // NOTE: Does not shape. For prioritised automaton consider Shape first.
1977  FD_DF("IsStronglyNonblocking()");
1978  Generator copy = rPGen;
1979  copy.Accessible();
1981  for(;fpos<rPGen.GlobalAttribute().Fairness().Size();++fpos){
1982  const EventSet& fair = rPGen.GlobalAttribute().Fairness().At(fpos);
1983  copy.ClearMarkedStates();
1984  StateSet::Iterator sit = copy.StatesBegin();
1985  for(;sit!=copy.StatesEnd();sit++){
1986  // if a state can execute a fair event, it's "marked" for this fairness constraint
1987  if(!(copy.ActiveEventSet(*sit) * fair).Empty()){
1988  copy.SetMarkedState(*sit);
1989  }
1990  }
1991  if (!faudes::IsNonblocking(copy)){
1992  StateSet blocking = copy.BlockingStates();
1993  std::cout<<"****** THE BLOCKING: "+ToStringInteger(*blocking.Begin())<<std::endl;
1994  return false; // fails at this fairness constraint
1995  }
1996  }
1997  return true;
1998 }
1999 
2000 
2001 // merge the fairness constraint of two pGenerators
2002 void MergeFairness(const pGenerator& rPGen1, const pGenerator& rPGen2, FairnessConstraints& rFairRes){
2003  rFairRes = rPGen1.GlobalAttribute().Fairness();
2005  for(;fpos<rPGen2.GlobalAttribute().Fairness().Size();++fpos){
2006  const EventSet& fair = rPGen2.GlobalAttribute().Fairness().At(fpos);
2007  rFairRes.Append(fair);
2008  }
2009 }
2010 
2011 
2012 // The main function for non-conflict check.
2013 // a) if rFairVec is non-empty, fairness constraints are considered
2014 // b) if rFairVec is empty we treat omega-termination as the acceptance condition (see below wraper)
2016  const EventPriorities& rPrios,
2017  const std::vector<FairnessConstraints>& rFairVec) {
2018 
2019  FD_DF("IsPFNonblocking()");
2020  // have a writable copy
2021  EventPriorities prios=rPrios;
2022 
2023  // consistency check for coloured marking
2024  if(rFairVec.size()>0){
2025  if (rGvec.Size()!=rFairVec.size()){
2026  std::stringstream errstr;
2027  errstr << "consistency check fails (vector length mismatch)";
2028  throw Exception("IsPFNonconflicting", errstr.str(), 599);
2029  }
2030  Idx git = 0;
2031  for(;git!=rGvec.Size();git++){
2033  for(;fpos<rFairVec.at(git).Size();++fpos){
2034  const EventSet& fair = rFairVec.at(git).At(fpos);
2035  if (!(fair<=rGvec.At(git).Alphabet())){
2036  std::stringstream errstr;
2037  errstr << "Consistency check fails";
2038  errstr << "Generator '"<<rGvec.At(git).Name() <<"' contains fairness event not in its alphabet";
2039  throw Exception("IsPFNonconflicting", errstr.str(), 599);
2040  }
2041  }
2042  }
2043  }
2044  Idx tau = 0; // index for "full hiding"
2045 
2046  EventSet merging;
2047  std::map<std::string,Idx>::const_iterator mit;
2048  // if isSFC==1, set up merging events. Also check priority (disjunct is checked by SFC_Parallel)
2049 
2050 
2051  PCOMPVER_VERB1("IsPFNonconflicting:: Installing priority and appending omega termination")
2052  // rearrange for consecutive priorities starting at 1 // TM2025/04
2053  //prios.NormalisePriorities();
2054  // get lowest/highest priority (PWB requires on extra prioity below internally) TMPRIO
2055  Idx lowest = prios.LowestPriority();
2056  Idx highest = prios.HighestPriority();
2057  if(lowest==0){
2058  throw Exception("IsPFNonconflicting()", "priority 0 reserved for internal use", 599);
2059  }
2060  lowest--;
2061  // encode priority and fairness information into pgen
2062  std::vector<pGenerator> pgenvec;
2063  pgenvec.reserve(rGvec.Size());
2064  Idx git = 0;
2065  for(;git!=rGvec.Size();git++){
2066  pGenerator pgen=rGvec.At(git);
2067  pgen.Priorities(prios);
2068  pgen.LowestPriority(lowest);
2069  pgen.HighestPriority(highest);
2070  if (rFairVec.size()==0){ // go for omega termination
2071  AppendOmegaTermination(pgen,prios);
2072  }
2073  else{ // install predefined fairness
2074  pgen.GlobalAttributep()->Fairness(rFairVec.at(git));
2075  }
2076  pgenvec.push_back(pgen);
2077  }
2078  bool firstCycle = true;
2079  while (true){
2080  PCOMPVER_VERB1("========================================")
2081  PCOMPVER_VERB1("Remaining automata: "<<pgenvec.size())
2082 
2083  // trivial cases
2084  if(pgenvec.size()==0) return true;
2085  if(pgenvec.size()==1) break;
2086 
2087  // figure silent events
2088  EventSet silent, all, shared;
2089  Idx git = 0;
2090  while(true){
2091  all = all+pgenvec.at(git).Alphabet();
2092  Idx git_next = git+1;
2093  if (git_next == pgenvec.size()) break;
2094  for(;git_next!=pgenvec.size();git_next++){
2095  shared = shared
2096  + (pgenvec.at(git).Alphabet())
2097  * (pgenvec.at(git_next).Alphabet());
2098  }
2099  git++;
2100  }
2101  silent=all-shared; // all silent events in all current candidates
2102  // normalize for one silent event at each priority level per generator, and then abstract.
2103  // note from the second iteration, this is only necessary for the
2104  // automaton composed from former candidates. This is realized by
2105  // the break at the end
2106  git = 0;
2107  for(;git!=pgenvec.size();git++){
2108  //abstraction
2109  pGenerator& g = pgenvec.at(git);
2110  PCOMPVER_VERB1("Abstracting Automaton "<< g.Name()<<", with state count: "<<g.Size())
2111  ShapeUpsilon(g,silent); // enforce well-formedness
2112  g.Accessible();
2113  EventSet upsilon = HidePrivateEvs(g,silent,prios,tau,&merging);
2114  PConflictPreservingAbstraction(g, upsilon);
2115  PCOMPVER_VERB1("State count after abstraction: "<<g.Size())
2116  if (!firstCycle) break;
2117  }
2118  firstCycle = false;
2119 
2120  // candidate choice heuritics. Branch by different tasks
2121  Idx imin = 0;
2122  Idx jmin = 0;
2123 
2124  // // candidat pairs with fewest transitions 'minT'
2125  // git = 1;
2126  // for(;git!=pgenvec.size();git++){
2127  // if(pgenvec.at(git).TransRelSize()<pgenvec.at(imin).TransRelSize());
2128  // imin = git;
2129  // }
2130  // // candidat pairs with most common events 'maxC'
2131  // git = jmin;
2132  // Int score=-1;
2133  // for(; git!=pgenvec.size(); git++){
2134  // if(git==imin) continue;
2135  // Int sharedsize = (pgenvec.at(git).Alphabet() * pgenvec.at(imin).Alphabet()).Size();
2136  // if ( sharedsize > score){
2137  // jmin = git;
2138  // score = sharedsize;
2139  // }
2140  // }
2141  // compose candidate pair
2142  imin = 0;
2143  jmin = 1;
2144 
2145  // get new private event for SParallel
2146  EventSet myevs;
2147  EventSet otherevs;
2148  git = 0;
2149  for(;git!=pgenvec.size();git++){
2150  if (git==imin || git==jmin)
2151  myevs = myevs + pgenvec.at(git).Alphabet();
2152  else
2153  otherevs = otherevs + pgenvec.at(git).Alphabet();
2154  }
2155  EventSet privateevs = myevs-otherevs;
2156 
2157  // *************** compose Gi and Gj and reinstall attributes to gij
2158  std::vector<pGenerator> newpgenvec;
2159  pGenerator gij;
2160  FairnessConstraints newfairness;
2161  PCOMPVER_VERB1("Composing automata "<<pgenvec.at(imin).Name()<<" and "<<pgenvec.at(jmin).Name());
2162  SUParallel(pgenvec.at(imin),pgenvec.at(jmin),merging,privateevs,prios,gij);
2163  pGenerator pgij = gij;
2164  pgij.Priorities(prios);
2165  newpgenvec.push_back(pgij); // the composed generator is always the first element
2166  UParallel_MergeFairness(pgenvec.at(imin), pgenvec.at(jmin),gij, merging, newfairness);
2167 
2168  newpgenvec[0].Fairness(newfairness);
2169  newpgenvec[0].LowestPriority(lowest);
2170  newpgenvec[0].HighestPriority(highest);
2171  // and retain other uncomposed automata
2172  git = 0;
2173  for(;git!=pgenvec.size();git++){
2174  if (git == imin || git == jmin) continue;
2175  newpgenvec.push_back(pgenvec.at(git)); // all other candidates are just copied to the next iteraion
2176  }
2177  pgenvec = newpgenvec;
2178  }
2179  ShapePriorities(pgenvec.at(0));
2180  pgenvec.at(0).Accessible();
2181  std::cout<<"Final state count: "<<ToStringInteger(pgenvec.at(0).Size())<<std::endl;
2182  return IsStronglyNonblocking(pgenvec.at(0));
2183 }
2184 
2185 // wrapper for no fairness constraints
2186 bool IsPNonblocking(const GeneratorVector& rGvec, const EventPriorities& rPrios) {
2187  std::vector<FairnessConstraints> dummy;
2188  return IsPFNonblocking(rGvec,rPrios,dummy);
2189 }
2190 
2191 
2192 
2193 /*
2194 ***********
2195 NEED OLD (?) VERSION DUMMIES TO COMPILE (TM 2025)
2196 ******
2197 */
2198 
2200  FD_ERR("MergeSilentLoops(): revise pev-abstraction.cpp??");
2201 }
2202 
2204  mGenHidden = mGenRaw;
2205  mGenHidden.Name(mGenRaw.Name() + "_H");
2206  EventSet msilentevs = (mGenRaw.Alphabet()*silent) - mPevs;
2207  EventSet mpsilentevs = (mGenRaw.Alphabet()*silent) * mPevs;
2208  if(msilentevs.Empty() && mpsilentevs.Empty()){
2210  mGenMerged.Name(mGenRaw.Name()+"_M");
2211  return;
2212  }
2213  Idx tau;
2214  Idx ptau;
2215  if (!msilentevs.Empty()){
2216  tau=*(msilentevs.Begin());
2217  SetTau(tau);
2218  SetSilentevs(msilentevs);
2219  msilentevs.Erase(tau); // from now on, msilentevs exclude tau
2220  }
2221  if (!mpsilentevs.Empty()){
2222  ptau = *(mpsilentevs.Begin());
2223  SetPtau(ptau);
2224  SetPSilentevs(mpsilentevs);
2225  mpsilentevs.Erase(ptau);
2226  }
2227 
2228  silent.EraseSet(msilentevs);
2229  silent.EraseSet(mpsilentevs);
2230 
2231  if (msilentevs.Empty() && mpsilentevs.Empty()){// in this case, only one 1 silent event is set to tau and no need to hide
2233  mGenMerged.Name(mGenRaw.Name()+"_M");
2234  return;
2235  }
2238  for(;tit!=tit_end;) {
2239  if(!(msilentevs+mpsilentevs).Exists(tit->Ev)) {++tit; continue;}
2240  Transition t;
2241  if (msilentevs.Exists(tit->Ev))
2242  t = Transition(tit->X1,tau,tit->X2);
2243  else
2244  t = Transition(tit->X1,ptau,tit->X2);
2245  mGenHidden.ClrTransition(tit++);
2246  if (!mGenHidden.ExistsTransition(t))
2248  }
2249  mGenHidden.InjectAlphabet(mGenHidden.Alphabet()-msilentevs-mpsilentevs);
2251  mGenMerged.Name(mGenRaw.Name()+"_M");
2252 }
2253 
2255  const EventSet &silent){
2256  FD_ERR("ObservationEquivalenceQuotient_NonPreemptive(): revise pev_abstraction.cpp??");
2257 }
2258 
2259 
2261  FD_ERR("ObservationEquivalenceQuotient_Preemptive(): revise pev_abstraction.cpp??");
2262 }
2263 
2265  FD_ERR("ConflictEquivalentAbstraction(): revise pev_abstraction.cpp??");
2266 }
2267 
2268 
2269 
2270 } // namespace faudes
#define FD_DF(message)
#define FD_ERR(message)
void OnlySilentIncoming(Generator &g, const EventSet &silent)
void BlockingSilentEvent(Generator &g, const EventSet &silent)
virtual void HidePrivateEvs(EventSet &silent)
void RemoveTauSelfloops(Generator &g, const EventSet &silent)
void SetTau(Idx tau)
void RemoveNonCoaccessibleOut(Generator &g)
void ActiveNonTauEvs(const Generator &rGen, const EventSet &silent, const Idx &state, EventSet &result)
void SetSilentevs(EventSet silentevs)
std::map< Idx, Idx > mMergeMap
void ActiveEventsANDEnabledContinuationRule(Generator &g, const EventSet &silent)
void MergeEquivalenceClasses(Generator &rGen, TransSetX2EvX1 &rRevTrans, const std::list< StateSet > &rClasses, const EventSet &silent)
virtual void MergeSilentLoops(Generator &g, const EventSet &silent)
void OnlySilentOutgoing(Generator &g, const EventSet &silent)
virtual void ConflictEquivalentAbstraction(EventSet &silent)
void BlockingEvent(Generator &g, const EventSet &silent)
void WeakObservationEquivalentQuotient(Generator &g, const EventSet &silent)
void IncomingTransSet(const Generator &rGen, const EventSet &silent, const Idx &state, std::set< std::pair< Idx, Idx >> &result)
void ReverseObservationEquivalentQuotient(Generator &g, const EventSet &silent)
void ObservationEquivalentQuotient(Generator &g, const EventSet &silent)
void ExtendedTransRel(const Generator &rGen, const EventSet &rSilentAlphabet, TransSet &rXTrans)
void MergeNonCoaccessible(Generator &g)
bool Exists(const Idx &rIndex) const
virtual void InsertSet(const NameSet &rOtherSet)
bool Insert(const Idx &rIndex)
void EraseSet(const NameSet &rOtherSet)
virtual bool Erase(const Idx &rIndex)
virtual void HidePrivateEvs(EventSet &silent)
HidePrivateEvs replace all private events.
void SetPSilentevs(EventSet psilentevs)
void SetPtau(Idx ptau)
virtual void MergeSilentLoops(Generator &g, const EventSet &silent)
virtual void ConflictEquivalentAbstraction(EventSet &silent)
void ObservationEquivalenceQuotient_NonPreemptive(Generator &g, const EventSet &silent)
void ObservationEquivalenceQuotient_Preemptive(Generator &g, const EventSet &silent, const bool &flag)
std::vector< int >::size_type Position
virtual const T & At(const Position &pos) const
Iterator Begin(void) const
Iterator End(void) const
bool Exists(const Transition &t) const
Iterator BeginByX2(Idx x2) const
bool Insert(const Transition &rTransition)
Iterator EndByX2(Idx x2) const
bool Erase(const Transition &t)
void RestrictEvents(const EventSet &rEventSet)
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
void ReSort(TTransSet< OtherCmp > &res) const
GlobalAttr * GlobalAttributep(void)
void EventAttribute(Idx index, const EventAttr &rAttr)
EventAttr * EventAttributep(Idx index)
bool InsEvent(Idx index)
const TaStateSet< StateAttr > & States(void) const
const TaEventSet< EventAttr > & Alphabet(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
void InjectTransRel(const TransSet &rNewtransrel)
const ATransSet & TransRel(void) const
void GlobalAttribute(const GlobalAttr &rAttr)
Idx Priority(const std::string &rName) const
Idx LowestPriority(void) const
Idx HighestPriority(void) const
void InsPriority(const Idx idx, const Idx prio)
Idx Priority(const Idx index) const
void Priorities(const TpEventSet< EventAttr > &rOtherSet)
Idx LowestPriority(void) const
Idx HighestPriority(void) const
bool Empty(void) const
virtual void Erase(const Position &pos)
virtual void Append(const Type &rElem)
Idx Size(void) const
StateSet::Iterator StatesBegin(void) const
StateSet::Iterator InitStatesBegin(void) const
const TransSet & TransRel(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
EventSet ActiveEventSet(Idx x1) const
void DelEvents(const EventSet &rEvents)
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
void ClrTransition(Idx x1, Idx ev, Idx x2)
void InsEvents(const EventSet &events)
void ClrMarkedState(Idx index)
EventSet::Iterator AlphabetBegin(void) const
StateSet BlockingStates(void) const
void ClearMarkedStates(void)
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
void SetInitState(Idx index)
void InsStates(const StateSet &rStates)
StateSet::Iterator MarkedStatesBegin(void) const
void Name(const std::string &rName)
bool DelState(Idx index)
StateSet::Iterator StatesEnd(void) const
void DelStates(const StateSet &rDelStates)
TransSet::Iterator TransRelEnd(void) const
StateSet::Iterator MarkedStatesEnd(void) const
void InjectTransRel(const TransSet &rNewtransrel)
void SetMarkedState(Idx index)
bool InsEvent(Idx index)
StateSet::Iterator InitStatesEnd(void) const
void SetDefaultStateNames(void)
Idx TransRelSize(void) const
std::string EventName(Idx index) const
EventSet::Iterator AlphabetEnd(void) const
StateSet CoaccessibleSet(void) const
Idx Size(void) const
bool ExistsInitState(Idx index) const
bool ExistsMarkedState(Idx index) const
const StateSet & States(void) const
void InjectAlphabet(const EventSet &rNewalphabet)
bool Empty(void) const
Definition: cfl_baseset.h:1841
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2132
virtual void Clear(void)
Definition: cfl_baseset.h:1919
Iterator End(void) const
Definition: cfl_baseset.h:1913
virtual void InsertSet(const TBaseSet &rOtherSet)
Definition: cfl_baseset.h:2004
Iterator Begin(void) const
Definition: cfl_baseset.h:1908
virtual bool Erase(const T &rElem)
Definition: cfl_baseset.h:2036
Idx Size(void) const
Definition: cfl_baseset.h:1836
void ComputeBisimulation(const Generator &rGenOrig, map< Idx, Idx > &rMapStateToPartition)
bool ComputeScc(const Generator &rGen, const SccFilter &rFilter, std::list< StateSet > &rSccList, StateSet &rRoots)
void ShapePriorities(vGenerator &rGen, const EventPriorities &rPrios)
void ShapePreemption(Generator &rGen, const EventSet &pevs)
bool IsPFNonblocking(const GeneratorVector &rGvec, const EventPriorities &rPrios, const std::vector< FairnessConstraints > &rFairVec)
bool IsPNonblocking(const GeneratorVector &rGvec, const EventPriorities &rPrios)
uint32_t Idx
void BlockingSilentEvent(Generator &g, const EventSet &silent)
std::map< std::pair< Idx, Idx >, EventSet > IncTransSet
void IncomingTransSet(const Generator &rGen, const TransSetX2EvX1 &rRTrans, const EventSet &silent, const Idx &state, SetX1Ev &result)
EventSet NonsilHigherThen(const pGenerator &rPGen, const EventSet &rSilent, const Idx &rState, const Idx &rK)
void UParallel_MergeFairness(const pGenerator &rPGen1, const pGenerator &rPGen2, const Generator &rGen12, const EventSet &rMerge, FairnessConstraints &rFairRes)
void AppendOmegaTermination(Generator &rGen)
void OnlySilentIncoming(Generator &g, const EventSet &silent)
StateSet StronglyCoaccessibleSet(const pGenerator &rPGen)
void RemoveNonCoaccessibleOut(Generator &g)
void WritePrio(const pGenerator &rPGen)
bool IsHideable(const pGenerator &rPGen, const EventSet &rSilent, const Transition &rTrans)
void MergeEquivalenceClasses(Generator &rGen, TransSetX2EvX1 &rRevTrans, const std::list< StateSet > &rClasses)
void OnlySilentOutgoing(Generator &g, const EventSet &silent)
Idx SilentEvAtPrio(const pGenerator &rPGen, const EventSet &rSilent, const Idx &rK)
bool IsNonblocking(const GeneratorVector &rGvec)
std::map< SetX1Ev, StateSet > IncomingEquivalentClasses(const Generator &rGen, const EventSet &silent)
void SaturatePWB(const pGenerator &rPGen, const EventSet &rSilent, pGenerator &rResult)
void PrintEqclasses(const std::list< StateSet > &rEqclasses)
void ShapeUpsilon(vGenerator &rGen, const EventPriorities &rPrios, const EventSet &rUpsilon)
void PrintEventTable(const pGenerator &rPGen)
EventSet HidePrivateEvs(pGenerator &rPGen, EventSet &rPrivate, EventPriorities &rPrios, Idx &rTau, const EventSet *pUnHideable=nullptr)
void MergeAESC(pGenerator &rPGen, const EventSet &rSilent)
void SUParallel(const pGenerator &rPGen1, const pGenerator &rPGen2, std::map< std::pair< Idx, Idx >, Idx > &rCompositionMap, EventSet &rMerge, const EventSet &rPrivate, EventPriorities &rPrios, pGenerator &rPRes)
void PConflictPreservingAbstraction(pGenerator &rPGen, const EventSet &rSilent)
void RemoveRedSilentSelfloops(pGenerator &rPGen, const EventSet &rSilent)
void ComputeBisimulationCTA(const Generator &rGen, std::list< StateSet > &rResult)
ComputeBisimulationCTA basic bisimulation partition algorithm based on change-tracking algorithm.
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
void MergePWB(pGenerator &rPGen, const EventSet &rSilent)
void AESCClasses(const pGenerator &rPGen, const EventSet &rSilent, std::list< StateSet > &rResult)
bool IsStronglyNonblocking(const pGenerator &rPGen)
void BlockingEvent(pGenerator &rPGen, const EventSet &rSilent)
void RedundantSilentStep(pGenerator &rPGen, const EventSet &rSilent)
void DetectLiveLocks(const pGenerator &rPGen, const EventSet &rSilent, std::map< StateSet, Idx > &rResult)
void SaturateLowestPrio(const pGenerator &rPGen, const EventSet &rSilent, pGenerator &rResult)
void MergeFairness(const pGenerator &rPGen1, const pGenerator &rPGen2, FairnessConstraints &rFairRes)
long int Int
void MergeNonCoaccessible(Generator &g)
void SaturatePDelayed(const pGenerator &rPGen, const EventSet &rSilent, const bool &_mode, pGenerator &rResult)
#define PCOMPVER_VERB1(msg)

libFAUDES 2.33b --- 2025.05.07 --- c++ api documentaion by doxygen