cfl_conflequiv.cpp
Go to the documentation of this file.
1 /** @file cfl_conflequiv.cpp
2 
3 Abstractions that maintaine conflict-equivalence.
4 
5 */
6 
7 /* FAU Discrete Event Systems Library (libfaudes)
8 
9 Copyright (C) 2015 Michael Meyer and Thomnas Moor.
10 Exclusive copyright is granted to Klaus Schmidt
11 
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2.1 of the License, or (at your option) any later version.
16 
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21 
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
25 
26 
27 #include "cfl_conflequiv.h"
28 #include "cfl_bisimulation.h"
29 #include "cfl_graphfncts.h"
30 #include "cfl_parallel.h"
31 #include "cfl_regular.h"
32 
33 
34 /*
35 The functions in this file implement automata transformations
36 as proposed by Malik R and Flordal H in "Compositional verification in supervisory
37 control", SIAM Journal of Control and Optimization, 2009. The implementation at hand
38 is based on the Bachelor Thesis Project of Michael Meyer, Friedrich-Alexander Universitaet
39 Erlangen-Nuernberg, 2015.
40 
41 The current status is still experimental. The individual rules are implemented,
42 for further testing and optimisation. The code so far does not use
43 any advanced heuristics to apply the transformations is a strategic order.
44 */
45 
46 
47 namespace faudes {
48 
49 
50 // Merge equivalent classes, i.e. perform quotient abstraction
51 // (this implementation works fine with a small amount of small equiv classes)
53  Generator& rGen,
54  TransSetX2EvX1& rRevTrans,
55  const std::list< StateSet >& rClasses
56 )
57 {
58  // iterators
59  StateSet::Iterator sit;
60  StateSet::Iterator sit_end;
64  TransSet::Iterator tit_end;
65  // record for delayed delete
66  StateSet delstates;
67  // iterate classes
68  std::list< StateSet >::const_iterator qit=rClasses.begin();
69  for(;qit!=rClasses.end();++qit) {
70  sit=qit->Begin();
71  sit_end=qit->End();
72  Idx q1=*(sit++);
73  for(;sit!=sit_end;++sit){
74  Idx q2=*sit;
75  // merge outgoing transitions form q2 to q1
76  tit = rGen.TransRelBegin(q2);
77  tit_end = rGen.TransRelEnd(q2);
78  for(;tit!=tit_end;++tit) {
79  rGen.SetTransition(q1,tit->Ev,tit->X2);
80  rRevTrans.Insert(q1,tit->Ev,tit->X2);
81  }
82  // merge incomming transitions form q2 to q1
83  rit = rRevTrans.BeginByX2(q2);
84  rit_end = rRevTrans.EndByX2(q2);
85  for(;rit!=rit_end;++rit) {
86  rGen.SetTransition(rit->X1,rit->Ev,q1);
87  rRevTrans.Insert(rit->X1,rit->Ev,q1);
88  }
89  // fix marking: if q2 was not marked, need to un-mark q1 (original by Michael Meyer)
90  //if(!(rGen.ExistsMarkedState(q2)))
91  // rGen.ClrMarkedState(q1);
92  // fix marking: if q2 was marked, so becomes q1 (quatient by the books)
93  if(rGen.ExistsMarkedState(q2))
94  rGen.InsMarkedState(q1);
95  // fix initial states: if q2 was initial, so becomes q1
96  if((rGen.ExistsInitState(q2)))
97  rGen.InsInitState(q1);
98  // log for delete
99  delstates.Insert(q2);
100  }
101  }
102  // do delete
103  rGen.DelStates(delstates);
104  // optional: delete stes in rec transrel --- otherwise it is now invalid
105 }
106 
107 
108 
109 // Compute extended transition relation '=>', i.e. relate each two states that
110 // can be reached by one non-slilent event and an arbitrary amount of silent
111 // events befor/after the non-silent event
112 //
113 // Note: currently all silent events are treated equivalent, as if they
114 // had been substituted by a single silent event "tau"; we should perform
115 // this substitution beforehand.
116 // Note: the below fixpoint iteration is simple but perhaps suboptimal; can a
117 // todostack perform better? See also the varuious implementations of ProjectNonDet
118 
119 void ExtendedTransRel(const Generator& rGen, const EventSet& rSilentAlphabet, TransSet& rXTrans) {
120 
121  // HELPERS:
122  TransSet::Iterator tit1;
123  TransSet::Iterator tit1_end;
124  TransSet::Iterator tit2;
125  TransSet::Iterator tit2_end;
126  TransSet newtrans;
127 
128  // initialize result with original transitionrelation
129  rXTrans=rGen.TransRel();
130  // loop for fixpoint
131  while(true) {
132  // accumulate new transitions
133  newtrans.Clear();
134  // loop over all transitions
135  tit1=rXTrans.Begin();
136  tit1_end=rXTrans.End();
137  for(;tit1!=tit1_end; ++tit1) {
138  // if it is silent add transition to successor directly
139  if(rSilentAlphabet.Exists(tit1->Ev)) {
140  tit2=rXTrans.Begin(tit1->X2);
141  tit2_end=rXTrans.End(tit1->X2);
142  for(;tit2!=tit2_end; ++tit2) {
143  newtrans.Insert(tit1->X1,tit2->Ev,tit2->X2);
144  }
145  }
146  // if it is not silent add transition to silent successor directly
147  else {
148  tit2=rXTrans.Begin(tit1->X2);
149  tit2_end=rXTrans.End(tit1->X2);
150  for(;tit2!=tit2_end; ++tit2) {
151  if(rSilentAlphabet.Exists(tit2->Ev))
152  newtrans.Insert(tit1->X1,tit1->Ev,tit2->X2);
153  }
154  }
155  }
156  // insert new transitions, break on fixpoint
157  Idx tsz=rXTrans.Size();
158  rXTrans.InsertSet(newtrans);
159  if(tsz==rXTrans.Size()) break;
160  }
161 }
162 
163 
164 // Performs observation equivalent abstraction; see cited literature 3.1
165 // Note: do we need to implement the test on the initial states?
167  FD_DF("ObservationEquivalentQuotient(): prepare for t#"<<g.TransRelSize());
168 
169  // have extendend/reverse-ordered transition relations
170  TransSetX2EvX1 rtrans;
171  g.TransRel().ReSort(rtrans);
172  TransSet xtrans;
173  ExtendedTransRel(g,silent,xtrans);
174  FD_DF("ObservationEquivalentQuotient(): ext. trans t#"<<xtrans.Size());
175 
176  // remove silent events from extended transition relation
177  xtrans.RestrictEvents(g.Alphabet()-silent);
178 
179  // figure observation equivalent states
180  std::list< StateSet > eqclasses;
181  Generator xg(g);
182  xg.InjectTransRel(xtrans);
183  calcBisimulation(xg,eqclasses);
184 
185  // merge classes
186  FD_DF("ObservationEquivalentQuotient(): merging classes #"<< eqclasses.size());
187  MergeEquivalenceClasses(g,rtrans,eqclasses);
188 
189  FD_DF("ObservationEquivalentQuotient(): done with t#"<<g.TransRelSize());
190 }
191 
192 
193 
194 // Test for incoming equivalence '=_inc' based on reverse ext. transition relation
196  const TransSetX2EvX1& rRevXTrans,
197  const EventSet& rSilent,
198  const StateSet& rInitialStates,
199  Idx q1, Idx q2)
200 {
202  TransSetX2EvX1::Iterator rit1_end;
204  TransSetX2EvX1::Iterator rit2_end;
205  bool nonsilent=true;
206  // condition 1: is reached from same state by the same std event
207  rit1=rRevXTrans.BeginByX2(q1);
208  rit1_end=rRevXTrans.EndByX2(q1);
209  rit2=rRevXTrans.BeginByX2(q2);
210  rit2_end=rRevXTrans.EndByX2(q2);
211  while(true) {
212  // skip silent
213  for(;rit1!=rit1_end;++rit1) if(!rSilent.Exists(rit1->Ev)) break;
214  for(;rit2!=rit2_end;++rit2) if(!rSilent.Exists(rit2->Ev)) break;
215  // sense end of loop
216  if(rit1==rit1_end) break;
217  if(rit2==rit2_end) break;
218  // mismatch
219  if(rit1->X1!=rit2->X1) return false;
220  if(rit1->Ev!=rit2->Ev) return false;
221  nonsilent=true;
222  // increment
223  ++rit1;
224  ++rit2;
225  }
226  // skip silent
227  for(;rit1!=rit1_end;++rit1) if(!rSilent.Exists(rit1->Ev)) break;
228  for(;rit2!=rit2_end;++rit2) if(!rSilent.Exists(rit2->Ev)) break;
229  if(rit1!=rit1_end) return false;
230  if(rit2!=rit2_end) return false;
231  // condition 2: both or neither can be silently reached from an initial state
233  TransSetX2EvX1::Iterator rit_end;
234  bool ini1=rInitialStates.Exists(q1);
235  if(!ini1) {
236  rit=rRevXTrans.BeginByX2(q1);
237  rit_end=rRevXTrans.EndByX2(q1);
238  for(;rit!=rit_end;++rit) {
239  if(!rSilent.Exists(rit->Ev)) continue;
240  if(rInitialStates.Exists(rit->X1)) {ini1=true; break;}
241  }
242  }
243  bool ini2=rInitialStates.Exists(q2);
244  if(!ini2) {
245  rit=rRevXTrans.BeginByX2(q2);
246  rit_end=rRevXTrans.EndByX2(q2);
247  for(;rit!=rit_end;++rit) {
248  if(!rSilent.Exists(rit->Ev)) continue;
249  if(rInitialStates.Exists(rit->X1)) {ini2=true; break;}
250  }
251  }
252  if(ini1!=ini2) return false;
253  // condition 3: if all incomming are silent, must be reachable from initial state (redundant)
254  if(!nonsilent && !ini1) return false;
255  // all tests passt
256  //FD_DF("IE PASSED");
257  return true;
258 }
259 
260 // Candidates for incomming equivalent states '=_inc'
261 // (this is meant as a filter in iterations)
263  const TransSet& rXTrans,
264  const TransSetX2EvX1& rRevXTrans,
265  const EventSet& rSilent,
266  const StateSet& rInitialStates,
267  Idx q1,
268  StateSet& rRes)
269 {
270  // iterators
272  TransSetX2EvX1::Iterator rit_end;
273  TransSet::Iterator tit;
274  TransSet::Iterator tit_end;
275  // prepare result
276  rRes.Clear();
277  // std case: one back and one forth via matching non-silent event
278  bool stdcand=false;
279  rit = rRevXTrans.BeginByX2(q1);
280  rit_end = rRevXTrans.EndByX2(q1);
281  for(;rit!=rit_end;++rit) {
282  if(rSilent.Exists(rit->Ev)) continue;
283  stdcand=true;
284  tit = rXTrans.Begin(rit->X1,rit->Ev);
285  tit_end = rXTrans.End(rit->X1,rit->Ev);
286  for(;tit!=tit_end;++tit)
287  rRes.Insert(tit->X2);
288  }
289  // bail out if the std condition could be applied
290  if(stdcand) return;
291  // only reachable via silent events from initial state
292  rit = rRevXTrans.BeginByX2(q1);
293  rit_end = rRevXTrans.EndByX2(q1);
294  for(;rit!=rit_end;++rit) {
295  //if(!rSilent.Exists(tit->Ev)) continue; // all silent anyway
296  rRes.Insert(rit->X1);
297  }
298  tit = rXTrans.Begin(q1);
299  tit_end = rXTrans.End(q1);
300  for(;tit!=tit_end;++tit) {
301  if(!rSilent.Exists(tit->Ev)) continue;
302  rRes.Insert(tit->X2);
303  }
304 }
305 
306 
307 
308 
309 
310 // Active events rule; see cited literature 3.2.1
311 // Note: this is a re-write of Michael Meyer's implementation to refer to the
312 // ext. transistion relation, as indicated by the literature.
313 void ActiveEventsRule(Generator& g, const EventSet& silent){
314  FD_DF("ActiveEventsRule(): prepare for t#"<<g.TransRelSize());
315 
316  // iterators
317  StateSet::Iterator sit1;
318  StateSet::Iterator sit1_end;
319  StateSet::Iterator sit2;
320  StateSet::Iterator sit2_end;
321  TransSet::Iterator tit;
322  TransSet::Iterator tit_end;
323  EventSet::Iterator eit;
324  EventSet::Iterator eit_end;
325 
326 
327  // have extendend/reverse-order transition relations
328  TransSetX2EvX1 rtrans;
329  g.TransRel().ReSort(rtrans);
330  TransSet xtrans;
331  ExtendedTransRel(g,silent,xtrans);
332  TransSetX2EvX1 rxtrans;
333  xtrans.ReSort(rxtrans);
334  FD_DF("ActiveEventsRule: ext. trans t#"<<xtrans.Size());
335 
336  // record equivalent states
337  std::list< StateSet > eqclasses;
338  StateSet eqclass;
339 
340  // inner loop variables
341  StateSet candidates;
342  EventSet active1;
343 
344  // iterate pairs of states
345  StateSet states=g.States() - g.InitStates(); // todo: deal with initial states
346  sit1=states.Begin();
347  sit1_end=states.End();
348  for(;sit1!=sit1_end;++sit1) {
349 
350  // find candidates for incoming equivalence
351  IncomingEquivalentCandidates(xtrans,rxtrans,silent,g.InitStates(),*sit1,candidates);
352 
353  // q1 active events
354  active1=xtrans.ActiveEvents(*sit1) - silent;
355  // prepare set of equivalent states
356  eqclass.Clear();
357 
358  // iterate candidates
359  sit2=candidates.Begin();
360  sit2_end=candidates.End();
361  for(;sit2!=sit2_end;++sit2){
362  // skip restriction/dealt with
363  if(!states.Exists(*sit2)) continue;
364  // skip doublets
365  if(*sit2<=*sit1) continue;
366  //FD_DF("ActiveEventsRule: test "<< *sit1 << " with " << *sit2 );
367  // insist in active standard events to match
368  if(! ( active1 == xtrans.ActiveEvents(*sit2) - silent ) ) continue;
369 
370  /*
371  // alternative implementation: makes no difference
372  tit=xtrans.Begin(*sit2);
373  tit_end=xtrans.End(*sit2);
374  eit=active1.Begin();
375  eit_end=active1.End();
376  while(true) {
377  // skip silent
378  for(;tit!=tit_end;++tit) { if(!silent.Exists(tit->Ev)) break;}
379  if(tit==tit_end) break;
380  // sense mismatch
381  if(tit->Ev != *eit) break;
382  // increment
383  ++tit;
384  ++eit;
385  // sense end of loop
386  if(tit==tit_end) break;
387  if(eit==eit_end) break;
388  }
389  for(;tit!=tit_end;++tit) { if(!silent.Exists(tit->Ev)) break;}
390  if(eit!=eit_end) continue;
391  if(tit!=tit_end) continue;
392  */
393 
394  // insist in active events to match, incl w-event, i.e. marking (not needed?)
395  //if(! ( g.ExistsMarkedState(*sit1) == g.ExistsMarkedState(*sit2) ))
396  // continue;
397  //FD_DF("ActiveEventsRule: a-match "<< *sit1 << " with " << *sit2 );
398  // test incomming equivalence
399  if(! IsIncomingEquivalent(rxtrans,silent,g.InitStates(),*sit1,*sit2))
400  continue;
401  //FD_DF("ActiveEventsRule: record merge "<< *sit1 << " with " << *sit2 );
402  eqclass.Insert(*sit2);
403  states.Erase(*sit2);
404  }
405  // record non-trivial equaivalence class
406  if(eqclass.Size()>0){
407  eqclass.Insert(*sit1);
408  eqclasses.push_back(eqclass);
409  }
410 
411  } // end: loop pais of states
412 
413  // iterate over all classes of equivalent states and merge
414  FD_DF("ActiveEventsRule: merging classes #"<< eqclasses.size());
415  MergeEquivalenceClasses(g,rtrans,eqclasses);
416 
417  FD_DF("ActiveEventsRule: done with t#"<<g.TransRelSize());
418 }
419 
420 
421 // Silent continuation rule; see cited literature 3.2.2
422 // Note: this is a rewrite of Michael Meyer's implementation to refer to the
423 // ext. transistion relation, as indicated by the literature.
424 // Note: assumes that silent SCCs have been eliminated before; see lit. Corollary 1, and MergeSilentSccs()
425 void SilentContinuationRule(Generator& g, const EventSet& silent){
426  FD_DF("SilentContinuationRule(): prepare for t#"<<g.TransRelSize());
427 
428  // iterators
429  StateSet::Iterator sit1;
430  StateSet::Iterator sit1_end;
431  StateSet::Iterator sit2;
432  StateSet::Iterator sit2_end;
433 
434  // have extendend/reverse-ordered transition relations
435  TransSet xtrans;
436  TransSetX2EvX1 rxtrans;
437  TransSetX2EvX1 rtrans;
438  ExtendedTransRel(g,silent,xtrans);
439  xtrans.ReSort(rxtrans);
440  g.TransRel().ReSort(rtrans);
441 
442  // record equivalent states
443  std::list< StateSet > eqclasses;
444  StateSet eqclass;
445 
446  // loop variables
447  StateSet candidates;
448 
449  // iterate pairs of states
450  StateSet states=g.States() - g.InitStates(); // todo: deal with initial states
451  sit1=states.Begin();
452  sit1_end=states.End();
453  for(;sit1!=sit1_end;++sit1) {
454 
455  // must have at least one silent event enabled
456  if((g.ActiveEventSet(*sit1)*silent).Size()==0) continue;
457 
458  // find candidates for incoming equivalence
459  IncomingEquivalentCandidates(xtrans,rxtrans,silent,g.InitStates(),*sit1,candidates);
460  if(candidates.Empty()) continue;
461 
462  // iterate candidates
463  eqclass.Clear();
464  sit2=candidates.Begin();
465  sit2_end=candidates.End();
466  for(;sit2!=sit2_end;++sit2){
467  // skip restriction/dealt with
468  if(!states.Exists(*sit2)) continue;
469  // skip doublets
470  if(*sit2<=*sit1) continue;
471 
472  // must have at least one silent event enabled
473  if((g.ActiveEventSet(*sit2)*silent).Size()<=0)
474  continue;
475 
476  //FD_DF("SilentContinuationRule: test "<< *sit1 << " with " << *sit2 );
477 
478  // test incoming equivalence
479  if(! IsIncomingEquivalent(rxtrans,silent,g.InitStates(),*sit1,*sit2))
480  continue;
481  // record to merge
482  //FD_DF("SilentContuationRule: record to merge "<< *sit1 << " with " << *sit2 );
483  eqclass.Insert(*sit2);
484  states.Erase(*sit2);
485  }
486 
487  // record equaivalent states
488  if(eqclass.Size()>0){
489  eqclass.Insert(*sit1);
490  eqclasses.push_back(eqclass);
491  }
492 
493  } // end: loop pais of states
494 
495  // iterate over all classes of equivalent states and merge
496  FD_DF("SilentContinuationRule(): merging classes #"<< eqclasses.size());
497  MergeEquivalenceClasses(g,rtrans,eqclasses);
498 
499  FD_DF("SilentContinuationRule(): done with t#"<<g.TransRelSize());
500 }
501 
502 
503 // Represent each silent SCC by one state and remove respective silent events.
504 // This transformation is observation equivalent and, hence, conflict equivalent (reference [19] in cited literature)
505 // The current implementation is based on Michael Meyer's with some additional performance considerations.
506 void MergeSilentSccs(Generator& g, const EventSet& silent){
507  FD_DF("MergeSilentSccs(): prepare for t#"<<g.TransRelSize());
508  StateSet delstates;
509  TransSet::Iterator tit;
510  TransSet::Iterator tit_end;
511  StateSet::Iterator sit;
512  StateSet::Iterator sit_end;
513  // remove silent selfloops
514  tit=g.TransRelBegin();
515  tit_end=g.TransRelEnd();
516  for(;tit!=tit_end;){
517  if(tit->X1 == tit->X2)
518  if(silent.Exists(tit->Ev)) {
519  g.ClrTransition(tit++);
520  continue;
521  }
522  ++tit;
523  }
524  // find silent SCCs
525  EventSet avoid=g.Alphabet()-silent;
527  StateSet sccroots;
528  std::list< StateSet > scclist;
529  ComputeScc(g,filter,scclist,sccroots);
530  // set up state rename map
531  std::map< Idx , Idx > sccxmap;
532  while(!scclist.empty()) {
533  const StateSet& scc=scclist.front();
534  if(scc.Size()<=1) { scclist.pop_front(); continue;}
535  // have new state to represent scc
536  Idx newSt = g.InsState();
537  // set marking status
538  if( (scc * g.MarkedStates()).Size()>0 )
539  g.SetMarkedState(newSt);
540  // set initial status
541  if( (scc * g.InitStates()).Size()>0 )
542  g.SetInitState(newSt);
543  // add to map
544  sit=scc.Begin();
545  sit_end=scc.End();
546  for(;sit!=sit_end;++sit)
547  sccxmap[*sit]=newSt;
548  // add to delstates
549  delstates.InsertSet(scc);
550  //remove from list
551  scclist.pop_front();
552  }
553  // apply substitution
554  if(sccxmap.size()>0){
555  std::map<Idx,Idx>::iterator xit1;
556  std::map<Idx,Idx>::iterator xit2;
557  tit=g.TransRelBegin();
558  while(tit!=g.TransRelEnd()) {
559  Transition t= *tit;
560  g.ClrTransition(tit++);
561  xit1=sccxmap.find(t.X1);
562  xit2=sccxmap.find(t.X2);
563  if(xit1!=sccxmap.end()) t.X1=xit1->second;
564  if(xit2!=sccxmap.end()) t.X2=xit2->second;
565  g.SetTransition(t);
566  }
567  }
568  // delete scc states
569  g.DelStates(delstates);
570  FD_DF("MergeSilentSccs(): done with t#"<<g.TransRelSize());
571 }
572 
573 
574 // Certain conflicts. see cited literature 3.2.3
575 // -- remove outgoing transitions from not coaccessible states
577  StateSet notcoaccSet=g.States()-g.CoaccessibleSet();
578  StateSet::Iterator sit=notcoaccSet.Begin();
579  StateSet::Iterator sit_end=notcoaccSet.End();
580  for(;sit!=sit_end;++sit){
582  TransSetX1EvX2::Iterator tit_end=g.TransRelEnd(*sit);
583  for(;tit!=tit_end;) g.ClrTransition(tit++);
584  //FD_DF("RemoveCertainConflictA: remove outgoing from state "<<*sit);
585  }
586 }
587 
588 
589 
590 // Certain conflicts. see cited literature 3.2.3
591 // -- remove outgoing transitions from states that block by a silent event
592 void BlockingSilentEvent(Generator& g,const EventSet& silent){
593  FD_DF("BlockingSilentEvent(): prepare for t#"<<g.TransRelSize());
594  StateSet coacc=g.CoaccessibleSet();
595  StateSet sblock;
596  TransSet::Iterator tit;
597  TransSet::Iterator tit_end;
598  StateSet::Iterator sit;
599  StateSet::Iterator sit_end;
600  // loop all transitions to figure certain blocking states
601  tit=g.TransRelBegin();
602  tit_end=g.TransRelEnd();
603  for(;tit!=tit_end;++tit) {
604  if(silent.Exists(tit->Ev))
605  if(!coacc.Exists(tit->X2))
606  sblock.Insert(tit->X1);
607  }
608  // unmark blocking states and eliminate possible future
609  sit=sblock.Begin();
610  sit_end=sblock.End();
611  for(;sit!=sit_end;++sit) {
612  g.ClrMarkedState(*sit);
613  tit=g.TransRelBegin(*sit);
614  tit_end=g.TransRelEnd(*sit);
615  for(;tit!=tit_end;)
616  g.ClrTransition(tit++);
617  }
618  FD_DF("BlockingSilentEvent(): done with t#"<<g.TransRelSize());
619 }
620 
621 
622 
623 // Certain conflicts. see cited literature 3.2.3
624 // -- merge all states that block to one representative
626  StateSet notcoacc=g.States()-g.CoaccessibleSet();
627  // bail out on trovial case
628  if(notcoacc.Size()<2) return;
629  // have a new state
630  Idx qnc=g.InsState();
631  // fix init status
632  if((notcoacc * g.InitStates()).Size()>0)
633  g.SetInitState(qnc);
634  // fix transitions
636  TransSet::Iterator tit_end=g.TransRelEnd();
637  for(;tit!=tit_end;++tit){
638  if(notcoacc.Exists(tit->X2))
639  g.SetTransition(tit->X1,tit->Ev,qnc);
640  }
641  // delete original not coacc
642  g.DelStates(notcoacc);
643 }
644 
645 // Certain conflicts. see cited literature 3.2.3
646 // -- if a transition blocks, remove all transitions from the same state with the same label
647 void BlockingEvent(Generator& g,const EventSet& silent){
648  FD_DF("BlockingEvent(): prepare for t#"<<g.TransRelSize());
649  StateSet coacc=g.CoaccessibleSet();
650  TransSet::Iterator tit;
651  TransSet::Iterator tit_end;
652  TransSet::Iterator dit;
653  TransSet::Iterator dit_end;
654  TransSet deltrans;
655  // loop all transitions to figure transitions to blocking states
656  tit=g.TransRelBegin();
657  tit_end=g.TransRelEnd();
658  for(;tit!=tit_end;++tit) {
659  // silent events are treated by a separat rule;
660  if(silent.Exists(tit->Ev)) continue;
661  // look for transitions that block
662  if(coacc.Exists(tit->X1)) continue;
663  if(coacc.Exists(tit->X2)) continue;
664  // consider all transitions with the same event to block
665  dit=g.TransRelBegin(tit->X1,tit->Ev);
666  dit_end=g.TransRelEnd(tit->X1,tit->Ev);
667  for(;dit!=dit_end;++dit) {
668  // keep selfloops (Michael Meyer)
669  if(dit->X1==dit->X2) continue;
670  // rcord to delete later
671  deltrans.Insert(*dit);
672  }
673  }
674  // delete transitions
675  dit=deltrans.Begin();
676  dit_end=deltrans.End();
677  for(;dit!=dit_end;++dit)
678  g.ClrTransition(*dit);
679  FD_DF("BlockingEvent(): done with t#"<<g.TransRelSize());
680 }
681 
682 
683 
684 // Only silent incomming rule; see cited literature 3.2.4
685 // Note: input generator must be silent-SCC-free
686 // Note: this is a complete re-write and needs testing for more than one candidates
687 void OnlySilentIncoming(Generator& g, const EventSet& silent){
688  FD_DF("OnlySilentIncoming(): prepare with t#"<<g.TransRelSize());
689 
690  TransSet::Iterator tit;
691  TransSet::Iterator tit_end;
692  TransSet::Iterator dit;
693  TransSet::Iterator dit_end;
694  StateSet::Iterator sit;
695  StateSet::Iterator sit_end;
696 
697  // figure states with only silent incomming transitions
698  // note: Michael Meyer proposed to only consider states with at least two incomming
699  // events -- this was dropped in the re-write
700  StateSet cand1=g.States()-g.InitStates();
701  tit=g.TransRelBegin();
702  tit_end=g.TransRelEnd();
703  for(;tit!=tit_end;++tit)
704  if(!silent.Exists(tit->Ev)) cand1.Erase(tit->X2);
705 
706  // bail out on trivial
707  if(cand1.Size()==0) return;
708 
709  // restrict candidates to have at least one silent outgoing transition
710  StateSet cand2;
711  sit=cand1.Begin();
712  sit_end=cand1.End();
713  for(;sit!=sit_end;++sit) {
714  tit=g.TransRelBegin(*sit);
715  tit_end=g.TransRelEnd(*sit);
716  for(;tit!=tit_end;++tit) {
717  if(silent.Exists(tit->Ev)) {
718  cand2.Insert(*sit);
719  break;
720  }
721  }
722  }
723 
724  // bail out on trivial
725  if(cand2.Size()==0) return;
726 
727  // current code is not tested to handle multiple successive silent events
728  tit=g.TransRelBegin();
729  tit_end=g.TransRelEnd();
730  for(;tit!=tit_end;++tit)
731  if(cand2.Exists(tit->X1) && cand2.Exists(tit->X2)) cand2.Erase(tit->X2);
732 
733  // current code is not tested to handle more than one candidate at a time
734  //while(cand2.Size()>1) cand2.Erase(*cand2.Begin());
735 
736  // re-link outgoing transitions to predecessor
737  // note: see the attempt we did for marking? this does not work
738  // and is one reason why one insists in one silent outgoing event
739  tit=g.TransRelBegin();
740  tit_end=g.TransRelEnd();
741  for(;tit!=tit_end;++tit) {
742  if(!cand2.Exists(tit->X2)) continue;
743  //bool marked = g.ExistsMarkedState(tit->X2);
744  dit=g.TransRelBegin(tit->X2);
745  dit_end=g.TransRelEnd(tit->X2);
746  for(;dit!=dit_end;++dit) {
747  g.SetTransition(tit->X1,dit->Ev,dit->X2);
748  //if(!marked) g.ClrMarkedState(tit->X1);
749  }
750  }
751 
752  // remove candidates
753  g.DelStates(cand2);
754  FD_DF("OnlySilentIncoming(): done with t#"<<g.TransRelSize());
755 }
756 
757 
758 // Only silent outgoing rule; see cited literature 3.2.5
759 // Note: input generator must be silent-SCC-free
760 // TODO: marking
761 void OnlySilentOutgoing(Generator& g,const EventSet& silent){
762  FD_DF("OnlySilentOutgoing(): prepare for t#"<<g.TransRelSize());
763  TransSet::Iterator tit;
764  TransSet::Iterator tit_end;
765  TransSet::Iterator dit;
766  TransSet::Iterator dit_end;
767  StateSet::Iterator sit;
768  StateSet::Iterator sit_end;
769  TransSetX2EvX1 rtrans;
771  TransSetX2EvX1::Iterator rit_end;
772 
773  // figure states with only silent outgoing transitions
774  StateSet cand=g.States() - g.InitStates();
775  tit=g.TransRelBegin();
776  tit_end=g.TransRelEnd();
777  for(;tit!=tit_end;++tit)
778  if(!silent.Exists(tit->Ev)) cand.Erase(tit->X1);
779 
780  // current code cannot handle multiple successive silent events
781  tit=g.TransRelBegin();
782  tit_end=g.TransRelEnd();
783  for(;tit!=tit_end;++tit)
784  if(cand.Exists(tit->X1) && cand.Exists(tit->X2)) cand.Erase(tit->X1);
785 
786  // bail out on trivial
787  if(cand.Size()==0) return;
788 
789  // can handle only one state at a time (need to re-work this)
790  //while(cand.Size()>1) cand.Erase(*cand.Begin());
791 
792 
793  // re-link outgoing transitions of predecessor
794  tit=g.TransRelBegin();
795  tit_end=g.TransRelEnd();
796  for(;tit!=tit_end;++tit) {
797  if(!cand.Exists(tit->X2)) continue;
798  dit=g.TransRelBegin(tit->X2);
799  dit_end=g.TransRelEnd(tit->X2);
800  if(dit==dit_end) cand.Erase(tit->X2); // no outgoing trans at all
801  for(;dit!=dit_end;++dit)
802  g.SetTransition(tit->X1,tit->Ev,dit->X2);
803  }
804 
805  // fix initial states
806  sit=cand.Begin();
807  sit_end=cand.End();
808  for(;sit!=sit_end;++sit)
809  if(g.ExistsInitState(*sit))
810  g.InsInitStates(g.SuccessorStates(*sit));
811 
812  // remove candidates
813  g.DelStates(cand);
814  FD_DF("OnlySilentOutgoing(): done with t#"<<g.TransRelSize());
815 }
816 
817 
818 
819 
820 
821 // apply all of the above repeatedly until a fixpoint is attained
822 void ConflictEquivalentAbstraction(vGenerator& rGen, const EventSet& rSilentEvents){
823  FD_DF("ConflictEquivalentAbstraction(): prepare with t#"<<rGen.TransRelSize());
824  while(true) {
825  // track overall gain
826  Idx sz0=rGen.Size();
827  (void) sz0; // make compiler happy
828  // good performance operations: go for fixpoint
829  while(true) {
830  Idx sz1=rGen.Size();
831  FD_WPC(sz0, sz1, "ConflictEquivalentAbstraction: fixpoint iteration states #" << sz1);
832  MergeNonCoaccessible(rGen);
833  if(rSilentEvents.Size()>0){
834  MergeSilentSccs(rGen,rSilentEvents);
835  BlockingSilentEvent(rGen,rSilentEvents);
836  BlockingEvent(rGen,rSilentEvents);
837  OnlySilentOutgoing(rGen,rSilentEvents);
838  OnlySilentIncoming(rGen,rSilentEvents);
839  }
840  if(rGen.Size()==sz1) break;
841  }
842  // break on large automata
843  //if(rGen.TransRelSize()> 50000) break;
844  // badly performing operations: give it a try
845  Idx sz2=rGen.Size();
846  ActiveEventsRule(rGen,rSilentEvents); // can cause tau-scc
847  if(rSilentEvents.Size()>0) {
848  MergeSilentSccs(rGen,rSilentEvents);
849  SilentContinuationRule(rGen,rSilentEvents); // must not have tau-scc
850  }
851  if(rSilentEvents.Size()>0) {
852  ObservationEquivalentQuotient(rGen,rSilentEvents);
853  }
854  if(rGen.Size()==sz2) break;
855  // break on slow progress
856  //if(rGen.Size()> 1000 && rGen.Size()>0.95*sz0) break;
857  }
858  FD_DF("ConflictEquivalentAbstraction(): done with t#"<<rGen.TransRelSize());
859 }
860 
861 
862 // intentend user interface
863 bool IsNonblocking(const GeneratorVector& rGenVec) {
864  Idx i,j;
865 
866  // trivial cases
867  if(rGenVec.Size()==0) return true;
868  if(rGenVec.Size()==1) return IsNonblocking(rGenVec.At(0));
869 
870  // have a local copy of input generator
871  GeneratorVector gvec=rGenVec;
872 
873  // figure silent events
874  EventSet silent, all, shared;
875  for(i=0;i<gvec.Size()-1;++i){
876  for(j=i+1;j<gvec.Size();++j){
877  const Generator& g1=gvec.At(i);
878  const Generator& g2=gvec.At(j);
879  shared=shared+g1.Alphabet()*g2.Alphabet();
880  all=all+gvec.At(i).Alphabet();
881  }
882  }
883  silent=all-shared;
884 
885  // normalize for one silent event per generator
886  for(i=0;i<gvec.Size();++i){
887  Generator& gi=gvec.At(i);
888  EventSet sili=gi.Alphabet()*silent;
889  if(sili.Size()<=1) continue;
890  Idx esi=*(sili.Begin());
891  sili.Erase(esi);
892  silent.EraseSet(sili);
893  all.EraseSet(sili);
895  TransSet::Iterator tit_end=gi.TransRelEnd();
896  for(;tit!=tit_end;) {
897  if(!sili.Exists(tit->Ev)) {++tit; continue;}
898  Transition t(tit->X1,esi,tit->X2);
899  gi.ClrTransition(tit++);
900  gi.SetTransition(t);
901  }
902  gi.InjectAlphabet(gi.Alphabet()-sili);
903  }
904 
905  // reduce all generators
906  for(i=0;i<gvec.Size();i++){
907  Generator& g=gvec.At(i);
908  FD_DF("Abstract generator " << g.Name());
909  FD_DF("Silent events #" << (g.Alphabet()*silent).Size());
911  if(g.InitStates().Size()>0)
912  if(g.MarkedStates().Size()==0){
913  FD_DF("No marked states (A)");
914  return false;
915  }
916  }
917 
918  // loop until resolved
919  while(gvec.Size()>=2) {
920 
921  // candidat pairs with fewest transitions 'minT'
922  Idx imin=0;
923  for(i=1;i<gvec.Size();i++){
924  if(gvec.At(i).TransRelSize()<gvec.At(imin).TransRelSize())
925  imin=i;
926  }
927 
928  // candidat pairs with most local events 'maxL'
929  Idx jmin=0;
930  Int score=-1;
931  for(i=0;i<gvec.Size();i++){
932  if(i==imin) continue;
933  const Generator& gi=gvec.At(imin);
934  const Generator& gj=gvec.At(i);
935  EventSet aij=gi.Alphabet()+gj.Alphabet();
936  EventSet shared;
937  for(j=0;j<gvec.Size();j++){
938  if(j==imin) continue;
939  if(j==i) continue;
940  shared=shared + gvec.At(j).Alphabet()*aij;
941  }
942  Int jscore= aij.Size()-shared.Size();
943  if(jscore>score) {score=jscore; jmin=i;}
944  }
945 
946  // candidat pairs with fewest states when composed 'minS'
947  /*
948  Idx jmin=0;
949  Float score=-1;
950  for(i=0;i<gvec.Size();i++){
951  if(i==imin) continue;
952  const Generator& gi=gvec.At(imin);
953  const Generator& gj=gvec.At(i);
954  Int jscore= gi.Size()*gj.Size()/((Float) gi.AlphabetSize()*gj.AlphabetSize()); // rough estimate
955  if(jscore<score || score<0) {score=jscore; jmin=i;}
956  }
957  */
958 
959  // compose candidate pair
960  Generator& gimin=gvec.At(imin);
961  Generator& gjmin=gvec.At(jmin);
962  FD_DF("Compose generator " << gimin.Name() << " and " << gjmin.Name());
963  Parallel(gimin,gjmin,gimin);
964  gvec.Erase(jmin);
965  FD_DF("Composition done t#"<< gimin.TransRelSize());
966 
967  // update shared events
968  EventSet silent, all, shared;
969  for(i=0;i<gvec.Size()-1;++i){
970  for(j=i+1;j<gvec.Size();++j){
971  const Generator& g1=gvec.At(i);
972  const Generator& g2=gvec.At(j);
973  shared=shared+g1.Alphabet()*g2.Alphabet();
974  all=all+gvec.At(i).Alphabet();
975  }
976  }
977  silent=all-shared;
978 
979  // normalize for one silent event per generator
980  EventSet sili=gimin.Alphabet()*silent;
981  if(sili.Size()>1) {
982  Idx esi=*(sili.Begin());
983  sili.Erase(esi);
984  silent.EraseSet(sili);
985  TransSet::Iterator tit=gimin.TransRelBegin();
986  TransSet::Iterator tit_end=gimin.TransRelEnd();
987  for(;tit!=tit_end;) {
988  if(!sili.Exists(tit->Ev)) {++tit; continue;}
989  Transition t(tit->X1,esi,tit->X2);
990  gimin.ClrTransition(tit++);
991  gimin.SetTransition(t);
992  }
993  gimin.InjectAlphabet(gimin.Alphabet()-sili);
994  }
995 
996  // abstract
997  if(gvec.Size()>1){
998  FD_DF("Abstract generator " << gimin.Name());
999  FD_DF("Silent events #" << (gimin.Alphabet()*silent).Size());
1000  ConflictEquivalentAbstraction(gimin,gimin.Alphabet()*silent);
1001  if(gimin.InitStates().Size()>0)
1002  if(gimin.MarkedStates().Size()==0){
1003  FD_DF("No marked states (A)");
1004  return false;
1005  }
1006  }
1007 
1008  }
1009 
1010  FD_DF("Testing final stage with t#" << gvec.At(0).TransRelSize() << "/s#" << gvec.At(0).Size());
1011  bool res=gvec.At(0).BlockingStates().Size()==0;
1012  FD_DF("IsNonblocking(): done");
1013  return res;
1014 }
1015 
1016 
1017 
1018 
1019 } // end namespace

libFAUDES 2.28a --- 2016.09.13 --- c++ api documentaion by doxygen