cfl_conflequiv.cpp
Go to the documentation of this file.
1 /** @file cfl_confequiv.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  // good performance operations: go for fixpoint
828  while(true) {
829  Idx sz1=rGen.Size();
830  MergeNonCoaccessible(rGen);
831  if(rSilentEvents.Size()>0){
832  MergeSilentSccs(rGen,rSilentEvents);
833  BlockingSilentEvent(rGen,rSilentEvents);
834  BlockingEvent(rGen,rSilentEvents);
835  OnlySilentOutgoing(rGen,rSilentEvents);
836  OnlySilentIncoming(rGen,rSilentEvents);
837  }
838  if(rGen.Size()==sz1) break;
839  }
840  // break on large automata
841  //if(rGen.TransRelSize()> 50000) break;
842  // badly performing operations: give it a try
843  Idx sz2=rGen.Size();
844  ActiveEventsRule(rGen,rSilentEvents); // can cause tau-scc
845  if(rSilentEvents.Size()>0) {
846  MergeSilentSccs(rGen,rSilentEvents);
847  SilentContinuationRule(rGen,rSilentEvents); // must not have tau-scc
848  }
849  if(rSilentEvents.Size()>0) {
850  ObservationEquivalentQuotient(rGen,rSilentEvents);
851  }
852  if(rGen.Size()==sz2) break;
853  // break on slow progress
854  //if(rGen.Size()> 1000 && rGen.Size()>0.95*sz0) break;
855  }
856  FD_DF("ConflictEquivalentAbstraction(): done with t#"<<rGen.TransRelSize());
857 }
858 
859 
860 // intentend user interface
861 bool IsNonblocking(const GeneratorVector& rGenVec) {
862  Idx i,j;
863 
864  // trivial cases
865  if(rGenVec.Size()==0) return true;
866  if(rGenVec.Size()==1) return IsNonblocking(rGenVec.At(0));
867 
868  // have a local copy of input generator
869  GeneratorVector gvec=rGenVec;
870 
871  // figure silent events
872  EventSet silent, all, shared;
873  for(i=0;i<gvec.Size()-1;++i){
874  for(j=i+1;j<gvec.Size();++j){
875  const Generator& g1=gvec.At(i);
876  const Generator& g2=gvec.At(j);
877  shared=shared+g1.Alphabet()*g2.Alphabet();
878  all=all+gvec.At(i).Alphabet();
879  }
880  }
881  silent=all-shared;
882 
883  // normalize for one silent event per generator
884  for(i=0;i<gvec.Size();++i){
885  Generator& gi=gvec.At(i);
886  EventSet sili=gi.Alphabet()*silent;
887  if(sili.Size()<=1) continue;
888  Idx esi=*(sili.Begin());
889  sili.Erase(esi);
890  silent.EraseSet(sili);
891  all.EraseSet(sili);
893  TransSet::Iterator tit_end=gi.TransRelEnd();
894  for(;tit!=tit_end;) {
895  if(!sili.Exists(tit->Ev)) {++tit; continue;}
896  Transition t(tit->X1,esi,tit->X2);
897  gi.ClrTransition(tit++);
898  gi.SetTransition(t);
899  }
900  gi.InjectAlphabet(gi.Alphabet()-sili);
901  }
902 
903  // reduce all generators
904  for(i=0;i<gvec.Size();i++){
905  Generator& g=gvec.At(i);
906  FD_DF("Abstract generator " << g.Name());
907  FD_DF("Silent events #" << (g.Alphabet()*silent).Size());
909  if(g.InitStates().Size()>0)
910  if(g.MarkedStates().Size()==0){
911  FD_DF("No marked states (A)");
912  return false;
913  }
914  }
915 
916  // loop until resolved
917  while(gvec.Size()>=2) {
918 
919  // candidat pairs with fewest transitions 'minT'
920  Idx imin=0;
921  for(i=1;i<gvec.Size();i++){
922  if(gvec.At(i).TransRelSize()<gvec.At(imin).TransRelSize())
923  imin=i;
924  }
925 
926  // candidat pairs with most local events 'maxL'
927  Idx jmin=0;
928  Int score=-1;
929  for(i=0;i<gvec.Size();i++){
930  if(i==imin) continue;
931  const Generator& gi=gvec.At(imin);
932  const Generator& gj=gvec.At(i);
933  EventSet aij=gi.Alphabet()+gj.Alphabet();
934  EventSet shared;
935  for(j=0;j<gvec.Size();j++){
936  if(j==imin) continue;
937  if(j==i) continue;
938  shared=shared + gvec.At(j).Alphabet()*aij;
939  }
940  Int jscore= aij.Size()-shared.Size();
941  if(jscore>score) {score=jscore; jmin=i;}
942  }
943 
944  // candidat pairs with fewest states when composed 'minS'
945  /*
946  Idx jmin=0;
947  Float score=-1;
948  for(i=0;i<gvec.Size();i++){
949  if(i==imin) continue;
950  const Generator& gi=gvec.At(imin);
951  const Generator& gj=gvec.At(i);
952  Int jscore= gi.Size()*gj.Size()/((Float) gi.AlphabetSize()*gj.AlphabetSize()); // rough estimate
953  if(jscore<score || score<0) {score=jscore; jmin=i;}
954  }
955  */
956 
957  // compose candidate pair
958  Generator& gimin=gvec.At(imin);
959  Generator& gjmin=gvec.At(jmin);
960  FD_DF("Compose generator " << gimin.Name() << " and " << gjmin.Name());
961  Parallel(gimin,gjmin,gimin);
962  gvec.Erase(jmin);
963  FD_DF("Composition done t#"<< gimin.TransRelSize());
964 
965  // update shared events
966  EventSet silent, all, shared;
967  for(i=0;i<gvec.Size()-1;++i){
968  for(j=i+1;j<gvec.Size();++j){
969  const Generator& g1=gvec.At(i);
970  const Generator& g2=gvec.At(j);
971  shared=shared+g1.Alphabet()*g2.Alphabet();
972  all=all+gvec.At(i).Alphabet();
973  }
974  }
975  silent=all-shared;
976 
977  // normalize for one silent event per generator
978  EventSet sili=gimin.Alphabet()*silent;
979  if(sili.Size()>1) {
980  Idx esi=*(sili.Begin());
981  sili.Erase(esi);
982  silent.EraseSet(sili);
983  TransSet::Iterator tit=gimin.TransRelBegin();
984  TransSet::Iterator tit_end=gimin.TransRelEnd();
985  for(;tit!=tit_end;) {
986  if(!sili.Exists(tit->Ev)) {++tit; continue;}
987  Transition t(tit->X1,esi,tit->X2);
988  gimin.ClrTransition(tit++);
989  gimin.SetTransition(t);
990  }
991  gimin.InjectAlphabet(gimin.Alphabet()-sili);
992  }
993 
994  // abstract
995  if(gvec.Size()>1){
996  FD_DF("Abstract generator " << gimin.Name());
997  FD_DF("Silent events #" << (gimin.Alphabet()*silent).Size());
998  ConflictEquivalentAbstraction(gimin,gimin.Alphabet()*silent);
999  if(gimin.InitStates().Size()>0)
1000  if(gimin.MarkedStates().Size()==0){
1001  FD_DF("No marked states (A)");
1002  return false;
1003  }
1004  }
1005 
1006  }
1007 
1008  FD_DF("Testing final stage with t#" << gvec.At(0).TransRelSize() << "/s#" << gvec.At(0).Size());
1009  bool res=gvec.At(0).BlockingStates().Size()==0;
1010  FD_DF("IsNonblocking(): done");
1011  return res;
1012 }
1013 
1014 
1015 
1016 
1017 } // end namespace

libFAUDES 2.26g --- 2015.08.17 --- c++ api documentaion by doxygen