cfl_bisimulation.cpp
Go to the documentation of this file.
1 /** @file cfl_bisimulation.cpp Bisimulation relations
2 
3  Functions to compute bisimulation relations on dynamic systems (represented
4  by non-deterministic finite automata).
5 
6  The relevant algorithms are described in J.-C. Fernandez, "An implementation
7  of an efficient algorithm for bisimulation equivalence", Science of Computer
8  Programming, vol. 13, pp. 219-236, 1990.
9 
10  This code was originally part of the observer plug-in (op_bisimulation.* and
11  op_partition.*). It moved in revised form to corefaudes as of libFAUDES 2.26.
12 
13 **/
14 
15 /* FAU Discrete Event Systems Library (libfaudes)
16 
17  Copyright (C) 2009, Christian Breindl
18  Copyright (C) 2015, Thomas Moor
19  Exclusive copyright is granted to Klaus Schmidt
20 
21  This library is free software; you can redistribute it and/or
22  modify it under the terms of the GNU Lesser General Public
23  License as published by the Free Software Foundation; either
24  version 2.1 of the License, or (at your option) any later version.
25 
26  This library is distributed in the hope that it will be useful,
27  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29  Lesser General Public License for more details.
30 
31  You should have received a copy of the GNU Lesser General Public
32  License along with this library; if not, write to the Free Software
33  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
34 
35 #include <cfl_bisimulation.h>
36 
37 #include <string>
38 #include <sstream>
39 #include <stack>
40 
41 using namespace std;
42 
43 //#undef FD_DF
44 //#define FD_DF(a) FD_WARN(a)
45 
46 namespace faudes {
47 
48 /*
49 *********************************************
50 *********************************************
51 
52 PART 1: Partition
53 
54 Objects of class faudes::Pnode represent a set of states with various administration
55 features for the interpretation as a node in a binary tree. Each node state set amounts
56 to the disjoint union of the two child state sets, with the root of the tree holding the
57 full state set of the generator under consideration. The leaves of the tree the form
58 the current partition in the bisimulation algorithm.
59 
60 The code used to reside in the observer plug-in as a public class up to version 2.25.
61 
62 *********************************************
63 *********************************************
64 */
65 
66 
67 struct Pnode {
68 
69  /** unique partition index */
71 
72  /** Associated set of states */
73  // Revision 20150714 tmoor
74  // --- replaced faudes sets by plain STL sets for inner-loop variables
75  // [test case performance 4min-->1min]
76  // --- avoid copying STL sets by using pointers instead
77  // [test case performance 1min-->30sec]
78  // --- avoid sets altogether, use sorted STL vectors and swap rather than copy
79  // [test case performance 30min-->20sec]
80  std::vector<Idx> states;
81 
82  /** number of states in this coset */
84 
85  /** ref or relatives */
89 
90  /** indicates whether the current partition ro is stable with respect to this block */
91  bool rostable;
92 
93  /** Info-map. First Idx: ev, second Idx: state q, third Idx: number q-ev-successors in this node */
94  std::vector<std::map<Idx,Idx> > infoMap;
95 
96  /** flag to inicate non-empty infoMap per event (for use with alternative info-map constructs) */
97  std::vector<bool> activeEv; // <> infomap nonempty
98 
99  /**
100  * write info-map to console
101  *
102  * @param event
103  * event for which the info-map shall be plotted
104  */
105  void writeInfoMap(Idx event) const {
106  cout << "Writing info-map for event " << event << endl;
107  const std::map<Idx,Idx> & pMap = infoMap[event];
108  std::map<Idx,Idx>::const_iterator mIt;
109  std::map<Idx,Idx>::const_iterator mItBegin = pMap.begin();
110  std::map<Idx,Idx>::const_iterator mItEnd = pMap.end();
111  if(mItBegin == mItEnd)
112  cout << "no entries for this event" << endl;
113  for(mIt=mItBegin; mIt != mItEnd; ++mIt)
114  cout << "state: " << (*mIt).first << " : occurrences: " << (*mIt).second << endl;
115  cout << endl;
116  };
117 };
118 
119 
120 /*
121 *********************************************
122 PART 2: Bisimulation
123 
124 The class faudes::Bisimulation is used to compute the coarsest bisimulation relation
125 and to maintain relevant data structures required for the particular implementation.
126 The code used to reside in the observer plug-in as a public class up to libFAUDES 2.25.
127 
128 *********************************************
129 */
130 
131 
133 
134 public:
135 
136  /**
137  * Contructor:
138  * keep a reference to the generator and initialize the partition and the W-Tree
139  * to represent the universal equivalence relation, i.e. every two states are equivalent.
140  *
141  * @param g
142  * Original generator
143  */
144  Bisimulation(const Generator& g);
145 
146  /**
147  * Destructor
148  */
149  ~Bisimulation(void);
150 
151  /**
152  * Write W-tree to console
153  */
154  void writeW(void);
155 
156  /**
157  * Write the set of equivalence classes to console
158  */
159  void writeRo(void);
160 
161  /**
162  * Perform fixpoint iteration to obtain the coarset bisimulation relation
163  */
164  void refine(void);
165 
166  /**
167  * Extract output generator that represents the resulting quotient automaton.
168  * (need to invoke refine() befor)
169  *
170  * @param rMapStateToPartition
171  * Maps each state to its equivalence class
172  * @param rGenPart
173  * Generator representing the result of the computation. Each state corresponds to an
174  * euivalence class
175  */
176  void partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart);
177 
178 
179  /**
180  * Extract the coarsest quasi-congruence as an STL map
181  * (need to invoke refine() befor)
182  *
183  * @param rMapStateToPartition
184  * Maps each state to its equivalence class
185  */
186  void partition(std::map<Idx,Idx>& rMapStateToPartition);
187 
188  /**
189  * Extract the coarsest quasi-congruence as a list of equivalence classes.
190  * (need to invoke refine() befor)
191  *
192  * @param rPartition
193  * List of equivcalent sets ogf states
194  */
195  void partition(std::list< StateSet >& rPartition);
196 
197 
198 private:
199 
200  /**
201  * internal representation of transition relation with consecutive indexed states and events
202  // Revision 20150724 tmoor
203  // --- technically, re-indexing is equivalent to "pointers on source indicees" and
204  // buffers log-n searches [30sec -> 10sec for our testcases]
205  */
206  struct State {
207  Idx idx; // source state idx
208  vector< vector<Idx> > suc; // successors by event
209  vector< vector<Idx> > pre; // predecessors by event
210  size_t iscnt; // alternative infomap for current BSmaller [not used]
211  size_t ilcnt; // alternative infomap for current BLarger [not used]
212  };
213  vector<State> states; // vector of all states [starting with 1 -- use min-index for debugging]
214  vector<Idx> events; // vector of all events [starting with 1]
215 
216 
217  /**
218  * Keep reference to Automaton
219  */
220  const Generator* gen;
221 
222  /**
223  * Counter to assign a unique index to each node [debugging/cosmetic only]
224  */
226 
227  /**
228  * W-tree. Contains all blocks ever created [required for destruction]
229  */
230  std::vector<Pnode*> W;
231 
232  /**
233  * insert new node to W-tree (empty stateset)
234  * note: this method only cares about indexing, and initialisation of node members
235  * note: cross references are left to the caller
236  */
237  Pnode* newnode();
238 
239  /**
240  * set of nodes that form current partition ro (i.e. leaves of W)
241  */
242  // Revision 20150714 tmoor
243  // --- this used to be a vector with suboptimal performance for search/delete
244  // --- todo: this could be represented by pointers per node
245  std::set<Pnode*> ro;
246 
247  /**
248  * set of nodes that can possibly split classes in ro
249  */
250  std::set<Pnode*> roDividers;
251 
252 
253  /**
254  * compute info-maps for two cosets pSmallerPart and pLargerpart.
255  * - the current partition must be stable wrt the common parent the both parts
256  * - the smaller part and larger part info maps must be initialized empty and by parent, resp.
257  *
258  * @param node
259  * Node to provide states of pSmallerPart (call with pSmallerPart)
260  * @param pSmallerPart
261  * Child coset P1 of P with smaller number of states
262  * @param pLargerPart
263  * Child coset P2 of P with larger number of states
264  * @param ev
265  * Event
266  */
267  void computeInfoMaps(Pnode& node, Pnode* pSmallerPart, Pnode* pLargerPart, Idx ev);
268 
269  /**
270  * Compute info-map for coset B
271  *
272  * @param B
273  * Coset for which the info-map is computed
274  * @param Bstates
275  * Node to provide states of B
276  * @param ev
277  * Event to use
278  * @param tb
279  * sorted vector containing all the states that have an ev-transition into coset B
280  */
281  void computeInfoMap(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb);
282 
283 
284  /**
285  * Alternative: compute and set info-map to state data
286  * --- this is for testing/debugging only, it did neither buy nor cost relevant performance
287  */
288  void setInfoMap(Pnode& BSmaller, Pnode& BLarger, Idx ev);
289  void invImage(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb);
290 
291  /**
292  * Test wehther a state has an ev-transitions into the specified coset
293  *
294  * @param state
295  * State to be examined
296  * @param node
297  * Coset
298  * @param ev
299  * Event
300  */
301  bool stateLeadsToPartition(Idx state, Pnode& node, Idx ev);
302 
303 
304  /**
305  * Refine current partition with respect to coset B
306  *
307  * @param B
308  * Coset
309  */
310  void partitionClass(Pnode& B);
311 
312  /**
313  * Refine current partition with respect to partition B and make use of the fact that
314  * the current partition is stable with respect to the parent coset of B (compound splitter).
315  *
316  * @param B
317  * Coset
318  */
319  void partitionSplitter(Pnode& B);
320 
321 
322  /**
323  * Function for recursively plotting the W-tree to console [debugging]
324  *
325  * @param node
326  * Coset
327  */
328  void writeNode(Pnode& node);
329 
330 };
331 
332 
333 
334 // Constructor Bisimulation(g)
335 Bisimulation::Bisimulation(const Generator& g)
336 {
337  FD_DF("Bisimulation::Bisimulation(" << g.Name() << ")");
338  gen = &g;
339  nxidx=1;
340 
341  // encode transition relation [effectively buffer log-n search]
342  map<Idx,Idx> smap;
343  map<Idx,Idx> emap;
344  Idx max=0;
345  events.resize(gen->Alphabet().Size()+1);
346  EventSet::Iterator eit=gen->AlphabetBegin();
347  for(; eit != gen->AlphabetEnd(); ++eit) {
348  emap[*eit]=++max;
349  events[max]=*eit;
350  }
351  max=0;
352  states.resize(gen->States().Size()+1);
353  StateSet::Iterator sit=gen->StatesBegin();
354  for(; sit != gen->StatesEnd(); ++sit) {
355  smap[*sit]=++max;
356  states[max].idx=*sit;
357  states[max].suc.resize(events.size());
358  states[max].pre.resize(events.size());
359  }
360  TransSet::Iterator tit=gen->TransRelBegin();
361  for(; tit != gen->TransRelEnd(); ++tit) {
362  states[smap[tit->X1]].suc[emap[tit->Ev]].push_back(smap[tit->X2]);
363  states[smap[tit->X2]].pre[emap[tit->Ev]].push_back(smap[tit->X1]);
364  }
365 
366  // create universal partition holding the complete state set
367  Pnode* universe = newnode();
368  universe->pParent=NULL;
369 
370  Idx st=1;
371  for(;st<states.size();++st) universe->states.push_back(st);
372  universe->nsize = universe->states.size();
373 
374  // add universal Partition to ro and roDividers (all equivalence classes are potential dividers)
375  ro.insert(universe);
376  roDividers.insert(universe);
377 
378  // this partition is too coarse ... it needs refinement
379  FD_DF("Bisimulation::Bisimulation: leaving function");
380 }
381 
382 // destruct
383 Bisimulation::~Bisimulation(void)
384 {
385  vector<Pnode*>::iterator wit=W.begin();
386  vector<Pnode*>::iterator wit_end=W.end();
387  for(;wit!=wit_end;++wit) delete *wit;
388 
389 }
390 
391 // maintain W-tree: new node
392 Pnode* Bisimulation::newnode(void) {
393  Pnode* nn= new Pnode();
394  nn->rostable=false;
395  nn->nsize=0;
396  nn->pFirstChild=NULL;
397  nn->pSecondChild=NULL;
398  nn->index=nxidx;
399  nn->infoMap.resize(events.size());
400  nn->activeEv.resize(events.size());
401  nxidx++;
402  W.push_back(nn);
403  return nn;
404 }
405 
406 
407 // Bisimulation::partitionSplitter(B)
408 // Revision tmoor 20150714
409 // -- gprof indicated that most time is spend in this function; not quite sure whether this is acurate
410 // -- circumvented excessive set-look up "W[index]"
411 // -- using stl set for current partition "ro" to improve performance when deleting a cell
412 void Bisimulation::partitionSplitter(Pnode& B) {
413 
414  FD_DF("Bisimulation::partitionSplitter(B)");
415  FD_DF("Bisimulation::partitionSplitter: index of current coset is " << B.index);
416 
417  // it is ensured by the calling function that the passed coset B has a parent coset B' and
418  // that ro is stable with respect to B'. Therefore, the info-maps for the parent coset B' already exist.
419 
420  // pointer to parent coset
421  Pnode* BParent = B.pParent;
422 
423  // Choose the coset with fewer states among B and its brother coset and let pSmallerPart point to it
424  Pnode* BSmallerPart=BParent->pFirstChild;
425  Pnode* BLargerPart=BParent->pSecondChild;
426  if(BSmallerPart->nsize > BLargerPart->nsize) {
427  BSmallerPart=BParent->pSecondChild;
428  BLargerPart=BParent->pFirstChild;
429  }
430 
431  FD_DF("Bisimulation::partitionSplitter: the smaller coset (chosen) has index: " << BSmallerPart->index);
432  FD_DF("Bisimulation::partitionSplitter: the larger coset has index: " << BLargerPart->index);
433 
434  // Iterators for loop over states
435  vector<Idx>::iterator sit;
436  vector<Idx>::iterator sit_end;
437 
438  // stack of cells to process
439  stack<Pnode*> toDo;
440 
441  //loop over all events
442  size_t ev=1;
443  for(; ev < events.size(); ++ev){
444 
445  // the current event only has to be processed if there are transitions with ev to states in the
446  // parent coset, i.e., there is an entry for ev in the infoMap of BParent
447  if(!BParent->activeEv[ev]) continue;
448  FD_DF("Bisimulation::partitionSplitter: partitioning for event " << gen->EventName(events[ev]));
449 
450  // initialize info-map for current event of larger child coset with
451  // a copy of the info-map of the current event of the parent coset
452  BLargerPart->infoMap[ev]= BParent->infoMap[ev];
453  // initialize info-map for current event of smaller child coset with an empty info-map
454  BSmallerPart->infoMap[ev].clear();
455  // compute the info maps for current event for smaller child cosets
456  computeInfoMaps(*(BSmallerPart), BSmallerPart, BLargerPart, ev);
457 
458 
459 
460  //debugging / performance: alternative --- almost no difference in performance
461  /*
462  set<Idx> tb;
463  computeInfoMap(*BSmallerPart,*BSmallerPart,ev,tb);
464  computeInfoMap(*BLargerPart,*BLargerPart,ev,tb);
465  */
466 
467 
468  // alternative current info map
469  // setInfoMap(*BSmallerPart, *BLargerPart, ev);
470 
471  // figure cosets in ro that are completely contained in T_{ev}^{-1}{B}
472  // note: since ro is stable w.r.t BParent, either all or no states of a ro-class have a successor in BParent
473  FD_DF("Bisimulation::partitionSplitter: computing predecessor cosets of parent coset with index " << BParent->index);
474  set<Pnode*>::iterator rit;
475  for(rit=ro.begin(); rit!=ro.end(); ++rit) {
476  // skip singletons
477  if((*rit)->nsize==1) continue;
478  // choose an arbitrary state from the current coset
479  Idx testState = *((*rit)->states.begin());
480  FD_DF("Bisimulation::partitionSplitter: candidate coset index " << (*rit)->index << " and test state " << gen->SStr(testState));
481  if(stateLeadsToPartition(testState, *BParent, ev)) {
482  toDo.push(*rit);
483  FD_DF("Bisimulation::partitionSplitter: coset index " << (*rit)->index << " is predecessor for parent coset with index " << (*BParent).index << " and event = " << gen->EStr(events[ev]) << " and was pushed on toDo-stack");
484  }
485  }
486 
487  // iterator to info map for parent and smaller coset with event (and opt x1) resolved
488  map<Idx, Idx> & imapParentEv = BParent->infoMap[ev];
489  map<Idx, Idx> & imapSmallerEv = BSmallerPart->infoMap[ev];
490  map<Idx, Idx>::const_iterator imapParentEvX1;
491  map<Idx, Idx>::const_iterator imapSmallerEvX1;
492 
493 
494  // split all cosets on the toDo-stack using the info-maps. This process is described in Equation (2) of
495  // J.-C. Fernandez, “An implementation of an efficient algorithm for bisimulation equivalence,”
496  // Science of Computer Programming, vol. 13, pp. 219-236, 1990.
497 
498  // iteration over all cosets on todo-stack
499  while(!toDo.empty()){
500  // take top of the stack
501  Pnode* rop=toDo.top();
502  toDo.pop();
503  FD_DF("Bisimulation::partitionSplitter: current coset taken from todo-stack has index " << rop->index);
504 
505  // prepare three empty state state sets for later insertion to W-Tree
506  vector<Idx> sX1;
507  vector<Idx> sX2;
508  vector<Idx> sX3;
509 
510  // iteration over all states of current candidate coset
511  // apply rules for splitting cosets into subsets using info-maps
512  sit_end = rop->states.end();
513  for(sit=rop->states.begin(); sit!=sit_end; ++sit) {
514  if(imapSmallerEv.empty()){
515  sX2.push_back(*sit); // all sucessors in larger part
516  } else {
517  imapSmallerEvX1=imapSmallerEv.find(*sit);
518  if(imapSmallerEvX1==imapSmallerEv.end()) {
519  sX2.push_back(*sit); // all sucessors in larger part
520  } else {
521  imapParentEvX1=imapParentEv.find(*sit);
522  if(imapParentEvX1->second==imapSmallerEvX1->second)
523  sX1.push_back(*sit); // all sucessors in smaller part
524  else {
525  sX3.push_back(*sit); // sucessors in both parts
526  }
527  }
528  }
529  }
530 
531  // use alternative info-map
532  /*
533  sit_end = rop->states.end();
534  for(sit=rop->states.begin(); sit!=sit_end; ++sit) {
535  State& st=states[*sit];
536  if(st.iscnt==0) { sX2->insert(*sit); continue;}
537  if(st.ilcnt==0) { sX1->insert(*sit); continue;}
538  sX3->insert(*sIt);
539  }
540  */
541 
542  // sort states
543  sort(sX1.begin(), sX1.end());
544  sort(sX2.begin(), sX2.end());
545  sort(sX3.begin(), sX3.end());
546 
547  // insert non empty sets to the W-Tree; W-Tree takes ownership
548  Pnode* nX1 = NULL;
549  Pnode* nX2 = NULL;
550  Pnode* nX3 = NULL;
551  if(!sX1.empty()) { nX1=newnode(); nX1->nsize=sX1.size(); nX1->states.swap(sX1); };
552  if(!sX2.empty()) { nX2=newnode(); nX2->nsize=sX2.size(); nX2->states.swap(sX2); };
553  if(!sX3.empty()) { nX3=newnode(); nX3->nsize=sX3.size(); nX3->states.swap(sX3); };
554 
555  // if not more than one set is empty, no split happens
556  if((nX1!=NULL ? 1 : 0) + (nX2!=NULL ? 1 : 0) + (nX3!=NULL ? 1 : 0) <2) continue;
557 
558  // any non-empty set becomes a ro-class and a roDivider
559  if(nX1!=NULL) {ro.insert(nX1); roDividers.insert(nX1);};
560  if(nX2!=NULL) {ro.insert(nX2); roDividers.insert(nX2);};
561  if(nX3!=NULL) {ro.insert(nX3); roDividers.insert(nX3);};
562 
563  // current split ro-class does not belong to ro anymore
564  ro.erase(rop);
565  roDividers.erase(rop);
566 
567  // states of split ro-class coset are no longer needed as they will be represented by childs
568  // rop->states=vector<Idx>()
569 
570  // info-map of the split coset's parent coset can be deleted if it is no longer needed
571  if(rop->pParent!=NULL && rop->pParent != BParent)
572  if(rop->pParent->pFirstChild->pFirstChild!=NULL && rop->pParent->pSecondChild->pSecondChild!=NULL) {
573  rop->pParent->infoMap.clear();
574  rop->pParent->states=vector<Idx>();
575  }
576 
577  // update W-tree structure (set cross references)
578  switch( (nX1!=NULL ? 1 : 0) + (nX2!=NULL ? 2 : 0) + (nX3!=NULL ? 4 : 0) ) {
579  case 0: // not possible
580  case 1: // not possible
581  case 2: // not possible
582  case 4: // not possible
583  break;
584 
585  case 3: //X1 and X2 are not empty
586  FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1 and X2");
587  rop->pFirstChild=nX1;
588  rop->pSecondChild=nX2;
589  nX2->pParent=rop;
590  nX1->pParent=rop;
591  break;
592 
593  case 5: //X1 and X3 are not empty
594  FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1 and X3");
595  rop->pFirstChild=nX1;
596  rop->pSecondChild=nX3;
597  nX3->pParent=rop;
598  nX1->pParent=rop;
599  break;
600 
601  case 6: //X2 and X3 are not empty
602  FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X2 and X3");
603  rop->pFirstChild=nX2;
604  rop->pSecondChild=nX3;
605  nX3->pParent=rop;
606  nX2->pParent=rop;
607  break;
608 
609  case 7: //X1 and X2 and X3 are not empty
610  FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1, X2 and X3");
611  // have one extra node parent of 2 and 3
612  Pnode* nX23=newnode();
613  std::set_union(nX2->states.begin(), nX2->states.end(), nX3->states.begin(), nX3->states.end(),
614  std::inserter(nX23->states, nX23->states.begin()));
615  // set references
616  rop->pFirstChild=nX1;
617  rop->pSecondChild=nX23;
618  nX1->pParent=rop;
619  nX23->pParent=rop;
620  nX23->pFirstChild=nX2;
621  nX23->pSecondChild=nX3;
622  nX2->pParent=nX23;
623  nX3->pParent=nX23;
624  nX23->nsize=nX2->nsize + nX3->nsize;
625  break;
626 
627  } //end switch-case
628 
629  } // end iteration over todo-stack
630  }
631 
632  // infoMap of parent coset is now lo longer needed and can be deleted (the information has been transferred to the children cosets)
633  BParent->infoMap.clear();
634  BParent->states=vector<Idx>();
635 
636  // ro is now stable with respect to the larger and smaller child cosets
637  BSmallerPart->rostable=true;
638  BLargerPart->rostable=true;
639 
640  // delete the stateSets of the smaller and larger child cosets since they are no ro-deviders anymore
641  if(BSmallerPart->pFirstChild != NULL) BSmallerPart->states=vector<Idx>();
642  if(BLargerPart->pFirstChild != NULL) BLargerPart->states=vector<Idx>();
643 
644  // if smaller and larger partitions were in roDividers, then they now have to be deleted from this vector
645  roDividers.erase(BSmallerPart);
646  roDividers.erase(BLargerPart);
647 
648  FD_DF("Bisimulation::partitionSplitter: leaving function");
649 }
650 
651 // Bisimulation::computeInfoMaps(node, pSmallerPart, pLargerPart, ev)
652 // compute info-maps for smaller and larger part with target states provided by node, first call with node=smaller
653 // assume that smaller is inititialized with zero and larger is initialized with parent map
654 void Bisimulation::computeInfoMaps(Pnode& node, Pnode* pSmallerPart, Pnode* pLargerPart, Idx ev) {
655 
656  FD_DF("Bisimulation::computeInfoMaps(" << node.index << "," << pSmallerPart->index << "," << pLargerPart->index << "," << gen->EventName(ev) << ")");
657 
658  // if the target node does not hold states, ask children
659  if(node.states.empty()){
660  if(node.pFirstChild!=NULL)
661  computeInfoMaps(*(node.pFirstChild), pSmallerPart, pLargerPart, ev);
662  if(node.pSecondChild!=NULL)
663  computeInfoMaps(*(node.pSecondChild),pSmallerPart, pLargerPart, ev);
664  return;
665  }
666 
667  // iterators over transitions
668  vector<Idx>::iterator tit;
669  vector<Idx>::iterator tit_end;
670 
671  // info maps with resolved ev (and opt x1)
672  map<Idx,Idx>& imapLEv = pLargerPart->infoMap[ev];
673  map<Idx,Idx>& imapSEv = pSmallerPart->infoMap[ev];
674  map<Idx,Idx>::iterator imapLEvX1;
675  map<Idx,Idx>::iterator imapSEvX1;
676 
677  // loop over states of target node
678  vector<Idx>::iterator xit2=node.states.begin();
679  vector<Idx>::iterator xit2_end=node.states.end();
680  for(; xit2!=xit2_end; ++xit2) {
681  // loop over transitions of target state to find predecessors
682  // Note that all states investigated are states of the smaller coset.
683  tit = states[*xit2].pre[ev].begin();
684  tit_end = states[*xit2].pre[ev].end();
685  for(; tit!=tit_end; ++tit) {
686  // record predecessor
687  Idx x1=*tit;
688  // increment number of occurrences for found predecessor in smaller part map
689  imapSEvX1=imapSEv.find(x1);
690  if(imapSEvX1!=imapSEv.end())
691  ++imapSEvX1->second;
692  else
693  imapSEv[x1]=1;
694  //decrement number of occurrences for found predecessor in larger part map
695  imapLEvX1=imapLEv.find(x1);
696  --imapLEvX1->second;
697  if(imapLEvX1->second==0) imapLEv.erase(imapLEvX1);
698  }
699  }
700 
701  // counts: larger = parent -smaller (should be outside the recursion)
702  /*
703  map<Idx,Idx> & imapFEv=pLargerPart->pParent->infoMap[ev];
704  map<Idx,Idx>::iterator mit=imapFEv.begin();
705  for(;mit!=imapFEv.end();++mit){
706  Idx cnt= mit->second;
707  imapSEvX1=imapLEv.find(mit->first);
708  if(imapSEvX1!=imapLEv.end()) cnt=cnt-imapSEvX1->second;
709  if(cnt>0) imapLEv[mit->first]=cnt;
710  }
711  */
712 
713  // set active flag
714  pSmallerPart->activeEv[ev]= !pSmallerPart->infoMap[ev].empty();
715  pLargerPart->activeEv[ev]= !pLargerPart->infoMap[ev].empty();
716 
717  FD_DF("Bisimulation::computeInfoMaps: leaving function");
718 }
719 
720 
721 // Bisimulation::stateLeadsToPartition(state, node, ev)
722 // Revision tmoor 20150715
723 // --- this was in error and of low performance
724 bool Bisimulation::stateLeadsToPartition(Idx state, Pnode& node, Idx ev) {
725  FD_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(ev) << ")");
726 
727  // if node does not hold states, ask children
728  if(node.states.empty()) {
729  if(node.pFirstChild!=NULL)
730  if(stateLeadsToPartition(state,*node.pFirstChild,ev)) return true;
731  if(node.pSecondChild!=NULL)
732  if(stateLeadsToPartition(state,*node.pSecondChild,ev)) return true;
733  return false;
734  }
735 
736  // look for transition to target node
737  vector<Idx>::iterator tit = states[state].suc[ev].begin();
738  vector<Idx>::iterator tit_end = states[state].suc[ev].end();
739  for(;tit!=tit_end; ++tit) {
740  if(binary_search(node.states.begin(),node.states.end(),*tit)) return true;
741  // break; --- todo: do we need to iterate here? original code did not ...
742  }
743  return false;
744 }
745 
746 
747 /*
748 // Bisimulation::stateLeadsToPartition(state, node, ev)
749 // libFAUDES Version 2.25 for reference
750 bool Bisimulation::stateLeadsToPartition(Idx state, Pnode& node, Idx ev)
751 {
752  FD_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(ev) << ")");
753 
754  bool found=false;
755  // there is a direct transition from state to a state in the coset node
756  if( node.states->find(gen->TransRelBegin(state, ev)->X2)!= node.states->end() &&
757  gen->TransRelBegin(state, ev)->X1 == state &&
758  gen->TransRelBegin(state, ev)->Ev == ev)
759  {
760  found = true;
761  }
762  // the stateset of node is stored in its children. Then, try to find a transition to any of the children cosets of node
763  if(found == false && node.pFirstChild!=NULL)
764  {
765  found=stateLeadsToPartition(state,*node.pFirstChild,ev);
766  }
767 
768  if(found == false && node.pSecondChild!=NULL)
769  {
770  found=stateLeadsToPartition(state,*node.pSecondChild,ev);
771  }
772 
773  FD_DF("Bisimulation::stateLeadsToPartition: leaving function");
774  return found;
775 }
776 */
777 
778 
779 
780 // Bisimulation::partitionClass(B)
781 // Revision tmoor 20150714
782 // -- gprof indicated that most time is spend in this function; not quite sure whether this is acurate
783 // -- circumvented excessive set-look up "W[index]" (this should become a vector anyway)
784 // -- using stl set for current partition ro to improve performance when deleting a cell
785 void Bisimulation::partitionClass(Pnode& B) {
786 
787  FD_DF("Bisimulation::partitionClass(" << B.index << ")");
788  FD_DF("Bisimulation::partitionClass: index of passed coset is " << B.index);
789 
790  // helpers
791  vector<Pnode*> addSet;
792  vector<Pnode*>::iterator addIt;
793  vector<Pnode*> removeSet;
794  vector<Pnode*>::iterator remIt;
795 
796  FD_DV("Bisimulation::partitionClass: loop over events");
797 
798  // Loop over all events
799  size_t ev=1;
800  for(; ev<events.size(); ++ev) {
801 
802  FD_DF("Bisimulation::partitionClass: partitioning for event " << gen->EventName(events[ev]));
803  // compute info map for current event ev and coset B and store predecessor states in T_{ev}^{-1}(B) in tb
804  vector<Idx> tb;
805  computeInfoMap(B, B, ev, tb);
806  //invImage(B, B, ev, tb);
807 
808  // if there are no predecessors for this event there will be no split
809  // --- tmoor 20150723: this clause bought us 13sec --> 6sec for testcases
810  if(!B.activeEv[ev]) continue;
811 
812  // compute the cosets in ro that are split into the subsets intersec and diff by evaluating the backward reachability from states in B
813  set<Pnode*>::iterator rit;
814  for(rit = ro.begin(); rit != ro.end(); ++rit) {
815  FD_DF("Bisimulation::partitionClass: candidate coset to be split has index " << (*rit)->index);
816 
817  // skip singletons
818  if((*rit)->nsize==1) continue;
819 
820  // compute intersection of tb with current candidate coset
821  vector<Idx> sXinter;
822  std::set_intersection((*rit)->states.begin(), (*rit)->states.end(), tb.begin(), tb.end(),
823  std::inserter(sXinter, sXinter.begin()));
824 
825  // skip on trivial intersection
826  if(sXinter.empty() || sXinter.size()==(*rit)->states.size()) continue;
827  FD_DF("Bisimulation::partitionClass: current coset with index " << (*rit)->index << " will be split");
828 
829  // delete from ro and roDividers
830  roDividers.erase(*rit);
831  removeSet.push_back(*rit);
832 
833  // set up new node for intersection
834  Pnode* nXinter= newnode();
835  nXinter->nsize=sXinter.size();
836  nXinter->states.swap(sXinter);
837  (*rit)->pFirstChild=nXinter;
838  nXinter->pParent=*rit;
839 
840  // set up new node for difference
841  Pnode* nXdiff = newnode();
842  std::set_difference((*rit)->states.begin(), (*rit)->states.end(), nXinter->states.begin(), nXinter->states.end(),
843  std::inserter(nXdiff->states,nXdiff->states.begin()));
844  (*rit)->pSecondChild=nXdiff;
845  nXdiff->pParent=*rit;
846  nXdiff->nsize=nXdiff->states.size();
847 
848  // record that the new cosets have to be added to ro and roDividers
849  addSet.push_back(nXinter);
850  addSet.push_back(nXdiff);
851  roDividers.insert(nXinter);
852  roDividers.insert(nXdiff);
853 
854  // report
855  FD_DF("Bisimulation::partitionClass: the coset with index " << nXinter->index << " has been added to addSet and to roDividers");
856  FD_DF("Bisimulation::partitionClass: the coset with index " << nXdiff->index << " has been added to addSet and to roDividers");
857  FD_DF("Bisimulation::partitionClass: the candidate coset has been split");
858 
859  // delete info-map of parent coset of split coset if no longer needed
860  if((*rit)->pParent!=NULL) {
861  FD_DF("Bisimulation::partitionClass: split coset has parent coset with index " << (*rit)->pParent->index);
862  if((*rit)->pParent->pFirstChild->pFirstChild!=NULL && (*rit)->pParent->pSecondChild->pSecondChild!=NULL && (*rit)->pParent->rostable) {
863  (*rit)->pParent->infoMap.clear();
864  (*rit)->pParent->states=vector<Idx>();
865  FD_DF("Bisimulation::partitionClass: info map of parent coset deleted");
866  }
867  }
868 
869  // delete stateSet of split coset as the states are now stored in the child cosets
870  //(*rit)->states=vector<Idx>();
871  FD_DF("Bisimulation::partitionClass: states of split coset " << (*rit)->index << " have been deleted");
872 
873  } // loop all ro classes
874 
875  // delete split partitions from ro
876  FD_DF("Bisimulation::partitionClass: deleting split cosets from ro");
877  for(remIt=removeSet.begin(); remIt!=removeSet.end();++remIt)
878  ro.erase(*remIt);
879  removeSet.clear();
880 
881  // insert the new cosets into ro
882  FD_DF("Bisimulation::partitionClass: inserting #" << addSet.size() <<" new cosets into ro");
883  for(addIt=addSet.begin();addIt!=addSet.end();++addIt)
884  ro.insert(*addIt);
885  addSet.clear();
886 
887  } //end loop over events
888 
889 
890  // ro is now stable with respect to coset B
891  B.rostable = true;
892 
893  // delete coset B from roDividers
894  roDividers.erase(&B);
895 
896  // delete stateSet of coset B if no longer needed
897  if(B.pFirstChild != NULL) B.states=vector<Idx>();
898 
899  FD_DF("Bisimulation::partitionClass(): done");
900 }
901 
902 // Bisimulation::computeInfoMap(B, Bstates, ev, tb)
903 // compute info map for B using target states provided by Bstates, i.e., first call with Bstates=B
904 void Bisimulation::computeInfoMap(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb) {
905 
906  FD_DF("Bisimulation::computeInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(ev) << ", Stateset&)");
907  FD_DF("Bisimulation::computeInfoMap: consider stateSet of coset " << Bstates.index);
908 
909  // if Bstates does not host states, ask children
910  if(Bstates.states.empty()) {
911  if(Bstates.pFirstChild!=NULL)
912  computeInfoMap(B, *(Bstates.pFirstChild), ev, tb);
913  if(Bstates.pSecondChild!=NULL)
914  computeInfoMap(B, *(Bstates.pSecondChild), ev, tb);
915  return;
916  }
917 
918  // iterators over predecessors
919  vector< Idx >::iterator tit;
920  vector< Idx >::iterator tit_end;
921 
922  // info map with ev (and opt x1) resolved
923  map<Idx, Idx>& imapBEv = B.infoMap[ev];
924  map<Idx, Idx>::iterator imapBEvX1;
925 
926  // loop over all states of current partition B
927  vector<Idx>::iterator xit2 = Bstates.states.begin();
928  vector<Idx>::iterator xit2_end = Bstates.states.end();
929  for(; xit2 != xit2_end; ++ xit2){
930  // loop over all transitions to current target state
931  tit=states[*xit2].pre[ev].begin();
932  tit_end=states[*xit2].pre[ev].end();
933  for(; tit < tit_end; ++tit) {
934  // record precessor
935  Idx x1=*tit;
936  tb.push_back(x1);
937  // increase number of occurrences for found predecessor state in info-map
938  imapBEvX1=imapBEv.find(x1);
939  if(imapBEvX1!=imapBEv.end()) ++imapBEvX1->second;
940  else imapBEv[x1]=1;
941  }
942  }
943  // sort states
944  sort(tb.begin(),tb.end());
945 
946  B.activeEv[ev]= !tb.empty();
947 
948  FD_DF("Bisimulation::computeInfoMap: leaving function");
949 }
950 
951 
952 // Bisimulation::setInfoMap(...)
953 // set up info map for smaller and larger part
954 // -- Revision 20150725: use state data structure to store current info map
955 // -- this did not help performance
956 void Bisimulation::setInfoMap(Pnode& BSmaller, Pnode& BLarger, Idx ev) {
957 
958  FD_DF("Bisimulation::setInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(ev) << ", Stateset&)");
959  FD_DF("Bisimulation::setInfoMap: consider stateSet of coset " << Bstates.index);
960 
961  // clear info
962  vector<State>::iterator sit=states.begin();
963  if(sit!=states.end()) ++sit;
964  for(;sit!=states.end();++sit) {
965  sit->iscnt=0;
966  sit->ilcnt=0;
967  }
968 
969  // iterators over predecessors
970  vector< Idx >::iterator tit;
971  vector< Idx >::iterator tit_end;
972  vector<Idx>::iterator xit2;
973  bool found;
974 
975  // loop over all states of current partition BSmaller
976  found=false;
977  xit2 = BSmaller.states.begin();
978  for(; xit2 != BSmaller.states.end(); ++xit2) {
979  // loop over all transitions to current target state
980  tit=states[*xit2].pre[ev].begin();
981  tit_end=states[*xit2].pre[ev].end();
982  for(; tit < tit_end; ++tit) {
983  // record predecessor
984  Idx x1=*tit;
985  ++(states[x1].iscnt);
986  found=true;
987  }
988  }
989  if(found) BSmaller.activeEv[ev]=true;
990 
991 
992  // loop over all states of current partition BLarger
993  found=false;
994  xit2 = BLarger.states.begin();
995  for(; xit2 != BLarger.states.end(); ++xit2) {
996  // loop over all transitions to current target state
997  tit=states[*xit2].pre[ev].begin();
998  tit_end=states[*xit2].pre[ev].end();
999  for(; tit < tit_end; ++tit) {
1000  // record predecessor
1001  Idx x1=*tit;
1002  ++(states[x1].ilcnt);
1003  found=true;
1004  }
1005  }
1006  if(found) BLarger.activeEv[ev]=true;
1007 
1008  FD_DF("Bisimulation::setInfoMap: leaving function");
1009 }
1010 
1011 
1012 // inverse image
1013 void Bisimulation::invImage(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb) {
1014 
1015  // if Bstates does not host states, ask children
1016  if(Bstates.states.empty()) {
1017  if(Bstates.pFirstChild!=NULL)
1018  invImage(B, *(Bstates.pFirstChild), ev, tb);
1019  if(Bstates.pSecondChild!=NULL)
1020  invImage(B, *(Bstates.pSecondChild), ev, tb);
1021  return;
1022  }
1023 
1024  // iterators over predecessors
1025  vector< Idx >::iterator tit;
1026  vector< Idx >::iterator tit_end;
1027 
1028  // loop over all states of current partition B
1029  vector<Idx>::iterator xit2 = Bstates.states.begin();
1030  for(; xit2 != Bstates.states.end(); ++xit2) {
1031  // loop over all transitions to current target state
1032  tit=states[*xit2].pre[ev].begin();
1033  tit_end=states[*xit2].pre[ev].end();
1034  for(; tit < tit_end; ++tit) {
1035  // record precessor
1036  Idx x1=*tit;
1037  tb.push_back(x1);
1038  }
1039  }
1040  // sort states
1041  sort(tb.begin(),tb.end());
1042 
1043  B.activeEv[ev]= !tb.empty();
1044 }
1045 
1046 
1047 // Bisimulation::refine()
1048 void Bisimulation::refine() {
1049  FD_DF("Bisimulation::refine()");
1050  //helpers
1051  set<Pnode*>::iterator roDivIt;
1052  Pnode* pParent;
1053  // start with first entry of roDividers and repeat the refinement steps performed by the functions partitionClass
1054  // and partitionSplitter as long as there are any roDividers
1055  while(!roDividers.empty()) {
1056  // be interuptable
1057  FD_WPC(ro.size()-roDividers.size(), ro.size(), "Bisimulation: blocks/dividers: " << ro.size() << " / " << roDividers.size());
1058  // find a coset that has a parent coset B' such that ro is stable w.r.t. B'
1059  // (the order in which the dividers are chosen does not matter)
1060  roDivIt=roDividers.begin();
1061  while(roDivIt != roDividers.end()) {
1062  pParent=(*roDivIt)->pParent;
1063  if(pParent == NULL) { roDivIt++; continue; };
1064  if(pParent->rostable != true) { roDivIt++; continue; };
1065  break;
1066  }
1067  // if a splitter was found, do the split
1068  if(roDivIt != roDividers.end()) {
1069  partitionSplitter(**roDivIt);
1070  continue;
1071  }
1072  // else split by class
1073  roDivIt=roDividers.begin();
1074  partitionClass(**roDivIt);
1075  }
1076 }
1077 
1078 
1079 
1080 // Bisimulation::partition(rMapStateToPartition, rGenPart)
1081 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart) {
1082 
1083  FD_DF("Bisimulation::partition(rMapStateToPartition," << rGenPart.Name() << ")");
1084 
1085  // prepare result
1086  rGenPart.Clear();
1087  rMapStateToPartition.clear();
1088 
1089  // loop over all elements of ro and create a new state for every coset in ro (ro contains the set of equivalence classes)
1090  set<Pnode*>::const_iterator cRoIt = ro.begin();
1091  set<Pnode*>::const_iterator cRoItEnd = ro.end();
1092  vector<Idx>::iterator cSIt;
1093  vector<Idx>::iterator cSItEnd;
1094  for(; cRoIt != cRoItEnd; ++cRoIt) {
1095  // have a new state
1096  std::ostringstream ostr;
1097  Idx newstate = rGenPart.InsState();
1098  FD_DF("Bisimulation::partition: new state " << newstate << " for coset "
1099  << (*cRoIt)->index );
1100 
1101  // loop over all original states in current coset
1102  cSIt=(*cRoIt)->states.begin();
1103  cSItEnd=(*cRoIt)->states.end();
1104  for(; cSIt != cSItEnd; ++cSIt) {
1105  // retrieve source state idx
1106  Idx st=states[*cSIt].idx;
1107  // map every state of the original generator to its equivalence class (= state in rGenPart)
1108  // by creating an entry in the map rMapStateToPartition
1109  rMapStateToPartition[st] = newstate;
1110  // set state names for resulting generator
1111  if(rGenPart.StateNamesEnabled()) {
1112  if(gen->StateName(st)!="") ostr << gen->StateName(st) << ",";
1113  else ostr << st << ",";
1114  }
1115  // set init states
1116  if(gen->ExistsInitState(st))
1117  rGenPart.SetInitState(newstate);
1118  // set marked states
1119  if(gen->ExistsMarkedState(st))
1120  rGenPart.SetMarkedState(newstate);
1121  }
1122 
1123  // set state name
1124  if(rGenPart.StateNamesEnabled()) {
1125  std::string statename = ostr.str();
1126  if(statename.length()>=1) statename.erase(statename.length()-1);
1127  statename = "{" + statename + "}";
1128  rGenPart.StateName(newstate, statename);
1129  FD_DF("Bisimulation::partition: new state " << statename);
1130  }
1131 
1132  }
1133 
1134  // create transition relation
1135  // iterate over all transitions of the original generator
1136  TransSet::Iterator tIt = gen->TransRelBegin();
1137  TransSet::Iterator tItEnd = gen->TransRelEnd();
1138  for(; tIt != tItEnd; ++tIt) {
1139  rGenPart.InsEvent(tIt->Ev); // ??
1140  rGenPart.SetTransition(rMapStateToPartition[tIt->X1], tIt->Ev, rMapStateToPartition[tIt->X2]);
1141  FD_DF("Bisimulation::partition: adding transition: X1=" << rGenPart.TStr(*tIt) );
1142  }
1143  FD_DF("Bisimulation::partition: leaving function");
1144 }
1145 
1146 
1147 
1148 // Bisimulation::partition(rMapStateToPartition)
1149 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition) {
1150  FD_DF("Bisimulation::partition(rMapStateToPartition)");
1151 
1152 
1153  // prepare result
1154  rMapStateToPartition.clear();
1155 
1156  // loop over all elements of ro
1157  set<Pnode*>::const_iterator cRoIt = ro.begin();
1158  set<Pnode*>::const_iterator cRoItEnd = ro.end();
1159  vector<Idx>::iterator cSIt;
1160  vector<Idx>::iterator cSItEnd;
1161  for (; cRoIt != cRoItEnd; ++cRoIt) {
1162  cSIt=(*cRoIt)->states.begin();
1163  cSItEnd=(*cRoIt)->states.end();
1164  for(; cSIt!=cSItEnd; ++ cSIt) {
1165  // map every state in the current coset to the index of this coset by creating an entry in the map rMapStateToPartition
1166  Idx st=states[*cSIt].idx;
1167  rMapStateToPartition[st] = (*cRoIt)->index; // fix: tmoor 20150712
1168  }
1169  }
1170  FD_DF("Bisimulation::partition: leaving function");
1171 }
1172 
1173 
1174 // Bisimulation::partition(rPartition)
1175 void Bisimulation::partition(std::list< StateSet >& rPartition) {
1176  FD_DF("Bisimulation::partition(rPartition)");
1177 
1178  // prepare result
1179  rPartition.clear();
1180 
1181  // loop over all elements of ro
1182  set<Pnode*>::const_iterator cRoIt = ro.begin();
1183  for(; cRoIt != ro.end(); ++cRoIt) {
1184  if((*cRoIt)->states.size()<=1) continue;
1185  StateSet tb;
1186  vector<Idx>::iterator cSIt=(*cRoIt)->states.begin();
1187  for(; cSIt!=(*cRoIt)->states.end(); ++ cSIt) tb.Insert(states[*cSIt].idx);
1188  rPartition.push_back(tb);
1189  }
1190  FD_DF("Bisimulation::partition: leaving function");
1191 }
1192 
1193 
1194 // Bisimulation::writeW()
1195 void Bisimulation::writeW(void)
1196 {
1197  FD_DF("Bisimulation:writeW()");
1198  cout << "Plotting the W-tree:" << endl;
1199  writeNode(**W.begin());
1200 }
1201 
1202 // Bisimulation::writeNode(node)
1203 void Bisimulation::writeNode(Pnode& node)
1204 {
1205  FD_DF("Bisimulation::writeNode(" << node.index << ")");
1206  cout << "Coset with index " << node.index << " has the following states:" << endl;
1207  vector<Idx>::iterator cSIt;
1208  vector<Idx>::iterator cSItEnd;
1209  cSIt=node.states.begin();
1210  cSItEnd=node.states.end();
1211  for(; cSIt!=cSItEnd; ++ cSIt) cout << *cSIt << " ";
1212  cout << endl;
1213  if(node.pParent!=NULL)
1214  cout << "Parent coset has index: " << node.pParent->index << endl;
1215  else
1216  cout << "Coset is the root of the tree" << endl;
1217  if(node.pParent!=NULL)
1218  if(node.pParent->pFirstChild!=NULL)
1219  if(node.index!=node.pParent->pFirstChild->index)
1220  cout << "Coset has brother coset with index: " << node.pParent->pFirstChild->index << endl;
1221  if(node.pParent!=NULL)
1222  if(node.pParent->pSecondChild!=NULL)
1223  if(node.index!=node.pParent->pSecondChild->index)
1224  cout << "Coset has brother coset with index: " << node.pParent->pSecondChild->index << endl;
1225 
1226 
1227  if(node.pFirstChild!=NULL && node.pSecondChild!=NULL)
1228  cout << "Child cosets have indices : " << node.pFirstChild->index << " and " << node.pSecondChild->index << endl;
1229  else
1230  cout << "Coset has no children" << endl;
1231  cout << "ro is stable with respect to this coset (1=yes; 0=no): " << node.rostable << endl;
1232  /*
1233  cout << "Info-map of coset: " << endl;
1234  EventSet::Iterator eIt;
1235  for(eIt=gen->AlphabetBegin();eIt != gen->AlphabetEnd(); ++eIt)
1236  node.writeInfoMap(*eIt);
1237 
1238  if(node.pFirstChild!=NULL)
1239  writeNode(*(node.pFirstChild));
1240  if(node.pSecondChild!=NULL)
1241  writeNode(*(node.pSecondChild));
1242  */
1243 }
1244 
1245 // Bisimulation::writeRo()
1246 void Bisimulation::writeRo(void)
1247 {
1248  FD_DF("Bisimulation::writeRo()");
1249  cout << "The Cosets with the following indices are in ro: " << endl;
1250  set<Pnode*>::iterator roIt;
1251  set<Pnode*>::iterator roItBegin =ro.begin();
1252  set<Pnode*>::iterator roItEnd = ro.end();
1253  for(roIt=roItBegin; roIt!=roItEnd; roIt++)
1254  cout << (*roIt)->index << endl;
1255  cout << endl;
1256 }
1257 
1258 
1259 
1260 
1261 /*
1262 *********************************************
1263 *********************************************
1264 PART 3: application interface
1265 
1266 Minimal application interface based on plain functions.
1267 *********************************************
1268 *********************************************
1269 */
1270 
1271 // ComputeBisimulation(rGenOrig, rMapStateToPartition)
1272 void ComputeBisimulation(const Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition)
1273 {
1274  FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition)");
1275  // Construct an instance of the Bisimulation class from rGenOrig
1276  Bisimulation bisim = Bisimulation(rGenOrig);
1277  // method to compute the bisimulation on rGenOrig
1278  bisim.refine();
1279  bisim.partition(rMapStateToPartition);
1280 #ifdef FAUDES_DEBUG_FUNCTION
1281  cout << "The result of the partition refinement is:" << endl;
1282  bisim.writeW();
1283  bisim.writeRo();
1284 #endif
1285  FD_DF("ComputeBisimulation: leaving function");
1286 }
1287 
1288 // ComputeBisimulation(rGenOrig, rMapStateToPartition, rGenPart)
1289 void ComputeBisimulation(const Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart)
1290 {
1291  FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, " << rGenPart.Name() << ")");
1292  // Construct an instance of the Bisimulation class from rGenOrig
1293  Bisimulation bisim = Bisimulation(rGenOrig);
1294  // method to compute the bisimulation on rGenOrig
1295  bisim.refine();
1296  bisim.partition(rMapStateToPartition, rGenPart);
1297 #ifdef FD_DF_PLOT
1298  cout << "The result of the partition refinement is:" << endl;
1299  bisim.writeW();
1300  bisim.writeRo();
1301 #endif
1302  FD_DF("ComputeBisimulation: leaving function");
1303 }
1304 
1305 // ComputeBisimulation(rGenOrig, rPartition)
1306 void ComputeBisimulation(const Generator& rGenOrig, std::list< StateSet >& rPartition)
1307 {
1308  FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rPartition)");
1309  // Construct an instance of the Bisimulation class from rGenOrig
1310  Bisimulation bisim = Bisimulation(rGenOrig);
1311  // method to compute the bisimulation on rGenOrig
1312  bisim.refine();
1313  bisim.partition(rPartition);
1314 #ifdef FD_DF_PLOT
1315  cout << "The result of the partition refinement is:" << endl;
1316  bisim.writeW();
1317  bisim.writeRo();
1318 #endif
1319  FD_DF("ComputeBisimulation: leaving function");
1320 }
1321 
1322 
1323 
1324 }
Bisimulation relations.
#define FD_WPC(cntnow, contdone, message)
Application callback: optional write progress report to console or application, incl count
#define FD_DV(message)
Debug: optional low-level report on iterations and token IO.
#define FD_DF(message)
Debug: optional report on user functions.
std::set< Pnode * > roDividers
set of nodes that can possibly split classes in ro
void refine(void)
Perform fixpoint iteration to obtain the coarset bisimulation relation.
void partition(std::map< Idx, Idx > &rMapStateToPartition, Generator &rGenPart)
Extract output generator that represents the resulting quotient automaton.
void writeW(void)
Write W-tree to console.
std::set< Pnode * > ro
set of nodes that form current partition ro (i.e.
void writeRo(void)
Write the set of equivalence classes to console.
Idx nxidx
Counter to assign a unique index to each node [debugging/cosmetic only].
std::vector< Pnode * > W
W-tree.
const Generator * gen
Keep reference to Automaton.
Set of indices.
Definition: cfl_indexset.h:78
Idx Insert(void)
Insert new index to set.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
Base class of all FAUDES generators.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
EventSet::Iterator AlphabetBegin(void) const
Iterator to Begin() of alphabet.
void SetInitState(Idx index)
Set an existing state as initial state by index.
std::string TStr(const Transition &rTrans) const
Return pretty printable transition (eg for debugging)
std::string StateName(Idx index) const
State name lookup.
void Name(const std::string &rName)
Set the generator's name.
Idx InsState(void)
Add new anonymous state to generator.
void SetMarkedState(Idx index)
Set an existing state as marked state by index.
bool StateNamesEnabled(void) const
Whether libFAUEDS functions are requested to generate state names.
bool InsEvent(Idx index)
Add an existing event to alphabet by index.
virtual void Clear(void)
Clear generator data.
void ComputeBisimulation(const Generator &rGenOrig, std::list< StateSet > &rPartition)
Computation of the coarsest bisimulation relation for a specified generator.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
vector< vector< Idx > > pre
vector< vector< Idx > > suc
void writeInfoMap(Idx event) const
write info-map to console
std::vector< bool > activeEv
flag to inicate non-empty infoMap per event (for use with alternative info-map constructs)
std::vector< std::map< Idx, Idx > > infoMap
Info-map.
Idx index
unique partition index
bool rostable
indicates whether the current partition ro is stable with respect to this block
Pnode * pParent
ref or relatives
Idx nsize
number of states in this coset
std::vector< Idx > states
Associated set of states.

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen