op_bisimulation.cpp
Go to the documentation of this file.
1 /** @file op_bisimulation.cpp
2 
3 Methods to compute bisimulations on dynamic systems (represented
4 by a finite automaton).
5 The relevant algorithms are described in
6 J.-C. Fernandez, “An implementation of an efficient algorithm for
7 bisimulation equivalence,” Science of Computer Programming, vol. 13,
8 pp. 219-236, 1990.
9 The class bisimulation supports these methods.
10 */
11 
12 /* FAU Discrete Event Systems Library (libfaudes)
13 
14  Copyright (C) 2006 Bernd Opitz
15  Exclusive copyright is granted to Klaus Schmidt
16 
17  This library is free software; you can redistribute it and/or
18  modify it under the terms of the GNU Lesser General Public
19  License as published by the Free Software Foundation; either
20  version 2.1 of the License, or (at your option) any later version.
21 
22  This library is distributed in the hope that it will be useful,
23  but WITHOUT ANY WARRANTY; without even the implied warranty of
24  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25  Lesser General Public License for more details.
26 
27  You should have received a copy of the GNU Lesser General Public
28  License along with this library; if not, write to the Free Software
29  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
30 
31 #include <op_bisimulation.h>
32 
33 using namespace std;
34 
35 namespace faudes {
36 // calcBisimulation(rGenOrig, rMapStateToPartition, rGenPart, rNewPartitions)
37 void calcBisimulation(Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart, vector<Idx>& rNewPartitions)
38 {
39  OP_DF("calcBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, " << rGenPart.Name() << ", rNewPartitions)");
40  // Construct an instance of the Bisimulation class from rGenOrig
41  Bisimulation bisim = Bisimulation(rGenOrig);
42  // method to compute the bisimulation on rGenOrig
43  bisim.partition(rMapStateToPartition, rGenPart, rNewPartitions);
44  #ifdef OP_DF_PLOT
45  cout << "The result of the partition refinement is:" << endl;
46  bisim.writeW();
47  bisim.writeRo();
48  #endif
49  OP_DF("calcBisimulation: leaving function");
50 }
51 
52 // calcBisimulation(rGenOrig, rMapStateToPartition, rNewPartitions)
53 void calcBisimulation(Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, vector<Idx>& rNewPartitions)
54 {
55  OP_DF("calcBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, rNewPartitions)");
56  // Construct an instance of the Bisimulation class from rGenOrig
57  Bisimulation bisim = Bisimulation(rGenOrig);
58  // method to compute the bisimulation on rGenOrig
59  bisim.partition(rMapStateToPartition, rNewPartitions);
60  #ifdef FAUDES_DEBUG_FUNCTION
61  cout << "The result of the partition refinement is:" << endl;
62  bisim.writeW();
63  bisim.writeRo();
64  #endif
65  OP_DF("calcBisimulation: leaving function");
66 }
67 
68 // Constructor Bisimulation(g)
69 Bisimulation::Bisimulation(Generator& g)
70 {
71  OP_DF("Bisimulation::Bisimulation(" << g.Name() << ")");
72  gen = &g;
73  gen->TransRel(tset_evx2x1);
74  index=1;
75 
76  // create universal partition holding the complete state space
77  Partition universalPartition;
78  universalPartition.index=index;
79  universalPartition.pFather=NULL;
80  universalPartition.pFirstChild=NULL;
81  universalPartition.pSecondChild=NULL;
82  universalPartition.pBrother=NULL;
83  universalPartition.states = gen->States();
84  universalPartition.numberOfStates = universalPartition.states.Size();
85 
86  // add universal partition (index 1) as root to W-tree
87  W[index]=universalPartition;
88 
89  // add universal Partition to ro and roDividers (all equivalence classes are potential dividers)
90  ro.push_back(&W[index]);
91  roDividers.insert(&W[index]);
92 
93  index++;
94 
95  OP_DF("Bisimulation::Bisimulation: leaving function");
96 }
97 
98 // Bisimulation::partitionSplitter(B)
99 void Bisimulation::partitionSplitter(Partition& B)
100 {
101  OP_DF("Bisimulation::partitionSplitter(B)");
102  OP_DF("Bisimulation::partitionSplitter: index of current coset is " << B.index);
103 
104  // it is ensured by the calling function partition that the passed coset B has a father coset B' and
105  // that ro is stable with respect to B'. Therefore, the info-maps for the father coset B' already exist.
106 
107  // pointer to father coset
108  Partition* pFather = B.pFather;
109 
110  // Choose the coset with fewer states among B and its brother coset and let pSmallerPart point to it
111  Partition* pSmallerPart;
112  Partition* pLargerPart;
113 
115  {
116  pSmallerPart = &B;
117  pLargerPart = B.pBrother;
118  }
119  else
120  {
121  pSmallerPart = B.pBrother;
122  pLargerPart = &B;
123  }
124 
125  OP_DF("Bisimulation::partitionSplitter: the chosen (smaller) coset for segmentation has the index: " << pSmallerPart->index);
126  OP_DF("Bisimulation::partitionSplitter: the larger coset has the index: " << pLargerPart->index << "\n");
127 
128  // helpers
129 
130  // Iterators for loop over events
131  EventSet::Iterator eIt;
132  EventSet::Iterator eItBegin=gen->AlphabetBegin();
133  EventSet::Iterator eItEnd=gen->AlphabetEnd();
134 
135  // Iterators for loop over states
136  StateSet::Iterator sIt;
137  StateSet::Iterator sItBegin;
138  StateSet::Iterator sItEnd;
139 
140  // Iterators over Transitions ordered by EvX2X1
142  TransSetEvX2X1::Iterator tItBegin;
144 
145  // Iterator over ro
146  vector<Partition*>::iterator roIt;
147 
148  // Stack of iterators over ro
149  stack<vector<Partition*>::iterator> toDo;
150 
151  // start computation
152  //loop over all events
153  for (eIt=eItBegin; eIt != eItEnd; ++eIt)
154  {
155  // the current event only has to be processed if there are transitions with *eIt to states in the
156  // father coset, i.e., there is an entry for *eIt in the infoMap of pFather
157  if(pFather->infoMap.find(*eIt) != pFather->infoMap.end() ){
158  OP_DF("Bisimulation::partitionSplitter: partitioning for event " << gen->EventName(*eIt));
159  // initialize info-map for current event of larger child coset with
160  // a copy of the info-map of the current event of the parent coset
161  pLargerPart->infoMap[*eIt]= pFather->infoMap.find(*eIt)->second;
162  // initialize info-map for current event of smaller child coset with an empty info-map
163  pSmallerPart->infoMap[*eIt]=map<Idx,Idx>();
164  // compute the info maps for current event for smaller and larger child cosets
165  computeInfoMaps(*(pSmallerPart), pSmallerPart, pLargerPart, eIt);
166  // if one of the infomaps for the event *eIt is empty, tbe element is erased
167  map<Idx, map<Idx, Idx> >::iterator imIt = pSmallerPart->infoMap.find(*eIt);
168  if(imIt == pSmallerPart->infoMap.end() )
169  pSmallerPart->infoMap.erase(imIt);
170  imIt = pLargerPart->infoMap.find(*eIt);
171  if(imIt == pLargerPart->infoMap.end() )
172  pLargerPart->infoMap.erase(imIt);
173  // compute cosets in ro that are completely contained in T_{eIt}^{-1}{B}
174  OP_DF("Bisimulation::partitionSplitter: computing predecessor cosets of parent coset with index " << pFather->index);
175  Idx tempState;
176  // iteration over all cosets in ro
177  for(roIt=ro.begin(); roIt!=ro.end(); roIt++)
178  {
179  // choose an arbitrary state from the current coset
180  tempState = *((*roIt)->states.Begin());
181  OP_DF("Bisimulation::partitionSplitter: checking candidate coset with index " << (*roIt)->index << " and its state " << gen->StateName(tempState) << " [" << tempState << "]");
182  // check if tempState has an eIt Transition to a state in the parent coset. If yes,
183  // dividing pFather might cause a division of the current coset
184  if(stateLeadsToPartition(tempState, *pFather, eIt))
185  {
186  toDo.push(roIt);
187  OP_DF("Bisimulation::partitionSplitter: coset with index " << (*roIt)->index << " is predecessor for parent coset with index " << (*pFather).index << " and event = " << gen->EventName(*eIt) << " and was pushed on toDo-stack");
188  }
189  }
190  // split all cosets on the toDo-stack using the info-maps. This process is described in Equation (2) of
191  // J.-C. Fernandez, “An implementation of an efficient algorithm for bisimulation equivalence,” Science of Computer Programming, vol. 13, pp. 219-236, 1990.
192  // helpers
193  Idx index1,index2,index3;
194  vector<Idx> removeSet;
195  vector<Partition*> addSet;
196 
197  // iteration over all cosets on todo-stack
198  while(!toDo.empty())
199  {
200  roIt=toDo.top();
201  toDo.pop();
202  OP_DF("Bisimulation::partitionSplitter: current coset taken from todo-stack has index " << (*roIt)->index);
203 
204  bool nonNull[3] = {0,0,0};
205 
206  // create three empty cosets and add them to W-tree
207  Partition X1,X2,X3;
208  index1=index;
209  W[index1]=X1;
210  W[index1].index=index1;
211  index++;
212  index2=index;
213  W[index2]=X2;
214  W[index2].index=index2;
215  index++;
216  index3=index;
217  W[index3]=X3;
218  W[index3].index=index3;
219  index++;
220 
221  sItBegin = (*roIt)->states.Begin();
222  sItEnd = (*roIt)->states.End();
223 
224  // pointer to info map for current event of partent coset
225  map<Idx, map<Idx, Idx> >::const_iterator itMapFather = pFather->infoMap.find(*eIt);
226  // pointer to info map for current event of smaller coset
227  map<Idx, map<Idx, Idx> >::const_iterator itMapSmallerPart = pSmallerPart->infoMap.find(*eIt);
228 
229  // iteration over all states of current candidate coset
230  // apply rules for splitting cosets into subsets using info-maps
231  for(sIt=sItBegin; sIt!=sItEnd; sIt++)
232  {
233  if(itMapSmallerPart == pSmallerPart->infoMap.end() ){
234  W[index2].states.Insert(*sIt);
235  nonNull[1]=true;
236  }
237  else if(itMapSmallerPart->second.find(*sIt)==itMapSmallerPart->second.end())
238  {
239  W[index2].states.Insert(*sIt);
240  nonNull[1]=true;
241  }
242  else
243  {
244  if(itMapFather->second.find(*sIt)->second==itMapSmallerPart->second.find(*sIt)->second)
245  {
246  W[index1].states.Insert(*sIt);
247  nonNull[0]=true;
248  }
249  if(itMapFather->second.find(*sIt)->second > itMapSmallerPart->second.find(*sIt)->second)
250  {
251  W[index3].states.Insert(*sIt);
252  nonNull[2]=true;
253  }
254  }
255  }
256 
257  // update W-tree, ro and roDividers. Different cases are distinguished depending on which of the sets are empty and non-empty
258  switch(nonNull[0]+nonNull[1]*2+nonNull[2]*4)
259  {
260  //case 0: not possible
261  case 1: //only X1 is not empty, no changes in W-tree and ro
262  index=index-3;
263  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has not been split ");
264  break;
265 
266  case 2: //only X2 is not empty, no changes in W-tree and ro
267  index=index-3;
268  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has not been split ");
269  break;
270 
271  case 4: //only X3 is not empty, no changes in W-tree and ro
272  index=index-3;
273  OP_DF("partition " << (*roIt)->index << " has not been split ");
274  break;
275 
276  case 3: //X1 and X2 are not empty
277  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1 and X2");
278 
279  // erase the empty set X3 from W-tree
280  W.erase(W.find(index3));
281 
282  // set cross references
283  W[index2].pBrother=&W[index1];
284  W[index2].pFather=*roIt;
285  W[index2].pFirstChild=NULL;
286  W[index2].pSecondChild=NULL;
287  W[index2].numberOfStates=W[index2].states.Size();
288  W[index1].pBrother=&W[index2];
289  W[index1].pFather=*roIt;
290  W[index1].pFirstChild=NULL;
291  W[index1].pSecondChild=NULL;
292  W[index1].numberOfStates=W[index1].states.Size();
293  (*roIt)->pFirstChild=&W[index1];
294  (*roIt)->pSecondChild=&W[index2];
295 
296  // states of split coset are no longer needed as they are now stored in X1 and X2
297  (*roIt)->states.Clear();
298 
299  // if split coset was in roDividers, then delete it from roDividers
300  if(roDividers.find(*roIt)!=roDividers.end())
301  roDividers.erase(roDividers.find(*roIt));
302 
303  // info-map of the split coset's parent coset can be deleted if it is no longer needed
304  if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
305  {
306  if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
307  {
308  (*roIt)->pFather->infoMap.clear();
309  }
310  }
311 
312  // remember which manipulations have to be made to ro and roDividers
313  removeSet.push_back((*roIt)->index);
314  addSet.push_back(&W[index1]);
315  addSet.push_back(&W[index2]);
316  roDividers.insert(&W[index1]);
317  roDividers.insert(&W[index2]);
318 
319  break;
320  case 5: //X1 and X3 are not empty
321  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1 and X3");
322 
323  // computation analogical to case 3
324 
325  W.erase(W.find(index2));
326  W[index3].pBrother=&W[index1];
327  W[index3].pFather=*roIt;
328  W[index3].pFirstChild=NULL;
329  W[index3].pSecondChild=NULL;
330  W[index3].numberOfStates=W[index3].states.Size();
331  W[index1].pBrother=&W[index3];
332  W[index1].pFather=*roIt;
333  W[index1].pFirstChild=NULL;
334  W[index1].pSecondChild=NULL;
335  W[index1].numberOfStates=W[index1].states.Size();
336  (*roIt)->pFirstChild=&W[index1];
337  (*roIt)->pSecondChild=&W[index3];
338 
339  (*roIt)->states.Clear();
340  if(roDividers.find(*roIt)!=roDividers.end())
341  roDividers.erase(roDividers.find(*roIt));
342  if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
343  {
344  if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
345  (*roIt)->pFather->infoMap.clear();
346  }
347 
348  removeSet.push_back((*roIt)->index);
349  addSet.push_back(&W[index1]);
350  addSet.push_back(&W[index3]);
351  roDividers.insert(&W[index1]);
352  roDividers.insert(&W[index3]);
353  break;
354 
355  case 6: //X2 and X3 are not empty
356  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X2 and X3");
357 
358  // computation analogical to case 3
359 
360  W.erase(W.find(index1));
361  W[index3].pBrother=&W[index2];
362  W[index3].pFather=*roIt;
363  W[index3].pFirstChild=NULL;
364  W[index3].pSecondChild=NULL;
365  W[index3].numberOfStates=W[index3].states.Size();
366  W[index2].pBrother=&W[index3];
367  W[index2].pFather=*roIt;
368  W[index2].pFirstChild=NULL;
369  W[index2].pSecondChild=NULL;
370  W[index2].numberOfStates=W[index2].states.Size();
371  (*roIt)->pFirstChild=&W[index2];
372  (*roIt)->pSecondChild=&W[index3];
373 
374 
375  (*roIt)->states.Clear();
376  if(roDividers.find(*roIt)!=roDividers.end())
377  roDividers.erase(roDividers.find(*roIt));
378  if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
379  {
380  if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
381  (*roIt)->pFather->infoMap.clear();
382  }
383 
384  removeSet.push_back((*roIt)->index);
385  addSet.push_back(&W[index2]);
386  addSet.push_back(&W[index3]);
387  roDividers.insert(&W[index2]);
388  roDividers.insert(&W[index3]);
389 
390  break;
391 
392  case 7: //X1 and X2 and X3 are not empty
393 
394  OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1, X2 and X3");
395 
396  // computation analogical to case 3
397 
398  Partition X23;
399  W[index]=X23;
400  W[index].index=index;
401  (*roIt)->pFirstChild=&W[index1];
402  (*roIt)->pSecondChild=&W[index];
403  W[index1].pFather=*roIt;
404  W[index1].pBrother=&W[index];
405  W[index1].pFirstChild=NULL;
406  W[index1].pSecondChild=NULL;
407  W[index1].numberOfStates=W[index1].states.Size();
408  W[index].pBrother=&W[index1];
409  W[index].pFather=*roIt;
410  W[index].pFirstChild=&W[index2];
411  W[index].pSecondChild=&W[index3];
412  W[index2].pBrother=&W[index3];
413  W[index2].pFather=&W[index];
414  W[index2].pFirstChild=NULL;
415  W[index2].pSecondChild=NULL;
416  W[index2].numberOfStates=W[index2].states.Size();
417  W[index3].pBrother=&W[index2];
418  W[index3].pFather=&W[index];
419  W[index3].pFirstChild=NULL;
420  W[index3].pSecondChild=NULL;
421  W[index3].numberOfStates=W[index3].states.Size();
422  W[index].numberOfStates=W[index2].numberOfStates+W[index3].numberOfStates;
423 
424  (*roIt)->states.Clear();
425 
426  if(roDividers.find(*roIt)!=roDividers.end())
427  roDividers.erase(roDividers.find(*roIt));
428  if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
429  {
430  if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
431  (*roIt)->pFather->infoMap.clear();
432  }
433 
434  removeSet.push_back((*roIt)->index);
435  addSet.push_back(&W[index1]);
436  addSet.push_back(&W[index2]);
437  addSet.push_back(&W[index3]);
438  roDividers.insert(&W[index1]);
439  roDividers.insert(&W[index2]);
440  roDividers.insert(&W[index3]);
441  index++;
442 
443  break;
444  } //end switch-case
445 
446  } // end iteration over todo-stack
447 
448  // delete split partitions from Ro
449  OP_DF("Bisimulation::partitionSplitter: deleting split cosets from ro");
450  vector<Idx>::iterator remIt;
451  for(remIt=removeSet.begin(); remIt != removeSet.end(); ++remIt)
452  {
453  vector<Partition*>::iterator delRoIt = ro.begin();
454  vector<Partition*>::iterator delRoItEnd = ro.end();
455  for(; delRoIt != delRoItEnd; ++delRoIt)
456  {
457  if((*delRoIt)->index == *remIt)
458  {
459  ro.erase(delRoIt);
460  OP_DF("Bisimulation::partitionSplitter: coset "<< (*delRoIt)->index << " deleted from ro");
461  break;
462  }
463  }
464  }
465  removeSet.clear();
466 
467  // insert the newly created partitions to ro
468  OP_DF("Bisimulation::partitionSplitter: inserting the new cosets into ro");
469  vector<Partition*>::iterator addIt;
470  for(addIt=addSet.begin(); addIt != addSet.end(); ++addIt)
471  {
472  ro.push_back(*addIt);
473  OP_DF("Bisimulation::partitionSplitter: coset " << (*addIt)->index << " inserted into ro");
474  }
475  addSet.clear();
476  }
477  } //end loop over all events
478 
479  // infoMap of parent coset is now lo longer needed and can be deleted (the information has been transferred to the children cosets)
480  pFather->infoMap.clear();
481 
482  // ro is now stable with respect to the larger and smaller child cosets
483  pSmallerPart->nonSplitting=true;
484  pLargerPart->nonSplitting=true;
485 
486  // delete the stateSets of the smaller and larger child cosets if no longer needed
487  if(pSmallerPart->pFirstChild != NULL)
488  pSmallerPart->states.Clear();
489  if(pLargerPart->pFirstChild != NULL)
490  pLargerPart->states.Clear();
491 
492  // if smaller and larger partitions were in roDividers, then they now have to be deleted from this vector
493  if(roDividers.find(pSmallerPart) != roDividers.end())
494  roDividers.erase(pSmallerPart);
495  if(roDividers.find(pLargerPart) != roDividers.end())
496  roDividers.erase(pLargerPart);
497 
498  OP_DF("Bisimulation::partitionSplitter: leaving function");
499 }
500 
501 // Bisimulation::computeInfoMaps(node, pSmallerPart, pLargerPart, eIt)
502 void Bisimulation::computeInfoMaps(Partition& node, Partition* pSmallerPart, Partition* pLargerPart, EventSet::Iterator eIt)
503 {
504  OP_DF("Bisimulation::computeInfoMaps(" << node.index << "," << pSmallerPart->index << "," << pLargerPart->index << "," << gen->EventName(*eIt) << ")");
505 
506  //helpers
507  Idx tempState;
508  // iterators over stateSets
509  StateSet::Iterator sIt;
510  StateSet::Iterator sItBegin;
511  StateSet::Iterator sItEnd;
512  // iterators over transitions ordered by EvX2X1
514  TransSetEvX2X1::Iterator tItBegin;
516  // loop over states of current stateSet of coset node
517  sItBegin=node.states.Begin();
518  sItEnd=node.states.End();
519  map<Idx, map<Idx,Idx> >::iterator imItLa, imItSm;
520  imItLa = pLargerPart->infoMap.find(*eIt);
521  imItSm = pSmallerPart->infoMap.find(*eIt);
522  for(sIt=sItBegin; sIt!=sItEnd; sIt++)
523  {
524  tItBegin=tset_evx2x1.BeginByEvX2(*eIt,*sIt);
525  tItEnd=tset_evx2x1.EndByEvX2(*eIt,*sIt);
526  // loop over transitions of current state ordered by EvX2 to find backward reachable states. Note that all states investigated are states of the smaller coset.
527  for(tIt=tItBegin; tIt != tItEnd; ++tIt)
528  {
529  tempState=tIt->X1;
530  // insert a newly found state in the infomap. Then, the number of transition is set to one
531  if(imItSm->second.find(tempState) == imItSm->second.end())
532  {
533  imItSm->second[tempState]=1;
534  }
535  // The number of transitions for the found state is incremented
536  else
537  {
538  imItSm->second[tempState]++;
539  }
540  imItLa->second[tempState]--;
541  if(imItLa->second[tempState]==0)
542  imItLa->second.erase(tempState);
543  }
544  }
545  // recursively call this function for the child cosets of node if the current coset is not a leaf of the W-tree
546  if(node.pFirstChild!=NULL){
547  computeInfoMaps(*(node.pFirstChild), pSmallerPart, pLargerPart, eIt);
548  }
549  if(node.pSecondChild!=NULL){
550  computeInfoMaps(*(node.pSecondChild),pSmallerPart, pLargerPart, eIt);
551  }
552 
553  OP_DF("Bisimulation::computeInfoMaps: leaving function");
554 }
555 
556 // Bisimulation::stateLeadsToPartition(state, node, eIt)
557 bool Bisimulation::stateLeadsToPartition(Idx state, Partition& node, EventSet::Iterator eIt)
558 {
559  OP_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(*eIt) << ")");
560 
561  bool found=false;
562  // there is a direct transition from state to a state in the coset node
563  if(node.states.Exists(gen->TransRelBegin(state, *eIt)->X2) && gen->TransRelBegin(state, *eIt)->X1 == state && gen->TransRelBegin(state, *eIt)->Ev == *eIt)
564  {
565  found = true;
566  }
567  // the stateset of node is stored in its children. Then, try to find a transition to any of the children cosets of node
568  if(found == false && node.pFirstChild!=NULL)
569  {
570  found=stateLeadsToPartition(state,*node.pFirstChild,eIt);
571  }
572 
573  if(found == false && node.pSecondChild!=NULL)
574  {
575  found=stateLeadsToPartition(state,*node.pSecondChild,eIt);
576  }
577 
578  OP_DF("Bisimulation::stateLeadsToPartition: leaving function");
579  return found;
580 }
581 
582 // Bisimulation::partitionClass(B)
583 void Bisimulation::partitionClass(Partition& B)
584 {
585  OP_DF("Bisimulation::partitionClass(" << B.index << ")");
586  OP_DF("Bisimulation::partitionClass: index of passed coset is " << B.index);
587 
588  // helpers
589  EventSet::Iterator eIt;
590  EventSet::Iterator eItBegin = gen->AlphabetBegin();
591  EventSet::Iterator eItEnd = gen->AlphabetEnd();
592 
593 
594  vector<Partition*>::iterator roIt;
595 
596  vector<Partition*> addSet;
597  vector<Partition*>::iterator addIt;
598  vector<Idx> removeSet;
599  vector<Idx>::iterator remIt;
600 
601  // temporary StateSet for computing events T_{eIt}^{-1}(B) for current event eIt
602  StateSet tb;
603 
604  FD_DV("Bisimulation::partitionClass: loop over events " << gen->Alphabet().ToString());
605 
606  // Loop over all events
607  for (eIt=eItBegin; eIt!=eItEnd; ++eIt)
608  {
609  OP_DF("Bisimulation::partitionClass: partitioning for event " << gen->EventName(*eIt));
610  // initialize info-map for current event of current coset node with an empty info-map
611  tb.Clear();
612  // compute info map for current event eIt and coset B and store predecessor states in T_{eIt}^{-1}(B) in tb
613  computeInfoMap(B, B, eIt, tb);
614  // compute the cosets in ro that are split into the subsets intersec and diff by evaluating the backward reachability from states in B
615  for(roIt = ro.begin(); roIt != ro.end(); ++roIt)
616  {
617  OP_DF("Bisimulation::partitionClass: candidate coset to be split has index " << (*roIt)->index);
618 
619  // compute intersection of tb with current candidate coset
620  Partition intersection;
621  W[index]=intersection;
622  W[index].states=(*roIt)->states;
623  W[index].states.SetIntersection(tb);
624  // check if the coset must be split
625  if(!W[index].states.Empty() && W[index].states.Size()!=(*roIt)->states.Size() )
626  {
627  // the coset will be split into two new cosets
628  OP_DF("Bisimulation::partitionClass: current coset with index " << (*roIt)->index << " will be split");
629 
630  // if it was in roDividers, delete it form that vector
631  if(roDividers.find(*roIt)!=roDividers.end())
632  {
633  OP_DF("Bisimulation::partitionClass: candidate was in roDividers and will be deleted from it");
634  roDividers.erase(roDividers.find(*roIt));
635  }
636 
637  // remember that the split coset needs to be deleted from ro
638  removeSet.push_back((*roIt)->index);
639 
640  // set cross references and properties of the intersection-coset
641  W[index].index=index;
642  W[index].pBrother=NULL;
643  W[index].pFirstChild=NULL;
644  W[index].pSecondChild=NULL;
645  W[index].pFather=*roIt;
646  W[index].numberOfStates=W[index].states.Size();
647  (*roIt)->pFirstChild=&W[index];
648 
649  // remember that the new coset has to be added to ro and roDividers
650  addSet.push_back(&W[index]);
651  roDividers.insert(&W[index]);
652  OP_DF("Bisimulation::partitionClass: the coset with index " << (&W[index])->index << " has been added to addSet and to roDividers");
653 
654  index++;
655 
656  // compute difference-coset and set cross references and properties
657  Partition diff;
658  W[index]=diff;
659  W[index].states = ((*roIt)->states) - W[index-1].states;
660  W[index].index=index;
661  W[index].pBrother=&W[index-1];
662  W[index-1].pBrother=&W[index];
663  W[index].pFirstChild=NULL;
664  W[index].pSecondChild=NULL;
665  W[index].pFather=*roIt;
666  W[index].numberOfStates=W[index].states.Size();
667  (*roIt)->pSecondChild=&W[index];
668 
669  // remember that the new coset has to be added to ro and roDividers
670  addSet.push_back(&W[index]);
671  roDividers.insert(&W[index]);
672  OP_DF("Bisimulation::partitionClass: the coset with index " << (&W[index])->index << " has been added to addSet and to roDividers");
673 
674  index++;
675  OP_DF("Bisimulation::partitionClass: the candidate coset has been split");
676 
677  // delete info-map of parent coset of split coset if no longer needed
678  if((*roIt)->pFather!=NULL)
679  {
680  OP_DF("Bisimulation::partitionClass: split coset has parent coset with index " << (*roIt)->pFather->index);
681  if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
682  {
683  (*roIt)->pFather->infoMap.clear();
684  OP_DF("Bisimulation::partitionClass: info map of parent coset deleted");
685  }
686  }
687 
688  // delete stateSet of split coset as the states are now stored in the child cosets
689  (*roIt)->states.Clear();
690  OP_DF("Bisimulation::partitionClass: states of split coset " << (*roIt)->index << " have been deleted");
691  }
692  else
693  {
694  // candidate is not split
695  W.erase(index);
696  }
697  }
698 
699  // delete split partitions from ro
700  OP_DF("Bisimulation::partitionClass: deleting split cosets from ro");
701  for(remIt=removeSet.begin(); remIt!=removeSet.end();remIt++)
702  {
703  vector<Partition*>::iterator delRoIt = ro.begin();
704  vector<Partition*>::iterator delRoItEnd = ro.end();
705  for(; delRoIt!=delRoItEnd; ++delRoIt)
706  {
707  if((*delRoIt)->index==*remIt)
708  {
709  ro.erase(delRoIt);
710  OP_DF("Bisimulation::partitionClass: coset " << (*delRoIt)->index << " was deleted from ro");
711  break;
712  }
713  }
714  }
715  removeSet.clear();
716 
717  // insert the new cosets into ro
718  OP_DF("Bisimulation::partitionClass: inserting the new cosets into ro");
719  for(addIt=addSet.begin();addIt!=addSet.end();addIt++)
720  {
721  ro.push_back(*addIt);
722  OP_DF("Bisimulation::partitionClass: coset with index " << (*addIt)->index << " was inserted into ro");
723  }
724  addSet.clear();
725 
726 
727  } //end loop over events
728 
729  // ro is now stable with respect to coset B
730  B.nonSplitting = true;
731 
732  // delete stateSet of coset B if no longer needed
733  if(B.pFirstChild != NULL)
734  B.states.Clear();
735 
736  // delete coset B from roDividers
737  roDividers.erase(&B);
738 
739  OP_DF("Bisimulation::partitionClass: leaving function");
740 }
741 
742 // Bisimulation::computeInfoMap(B, Bstates, eIt, tb)
743 void Bisimulation::computeInfoMap(Partition& B, Partition& Bstates, EventSet::Iterator eIt, StateSet& tb)
744 {
745  OP_DF("Bisimulation::computeInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(*eIt) << ", Stateset&)");
746  OP_DF("Bisimulation::computeInfoMap: consider stateSet of coset " << Bstates.index);
747 
748  // helpers
749  Idx temp;
750 
751  // iterators over StateSets
752  StateSet::Iterator sIt;
753  StateSet::Iterator sItBegin = Bstates.states.Begin();
754  StateSet::Iterator sItEnd = Bstates.states.End();
755 
756  // iterators over TransSets ordered by EvX2X1
758  TransSetEvX2X1::Iterator tItBegin;
760  map<Idx, map<Idx, Idx> >::iterator imIt;
761  // loop over all states of current partition B
762  for(sIt=sItBegin; sIt != sItEnd; ++sIt)
763  {
764  tItBegin=tset_evx2x1.BeginByEvX2(*eIt,*sIt);
765  tItEnd=tset_evx2x1.EndByEvX2(*eIt,*sIt);
766 
767  // loop over all transitions of current state ordered
768  for(tIt=tItBegin; tIt != tItEnd; ++tIt)
769  {
770  imIt = B.infoMap.find(*eIt);
771  // if the infoMap does not contaion the event *eIt, yet, an entry is inserted
772  if(imIt == B.infoMap.end() )
773  imIt = B.infoMap.insert(B.infoMap.begin(), make_pair(*eIt, map<Idx,Idx>() ) );
774 
775  temp=tIt->X1;
776  tb.Insert(temp);
777 
778  // increase number of occurrences for found predecessor state and current event eIt in info-map of coset B
779  if(imIt->second.find(temp)==imIt->second.end())
780  imIt->second[temp]=1;
781  else
782  imIt->second[temp]++;
783  }
784  }
785  // recursively call this function if coset Bstates has child cosets that contain the state informaton of B
786  if(Bstates.pFirstChild!=NULL)
787  {
788  computeInfoMap(B, *(Bstates.pFirstChild), eIt, tb);
789  }
790  if(Bstates.pSecondChild!=NULL)
791  {
792  computeInfoMap(B, *(Bstates.pSecondChild), eIt, tb);
793  }
794  OP_DF("Bisimulation::computeInfoMap: leaving function");
795 }
796 
797 // Bisimulation::partition(rMapStateToPartition, rGenPart, rNewPartitions)
798 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart, std::vector<Idx>& rNewPartitions)
799 {
800  OP_DF("Bisimulation::partition(rMapStateToPartition," << rGenPart.Name() << ", rNewPartitions)");
801 
802  //helpers
803  set<Partition*>::iterator roDivIt;
804  set<Partition*>::iterator roDivItEnd=roDividers.end();
805  Partition* pFather;
806  bool done=false;
807 
808  // choose first entry of roDividers to start the partition refinement
809  roDivIt=roDividers.begin();
810 
811  // repeat refinement steps performed by the functions partitionClass and partitionSplitter
812  // as long as there are elements in roDividers
813  while(done == false)
814  {
815  // iterate over roDividers and try to find a coset that has a parent coset B' such that ro is stable w.r.t. B'
816  // (note that the order in which the dividers are chosen is in principle arbitrary)
817  while(roDivIt != roDivItEnd && !roDividers.empty())
818  {
819  pFather=(*roDivIt)->pFather;
820  if(pFather != NULL)
821  {
822  if(pFather->nonSplitting == true)
823  {
824  partitionSplitter(**roDivIt);
825 
826  // roDividers might have been manipulated by the function partitionSplitter. Recompute iterators.
827  roDivItEnd=roDividers.end();
828  roDivIt=roDividers.begin();
829  continue;
830  }
831  }
832  roDivIt++;
833  }
834  // no element B' could be found such that ro is stable w.r.t. it, but roDividers is not empty. In that case,
835  // the first element of roDividers is chosen to serve as a "class" in the bisimulation algorithm.
836  if(!roDividers.empty())
837  {
838  roDivIt=roDividers.begin();
839  partitionClass(**roDivIt);
840 
841  // roDividers might have been manipulated by the function partitionClass. Recompute iterators.
842  roDivItEnd=roDividers.end();
843  roDivIt=roDividers.begin();
844  }
845  if(roDividers.empty())
846  done=true;
847  }
848 
849  // The following part of the algorithm computes the quotient automaton rGenPart resulting from the
850  // equivalence relation determined above.
851  OP_DF("Bisimulation::partition: entering function: building generator from equivalence classes");
852 
853  Idx newstate;
854  // loop over all elements of ro and create a new state for every coset in ro (ro contains the set of equivalence classes)
855  vector<Partition*>::const_iterator cRoIt = ro.begin();
856  vector<Partition*>::const_iterator cRoItEnd = ro.end();
857  StateSet::Iterator cSIt;
858  StateSet::Iterator cSItEnd;
859  for (; cRoIt != cRoItEnd; ++cRoIt)
860  {
861  std::ostringstream ostr;
862  newstate = rGenPart.InsState();
863 
864 
865  OP_DF("Bisimulation::partition: new state " << newstate << " for coset "
866  << (*cRoIt)->index << " :"<< (*cRoIt)->states.ToString());
867 
868  // store the index of the equivalence class (new state) in the vector rNewPartitions
869  rNewPartitions.push_back(newstate);
870 
871  cSIt=(*cRoIt)->states.Begin();
872  cSItEnd=(*cRoIt)->states.End();
873 
874  // loop over all states of current coset
875  for (; cSIt != cSItEnd; ++cSIt)
876  {
877  // map every state of the original generator to its equivalence class (= state in rGenPart)
878  // by creating an entry in the map rMapStateToPartition
879  rMapStateToPartition[*cSIt] = newstate;
880 
881  // set state names for resulting generator
882  if (rGenPart.StateNamesEnabled())
883  {
884  if (gen->StateName(*cSIt) == "")
885  {
886  ostr << ToStringInteger(*cSIt) << ",";
887  }
888  else
889  {
890  ostr << gen->StateName(*cSIt) << ",";
891  }
892  }
893 
894  // set init states
895  if (gen->ExistsInitState(*cSIt))
896  {
897  rGenPart.SetInitState(newstate);
898  }
899  // set marked states
900  if (gen->ExistsMarkedState(*cSIt))
901  {
902  rGenPart.SetMarkedState(newstate);
903  }
904  }
905 
906  if (rGenPart.StateNamesEnabled())
907  {
908  std::string statename = ostr.str();
909  if(statename.length()>=1) statename.erase(statename.length()-1);
910  statename = "{" + statename + "}";
911  rGenPart.StateName(newstate, statename);
912  OP_DF("Bisimulation::partition: new state " << statename);
913  }
914  }
915  // create transition relation
916  // iterate over all transitions of the original generator
917  TransSet::Iterator tIt = gen->TransRelBegin();
918  TransSet::Iterator tItEnd = gen->TransRelEnd();
919  for (; tIt != tItEnd; ++tIt)
920  {
921  rGenPart.InsEvent(tIt->Ev); // ??
922  rGenPart.SetTransition(rMapStateToPartition[tIt->X1], tIt->Ev, rMapStateToPartition[tIt->X2]);
923  OP_DF("Bisimulation::partition: adding transition: X1=" << rGenPart.TStr(*tIt) );
924  }
925  OP_DF("Bisimulation::partition: leaving function");
926 }
927 
928 // Bisimulation::partition(rMapStateToPartition, rNewPartitions)
929 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, std::vector<Idx>& rNewPartitions)
930 {
931  OP_DF("Bisimulation::partition(rMapStateToPartition, rNewPartitions)");
932 
933  // this function is equivalent to the other function Bisimulation:partition, but no generator is built from the result
934  set<Partition*>::iterator roDivIt;
935  set<Partition*>::iterator roDivItEnd=roDividers.end();
936  Partition* pFather;
937  bool done=false;
938  // choose first entry of roDividers to start the partition refinement
939  roDivIt=roDividers.begin();
940  // repeat refinement steps performed by the functions partitionClass and partitionSplitter
941  // as long as there are elements in roDividers
942  while(done==false)
943  {
944  // iterate over roDividers and try to find a coset that has a parent coset B' such that ro is stable w.r.t. B'
945  // (note that the order in which the dividers are chosen is in principle arbitrary)
946  while(roDivIt!=roDivItEnd && !roDividers.empty())
947  {
948  pFather=(*roDivIt)->pFather;
949  if(pFather!=NULL)
950  {
951  if(pFather->nonSplitting == true)
952  {
953  partitionSplitter(**roDivIt);
954  // roDividers might have been manipulated by the function partitionSplitter. Recompute iterators.
955  roDivItEnd=roDividers.end();
956  roDivIt=roDividers.begin();
957  continue;
958  }
959  }
960  roDivIt++;
961  }
962  // no element B' could be found such that ro is stable w.r.t. it, but roDividers is not empty. In that case,
963  // the first element of roDividers is chosen to serve as a "class" in the bisimulation algorithm.
964  if(!roDividers.empty())
965  {
966  roDivIt=roDividers.begin();
967  partitionClass(**roDivIt);
968  // roDividers might have been manipulated by the function partitionClass. Recompute iterators.
969  roDivItEnd=roDividers.end();
970  roDivIt=roDividers.begin();
971  }
972  if(roDividers.empty())
973  done=true;
974  }
975 
976 
977  // create an index for every coset in ro an write it to vector rNewPartitions
978  OP_DF("Bisimulation::partition: writing vector rMapStateToPartition");
979 
980  Idx newstate;
981  // loop over all elements of ro
982  vector<Partition*>::const_iterator cRoIt = ro.begin();
983  vector<Partition*>::const_iterator cRoItEnd = ro.end();
984  StateSet::Iterator cSIt;
985  StateSet::Iterator cSItEnd;
986  for (; cRoIt != cRoItEnd; ++cRoIt)
987  {
988  Generator dummy;
989  newstate = dummy.InsState();
990  rNewPartitions.push_back(newstate);
991  cSIt=(*cRoIt)->states.Begin();
992  cSItEnd=(*cRoIt)->states.End();
993  for ( ; cSIt!=cSItEnd; ++ cSIt)
994  {
995  // map every state in the current coset to the index of this coset by creating an entry in the map rMapStateToPartition
996  rMapStateToPartition[*cSIt] = newstate;
997  }
998  }
999  OP_DF("Bisimulation::partition: leaving function");
1000 }
1001 
1002 // Bisimulation::writeW()
1003 void Bisimulation::writeW(void)
1004 {
1005  OP_DF("Bisimulation:writeW()");
1006  cout << "Plotting the W-tree:" << endl;
1007  writeNode(W.find(1)->second);
1008 }
1009 
1010 // Bisimulation::writeNode(node)
1011 void Bisimulation::writeNode(Partition& node)
1012 {
1013  OP_DF("Bisimulation::writeNode(" << node.index << ")");
1014  cout << "Coset with index " << node.index << " has the following states:" << endl;
1015  node.states.Write();
1016  if(node.pFather!=NULL)
1017  cout << "Parent coset has index: " << node.pFather->index << endl;
1018  else
1019  cout << "Coset is the root of the tree" << endl;
1020  if(node.pBrother!=NULL)
1021  cout << "Coset has brother coset with index: " << node.pBrother->index << endl;
1022  else
1023  cout << "Coset has no brother" << endl;
1024  if(node.pFirstChild!=NULL && node.pSecondChild!=NULL)
1025  cout << "Child cosets have indices : " << node.pFirstChild->index << " and " << node.pSecondChild->index << endl;
1026  else
1027  cout << "Coset has no children" << endl;
1028  cout << "ro is stable with respect to this coset (1=yes; 0=no): " << node.nonSplitting << endl;
1029  cout << "Info-map of coset: " << endl;
1030  EventSet::Iterator eIt;
1031  for(eIt=gen->AlphabetBegin();eIt != gen->AlphabetEnd(); ++eIt)
1032  node.writeInfoMap(*eIt);
1033 
1034  if(node.pFirstChild!=NULL)
1035  writeNode(*(node.pFirstChild));
1036  if(node.pSecondChild!=NULL)
1037  writeNode(*(node.pSecondChild));
1038 }
1039 
1040 // Bisimulation::writeRo()
1041 void Bisimulation::writeRo(void)
1042 {
1043  OP_DF("Bisimulation::writeRo()");
1044  cout << "The Cosets with the following indices are in ro: " << endl;
1045  vector<Partition*>::iterator roIt;
1046  vector<Partition*>::iterator roItBegin =ro.begin();
1047  vector<Partition*>::iterator roItEnd = ro.end();
1048  for(roIt=roItBegin; roIt!=roItEnd; roIt++)
1049  cout << (*roIt)->index << endl;
1050  cout << endl;
1051 }
1052 
1053 }

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen