op_bisimulation.cpp

Go to the documentation of this file.
00001 /** @file op_bisimulation.cpp 
00002 
00003 Methods to compute bisimulations on dynamic systems (represented
00004 by a finite automaton). 
00005 The relevant algorithms are described in
00006 J.-C. Fernandez, “An implementation of an efficient algorithm for
00007 bisimulation equivalence,” Science of Computer Programming, vol. 13,
00008 pp. 219-236, 1990.
00009 The class bisimulation supports these methods.
00010 */
00011    
00012 /* FAU Discrete Event Systems Library (libfaudes)
00013 
00014    Copyright (C) 2006  Bernd Opitz
00015    Exclusive copyright is granted to Klaus Schmidt
00016 
00017    This library is free software; you can redistribute it and/or
00018    modify it under the terms of the GNU Lesser General Public
00019    License as published by the Free Software Foundation; either
00020    version 2.1 of the License, or (at your option) any later version.
00021 
00022    This library is distributed in the hope that it will be useful,
00023    but WITHOUT ANY WARRANTY; without even the implied warranty of
00024    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025    Lesser General Public License for more details.
00026 
00027    You should have received a copy of the GNU Lesser General Public
00028    License along with this library; if not, write to the Free Software
00029    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00030 
00031 #include <op_bisimulation.h>
00032 
00033 using namespace std;
00034 
00035 namespace faudes {
00036 // calcBisimulation(rGenOrig, rMapStateToPartition, rGenPart, rNewPartitions)
00037 void calcBisimulation(Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart, vector<Idx>& rNewPartitions)
00038 {
00039     OP_DF("calcBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, " << rGenPart.Name() << ", rNewPartitions)");
00040     // Construct an instance of the Bisimulation class from rGenOrig
00041     Bisimulation bisim = Bisimulation(rGenOrig);
00042     // method to compute the bisimulation on rGenOrig
00043     bisim.partition(rMapStateToPartition, rGenPart, rNewPartitions);
00044     #ifdef OP_DF_PLOT
00045         cout << "The result of the partition refinement is:" << endl;
00046         bisim.writeW();
00047         bisim.writeRo();
00048     #endif
00049     OP_DF("calcBisimulation: leaving function");
00050 }
00051 
00052 // calcBisimulation(rGenOrig, rMapStateToPartition, rNewPartitions)
00053 void calcBisimulation(Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, vector<Idx>& rNewPartitions)
00054 {
00055     OP_DF("calcBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, rNewPartitions)");
00056     // Construct an instance of the Bisimulation class from rGenOrig
00057     Bisimulation bisim = Bisimulation(rGenOrig);
00058     // method to compute the bisimulation on rGenOrig
00059     bisim.partition(rMapStateToPartition, rNewPartitions);
00060     #ifdef FAUDES_DEBUG_FUNCTION
00061         cout << "The result of the partition refinement is:" << endl;
00062         bisim.writeW();
00063         bisim.writeRo();
00064     #endif
00065     OP_DF("calcBisimulation: leaving function");    
00066 }
00067 
00068 // Constructor Bisimulation(g)
00069 Bisimulation::Bisimulation(Generator& g)
00070 {
00071     OP_DF("Bisimulation::Bisimulation(" << g.Name() << ")");
00072     gen = &g;
00073     gen->TransRel(tset_evx2x1);
00074     index=1;
00075 
00076     // create universal partition holding the complete state space
00077     Partition universalPartition;
00078     universalPartition.index=index;
00079     universalPartition.pFather=NULL;
00080     universalPartition.pFirstChild=NULL;
00081     universalPartition.pSecondChild=NULL;
00082     universalPartition.pBrother=NULL;
00083     universalPartition.states = gen->States();
00084     universalPartition.numberOfStates = universalPartition.states.Size();
00085 
00086     // add universal partition (index 1) as root to W-tree
00087     W[index]=universalPartition; 
00088 
00089     // add universal Partition to ro and roDividers (all equivalence classes are potential dividers)
00090     ro.push_back(&W[index]);
00091     roDividers.insert(&W[index]);
00092 
00093     index++;
00094     
00095     OP_DF("Bisimulation::Bisimulation: leaving function");
00096 }
00097 
00098 // Bisimulation::partitionSplitter(B)
00099 void Bisimulation::partitionSplitter(Partition& B)
00100 {
00101     OP_DF("Bisimulation::partitionSplitter(B)");
00102     OP_DF("Bisimulation::partitionSplitter: index of current coset is " << B.index);
00103 
00104     // it is ensured by the calling function partition that the passed coset B has a father coset B' and
00105     // that ro is stable with respect to B'. Therefore, the info-maps for the father coset B' already exist.
00106 
00107     // pointer to father coset
00108     Partition* pFather = B.pFather;
00109 
00110     // Choose the coset with fewer states among B and its brother coset and let pSmallerPart point to it
00111     Partition* pSmallerPart;
00112     Partition* pLargerPart;
00113 
00114     if(B.numberOfStates <= B.pBrother->numberOfStates)
00115     {
00116         pSmallerPart = &B;
00117         pLargerPart = B.pBrother;
00118     }
00119     else
00120     {
00121         pSmallerPart = B.pBrother;
00122         pLargerPart = &B;
00123     }
00124 
00125     OP_DF("Bisimulation::partitionSplitter: the chosen (smaller) coset for segmentation has the index: " << pSmallerPart->index);
00126     OP_DF("Bisimulation::partitionSplitter: the larger coset has the index: " << pLargerPart->index << "\n");
00127 
00128     // helpers
00129 
00130     // Iterators for loop over events
00131     EventSet::Iterator eIt;
00132     EventSet::Iterator eItBegin=gen->AlphabetBegin(); 
00133     EventSet::Iterator eItEnd=gen->AlphabetEnd();
00134 
00135     // Iterators for loop over states
00136     StateSet::Iterator sIt;
00137     StateSet::Iterator sItBegin;
00138     StateSet::Iterator sItEnd;
00139 
00140     // Iterators over Transitions ordered by EvX2X1
00141     TransSetEvX2X1::Iterator tIt;
00142     TransSetEvX2X1::Iterator tItBegin;
00143     TransSetEvX2X1::Iterator tItEnd;
00144 
00145     // Iterator over ro
00146     vector<Partition*>::iterator roIt;
00147     
00148     // Stack of iterators over ro
00149     stack<vector<Partition*>::iterator> toDo;
00150 
00151      // start computation
00152      //loop over all events
00153     for (eIt=eItBegin; eIt != eItEnd; ++eIt)
00154     {
00155   // the current event only has to be processed if there are transitions with *eIt to states in the 
00156   // father coset, i.e., there is an entry for *eIt in the infoMap of pFather
00157   if(pFather->infoMap.find(*eIt) != pFather->infoMap.end() ){
00158     OP_DF("Bisimulation::partitionSplitter: partitioning for event " << gen->EventName(*eIt));
00159     // initialize info-map for current event of larger child coset with 
00160     // a copy of the info-map of the current event of the parent coset 
00161     pLargerPart->infoMap[*eIt]= pFather->infoMap.find(*eIt)->second;
00162     // initialize info-map for current event of smaller child coset with an empty info-map
00163     pSmallerPart->infoMap[*eIt]=map<Idx,Idx>();
00164     // compute the info maps for current event for smaller and larger child cosets
00165     computeInfoMaps(*(pSmallerPart), pSmallerPart, pLargerPart, eIt);
00166     // if one of the infomaps for the event *eIt is empty, tbe element is erased
00167     map<Idx, map<Idx, Idx> >::iterator imIt = pSmallerPart->infoMap.find(*eIt);
00168     if(imIt == pSmallerPart->infoMap.end() )
00169       pSmallerPart->infoMap.erase(imIt);
00170     imIt = pLargerPart->infoMap.find(*eIt);
00171     if(imIt ==  pLargerPart->infoMap.end() )
00172        pLargerPart->infoMap.erase(imIt);
00173     // compute cosets in ro that are completely contained in T_{eIt}^{-1}{B}
00174     OP_DF("Bisimulation::partitionSplitter: computing predecessor cosets of parent coset with index " << pFather->index);
00175     Idx tempState;
00176     // iteration over all cosets in ro
00177     for(roIt=ro.begin(); roIt!=ro.end(); roIt++)
00178     {
00179       // choose an arbitrary state from the current coset
00180       tempState = *((*roIt)->states.Begin());
00181       OP_DF("Bisimulation::partitionSplitter: checking candidate coset with index " << (*roIt)->index << " and its state " << gen->StateName(tempState) << " [" << tempState << "]");
00182       // check if tempState has an eIt Transition to a state in the parent coset. If yes, 
00183       // dividing pFather might cause a division of the current coset
00184       if(stateLeadsToPartition(tempState, *pFather, eIt)) 
00185       {
00186         toDo.push(roIt);
00187         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");
00188       }
00189     }
00190     // split all cosets on the toDo-stack using the info-maps. This process is described in Equation (2) of 
00191     // J.-C. Fernandez, “An implementation of an efficient algorithm for bisimulation equivalence,” Science of Computer Programming, vol. 13, pp. 219-236, 1990.
00192     // helpers
00193     Idx index1,index2,index3;
00194     vector<Idx> removeSet;
00195     vector<Partition*> addSet;
00196     
00197     // iteration over all cosets on todo-stack
00198     while(!toDo.empty())
00199     {
00200       roIt=toDo.top();
00201       toDo.pop();
00202       OP_DF("Bisimulation::partitionSplitter: current coset taken from todo-stack has index " << (*roIt)->index);
00203       
00204       bool nonNull[3] = {0,0,0};
00205       
00206       // create three empty cosets and add them to W-tree
00207       Partition X1,X2,X3;
00208       index1=index;
00209       W[index1]=X1;
00210       W[index1].index=index1;
00211       index++;
00212       index2=index;
00213       W[index2]=X2;
00214       W[index2].index=index2;
00215       index++;
00216       index3=index;
00217       W[index3]=X3;
00218       W[index3].index=index3;
00219       index++;
00220       
00221       sItBegin = (*roIt)->states.Begin();
00222       sItEnd = (*roIt)->states.End();
00223       
00224       // pointer to info map for current event of partent coset 
00225       map<Idx, map<Idx, Idx> >::const_iterator itMapFather = pFather->infoMap.find(*eIt);
00226       // pointer to info map for current event of smaller coset
00227       map<Idx, map<Idx, Idx> >::const_iterator itMapSmallerPart = pSmallerPart->infoMap.find(*eIt);
00228     
00229       // iteration over all states of current candidate coset
00230       // apply rules for splitting cosets into subsets using info-maps 
00231       for(sIt=sItBegin; sIt!=sItEnd; sIt++)
00232       {
00233         if(itMapSmallerPart == pSmallerPart->infoMap.end() ){
00234           W[index2].states.Insert(*sIt);
00235           nonNull[1]=true;
00236         }
00237         else if(itMapSmallerPart->second.find(*sIt)==itMapSmallerPart->second.end())
00238         {
00239           W[index2].states.Insert(*sIt);
00240           nonNull[1]=true;
00241         }
00242         else
00243         {  
00244         if(itMapFather->second.find(*sIt)->second==itMapSmallerPart->second.find(*sIt)->second)
00245         {                
00246           W[index1].states.Insert(*sIt);                
00247           nonNull[0]=true;
00248         }
00249         if(itMapFather->second.find(*sIt)->second > itMapSmallerPart->second.find(*sIt)->second)
00250         {                   
00251           W[index3].states.Insert(*sIt);                
00252           nonNull[2]=true;
00253         }
00254         }
00255       }
00256       
00257       // update W-tree, ro and roDividers. Different cases are distinguished depending on which of the sets are empty and non-empty
00258       switch(nonNull[0]+nonNull[1]*2+nonNull[2]*4) 
00259       {
00260       //case 0: not possible
00261       case 1: //only X1 is not empty, no changes in W-tree and ro
00262         index=index-3;
00263         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has not been split ");
00264         break;
00265     
00266       case 2: //only X2 is not empty, no changes in W-tree and ro
00267         index=index-3;
00268         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has not been split ");
00269         break;
00270     
00271       case 4: //only X3 is not empty, no changes in W-tree and ro
00272         index=index-3;
00273         OP_DF("partition " << (*roIt)->index << " has not been split ");
00274         break;
00275     
00276       case 3: //X1 and X2 are not empty
00277         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1 and X2");
00278         
00279         // erase the empty set X3 from W-tree
00280         W.erase(W.find(index3));
00281         
00282         // set cross references
00283         W[index2].pBrother=&W[index1];
00284         W[index2].pFather=*roIt;
00285         W[index2].pFirstChild=NULL;
00286         W[index2].pSecondChild=NULL;
00287         W[index2].numberOfStates=W[index2].states.Size();
00288         W[index1].pBrother=&W[index2];
00289         W[index1].pFather=*roIt;
00290         W[index1].pFirstChild=NULL;
00291         W[index1].pSecondChild=NULL;
00292         W[index1].numberOfStates=W[index1].states.Size();
00293         (*roIt)->pFirstChild=&W[index1];
00294         (*roIt)->pSecondChild=&W[index2];
00295     
00296         // states of split coset are no longer needed as they are now stored in X1 and X2 
00297         (*roIt)->states.Clear();
00298         
00299         // if split coset was in roDividers, then delete it from roDividers
00300         if(roDividers.find(*roIt)!=roDividers.end())
00301         roDividers.erase(roDividers.find(*roIt));
00302         
00303         // info-map of the split coset's parent coset can be deleted if it is no longer needed 
00304         if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
00305         {
00306         if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
00307         {
00308           (*roIt)->pFather->infoMap.clear();
00309         }
00310         }
00311     
00312         // remember which manipulations have to be made to ro and roDividers
00313         removeSet.push_back((*roIt)->index);
00314         addSet.push_back(&W[index1]);
00315         addSet.push_back(&W[index2]);
00316         roDividers.insert(&W[index1]);
00317         roDividers.insert(&W[index2]);
00318     
00319         break;
00320       case 5: //X1 and X3 are not empty
00321         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1 and X3");
00322         
00323         // computation analogical to case 3
00324         
00325         W.erase(W.find(index2));
00326         W[index3].pBrother=&W[index1];
00327         W[index3].pFather=*roIt;
00328         W[index3].pFirstChild=NULL;
00329         W[index3].pSecondChild=NULL;
00330         W[index3].numberOfStates=W[index3].states.Size();
00331         W[index1].pBrother=&W[index3];
00332         W[index1].pFather=*roIt;
00333         W[index1].pFirstChild=NULL;
00334         W[index1].pSecondChild=NULL;
00335         W[index1].numberOfStates=W[index1].states.Size();
00336         (*roIt)->pFirstChild=&W[index1];
00337         (*roIt)->pSecondChild=&W[index3];
00338     
00339         (*roIt)->states.Clear();
00340         if(roDividers.find(*roIt)!=roDividers.end())
00341         roDividers.erase(roDividers.find(*roIt));
00342         if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
00343         {
00344         if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
00345           (*roIt)->pFather->infoMap.clear();
00346         }
00347     
00348         removeSet.push_back((*roIt)->index);
00349         addSet.push_back(&W[index1]);
00350         addSet.push_back(&W[index3]);
00351         roDividers.insert(&W[index1]);
00352         roDividers.insert(&W[index3]);
00353         break;
00354         
00355       case 6: //X2 and X3 are not empty
00356         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X2 and X3");
00357     
00358         // computation analogical to case 3
00359     
00360         W.erase(W.find(index1));
00361         W[index3].pBrother=&W[index2];
00362         W[index3].pFather=*roIt;
00363         W[index3].pFirstChild=NULL;
00364         W[index3].pSecondChild=NULL;
00365         W[index3].numberOfStates=W[index3].states.Size();
00366         W[index2].pBrother=&W[index3];
00367         W[index2].pFather=*roIt;
00368         W[index2].pFirstChild=NULL;
00369         W[index2].pSecondChild=NULL;
00370         W[index2].numberOfStates=W[index2].states.Size();
00371         (*roIt)->pFirstChild=&W[index2];
00372         (*roIt)->pSecondChild=&W[index3];
00373         
00374     
00375         (*roIt)->states.Clear();
00376         if(roDividers.find(*roIt)!=roDividers.end())
00377         roDividers.erase(roDividers.find(*roIt));
00378         if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
00379         {
00380         if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
00381           (*roIt)->pFather->infoMap.clear();
00382         }
00383         
00384         removeSet.push_back((*roIt)->index);
00385         addSet.push_back(&W[index2]);
00386         addSet.push_back(&W[index3]);
00387         roDividers.insert(&W[index2]);
00388         roDividers.insert(&W[index3]);
00389         
00390         break;
00391         
00392       case 7: //X1 and X2 and X3 are not empty
00393       
00394         OP_DF("Bisimulation::partitionSplitter: coset " << (*roIt)->index << " has been split into cosets X1, X2 and X3");
00395         
00396         // computation analogical to case 3
00397         
00398         Partition X23;
00399         W[index]=X23;
00400         W[index].index=index;
00401         (*roIt)->pFirstChild=&W[index1];
00402         (*roIt)->pSecondChild=&W[index];
00403         W[index1].pFather=*roIt;
00404         W[index1].pBrother=&W[index];
00405         W[index1].pFirstChild=NULL;
00406         W[index1].pSecondChild=NULL;
00407         W[index1].numberOfStates=W[index1].states.Size();
00408         W[index].pBrother=&W[index1];
00409         W[index].pFather=*roIt;
00410         W[index].pFirstChild=&W[index2];
00411         W[index].pSecondChild=&W[index3];
00412         W[index2].pBrother=&W[index3];
00413         W[index2].pFather=&W[index];
00414         W[index2].pFirstChild=NULL;
00415         W[index2].pSecondChild=NULL;
00416         W[index2].numberOfStates=W[index2].states.Size();
00417         W[index3].pBrother=&W[index2];
00418         W[index3].pFather=&W[index];
00419         W[index3].pFirstChild=NULL;
00420         W[index3].pSecondChild=NULL;
00421         W[index3].numberOfStates=W[index3].states.Size();
00422         W[index].numberOfStates=W[index2].numberOfStates+W[index3].numberOfStates;
00423     
00424         (*roIt)->states.Clear();
00425     
00426         if(roDividers.find(*roIt)!=roDividers.end())
00427         roDividers.erase(roDividers.find(*roIt));
00428         if((*roIt)->pFather!=NULL && (*roIt)->pFather != pFather)
00429         {
00430         if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
00431           (*roIt)->pFather->infoMap.clear();
00432         }
00433     
00434         removeSet.push_back((*roIt)->index);
00435         addSet.push_back(&W[index1]);
00436         addSet.push_back(&W[index2]);
00437         addSet.push_back(&W[index3]);
00438         roDividers.insert(&W[index1]);
00439         roDividers.insert(&W[index2]);
00440         roDividers.insert(&W[index3]);
00441         index++;
00442     
00443         break;
00444       } //end switch-case
00445   
00446     } // end iteration over todo-stack
00447   
00448     // delete split partitions from Ro
00449     OP_DF("Bisimulation::partitionSplitter: deleting split cosets from ro");
00450     vector<Idx>::iterator remIt;
00451     for(remIt=removeSet.begin(); remIt != removeSet.end(); ++remIt)
00452     {
00453       vector<Partition*>::iterator delRoIt = ro.begin();
00454       vector<Partition*>::iterator delRoItEnd = ro.end();
00455       for(; delRoIt != delRoItEnd; ++delRoIt)
00456       {
00457         if((*delRoIt)->index == *remIt)
00458         {
00459         ro.erase(delRoIt);
00460         OP_DF("Bisimulation::partitionSplitter: coset "<< (*delRoIt)->index << " deleted from ro");
00461         break;
00462         }
00463       }
00464     }
00465     removeSet.clear();
00466   
00467     // insert the newly created partitions to ro
00468     OP_DF("Bisimulation::partitionSplitter: inserting the new cosets into ro");
00469     vector<Partition*>::iterator addIt;
00470     for(addIt=addSet.begin(); addIt != addSet.end(); ++addIt)
00471     {
00472     ro.push_back(*addIt);
00473     OP_DF("Bisimulation::partitionSplitter: coset " << (*addIt)->index << " inserted into ro");
00474     }
00475     addSet.clear();
00476   }
00477     } //end loop over all events
00478 
00479     // infoMap of parent coset is now lo longer needed and can be deleted (the information has been transferred to the children cosets)
00480     pFather->infoMap.clear();
00481 
00482     // ro is now stable with respect to the larger and smaller child cosets
00483     pSmallerPart->nonSplitting=true;
00484     pLargerPart->nonSplitting=true;
00485     
00486     // delete the stateSets of the smaller and larger child cosets if no longer needed
00487     if(pSmallerPart->pFirstChild != NULL)
00488         pSmallerPart->states.Clear();
00489     if(pLargerPart->pFirstChild != NULL)
00490         pLargerPart->states.Clear();
00491     
00492     // if smaller and larger partitions were in roDividers, then they now have to be deleted from this vector
00493     if(roDividers.find(pSmallerPart) != roDividers.end())
00494             roDividers.erase(pSmallerPart);
00495     if(roDividers.find(pLargerPart) != roDividers.end())
00496             roDividers.erase(pLargerPart);
00497 
00498     OP_DF("Bisimulation::partitionSplitter: leaving function");
00499 }
00500 
00501 // Bisimulation::computeInfoMaps(node, pSmallerPart, pLargerPart, eIt)
00502 void Bisimulation::computeInfoMaps(Partition& node, Partition* pSmallerPart, Partition* pLargerPart, EventSet::Iterator eIt)
00503 {
00504   OP_DF("Bisimulation::computeInfoMaps(" << node.index << "," << pSmallerPart->index << "," << pLargerPart->index << "," << gen->EventName(*eIt) << ")");
00505   
00506   //helpers
00507   Idx tempState;
00508   // iterators over stateSets
00509   StateSet::Iterator sIt;
00510   StateSet::Iterator sItBegin;
00511   StateSet::Iterator sItEnd;
00512   // iterators over transitions ordered by EvX2X1
00513   TransSetEvX2X1::Iterator tIt;
00514   TransSetEvX2X1::Iterator tItBegin;
00515   TransSetEvX2X1::Iterator tItEnd;
00516   // loop over states of current stateSet of coset node
00517   sItBegin=node.states.Begin();
00518   sItEnd=node.states.End();
00519   map<Idx, map<Idx,Idx> >::iterator imItLa, imItSm;
00520   imItLa = pLargerPart->infoMap.find(*eIt);
00521   imItSm = pSmallerPart->infoMap.find(*eIt);
00522   for(sIt=sItBegin; sIt!=sItEnd; sIt++)
00523   {
00524     tItBegin=tset_evx2x1.BeginByEvX2(*eIt,*sIt);
00525     tItEnd=tset_evx2x1.EndByEvX2(*eIt,*sIt);
00526     // 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.
00527     for(tIt=tItBegin; tIt != tItEnd; ++tIt)
00528     {
00529       tempState=tIt->X1;
00530       // insert a newly found state in the infomap. Then, the number of transition is set to one
00531       if(imItSm->second.find(tempState) == imItSm->second.end())
00532       {
00533         imItSm->second[tempState]=1;
00534       }
00535       // The number of transitions for the found state is incremented
00536       else
00537       {
00538         imItSm->second[tempState]++;
00539       }
00540       imItLa->second[tempState]--;
00541       if(imItLa->second[tempState]==0)
00542         imItLa->second.erase(tempState);
00543     }
00544   }
00545   // recursively call this function for the child cosets of node if the current coset is not a leaf of the W-tree
00546   if(node.pFirstChild!=NULL){
00547     computeInfoMaps(*(node.pFirstChild), pSmallerPart, pLargerPart, eIt);
00548   }
00549   if(node.pSecondChild!=NULL){
00550     computeInfoMaps(*(node.pSecondChild),pSmallerPart, pLargerPart, eIt);
00551   }
00552         
00553     OP_DF("Bisimulation::computeInfoMaps: leaving function");
00554 }
00555 
00556 // Bisimulation::stateLeadsToPartition(state,  node, eIt)
00557 bool Bisimulation::stateLeadsToPartition(Idx state, Partition& node, EventSet::Iterator eIt)
00558 {
00559     OP_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(*eIt) << ")");
00560 
00561   bool found=false;
00562   // there is a direct transition from state to a state in the coset node
00563   if(node.states.Exists(gen->TransRelBegin(state, *eIt)->X2) && gen->TransRelBegin(state, *eIt)->X1 == state && gen->TransRelBegin(state, *eIt)->Ev == *eIt)
00564   {
00565     found = true;
00566   }
00567   // the stateset of node is stored in its children. Then, try to find a transition to any of the children cosets of node
00568   if(found == false && node.pFirstChild!=NULL)
00569   {
00570     found=stateLeadsToPartition(state,*node.pFirstChild,eIt);
00571   }
00572   
00573   if(found == false && node.pSecondChild!=NULL)
00574   {
00575     found=stateLeadsToPartition(state,*node.pSecondChild,eIt); 
00576   }
00577   
00578   OP_DF("Bisimulation::stateLeadsToPartition: leaving function");
00579   return found;
00580 }
00581 
00582 // Bisimulation::partitionClass(B)
00583 void Bisimulation::partitionClass(Partition& B)
00584 {
00585     OP_DF("Bisimulation::partitionClass(" << B.index << ")");
00586     OP_DF("Bisimulation::partitionClass: index of passed coset is " << B.index);
00587 
00588     // helpers
00589     EventSet::Iterator eIt;
00590     EventSet::Iterator eItBegin = gen->AlphabetBegin(); 
00591     EventSet::Iterator eItEnd   = gen->AlphabetEnd();
00592 
00593 
00594     vector<Partition*>::iterator roIt;
00595 
00596     vector<Partition*> addSet;
00597     vector<Partition*>::iterator addIt;
00598     vector<Idx> removeSet;
00599     vector<Idx>::iterator remIt;
00600 
00601     // temporary StateSet for computing events T_{eIt}^{-1}(B) for current event eIt
00602     StateSet tb;
00603 
00604     FD_DV("Bisimulation::partitionClass: loop over events " << gen->Alphabet().ToString());
00605 
00606     // Loop over all events
00607     for (eIt=eItBegin; eIt!=eItEnd; ++eIt)
00608     {
00609         OP_DF("Bisimulation::partitionClass: partitioning for event " << gen->EventName(*eIt));
00610         // initialize info-map for current event of current coset node with an empty info-map
00611         tb.Clear();
00612         // compute info map for current event eIt and coset B and store predecessor states in T_{eIt}^{-1}(B) in tb
00613         computeInfoMap(B, B, eIt, tb);
00614         // compute the cosets in ro that are split into the subsets intersec and diff by evaluating the backward reachability from states in B
00615         for(roIt = ro.begin(); roIt != ro.end(); ++roIt)
00616         {
00617              OP_DF("Bisimulation::partitionClass: candidate coset to be split has index " << (*roIt)->index);
00618 
00619             // compute intersection of tb with current candidate coset
00620             Partition intersection;
00621             W[index]=intersection;
00622             W[index].states=(*roIt)->states;
00623             W[index].states.SetIntersection(tb);
00624             // check if the coset must be split
00625             if(!W[index].states.Empty() && W[index].states.Size()!=(*roIt)->states.Size() )
00626             {
00627                 // the coset will be split into two new cosets 
00628                 OP_DF("Bisimulation::partitionClass: current coset with index " << (*roIt)->index << " will be split");
00629                 
00630                 // if it was in roDividers, delete it form that vector
00631                 if(roDividers.find(*roIt)!=roDividers.end())
00632                 {
00633                     OP_DF("Bisimulation::partitionClass: candidate was in roDividers and will be deleted from it");
00634                     roDividers.erase(roDividers.find(*roIt));
00635                 }
00636                 
00637                 // remember that the split coset needs to be deleted from ro
00638                 removeSet.push_back((*roIt)->index);
00639 
00640                 // set cross references and properties of the intersection-coset
00641                 W[index].index=index;
00642                 W[index].pBrother=NULL;
00643                 W[index].pFirstChild=NULL;
00644                 W[index].pSecondChild=NULL;
00645                 W[index].pFather=*roIt;
00646                 W[index].numberOfStates=W[index].states.Size();
00647                 (*roIt)->pFirstChild=&W[index];
00648 
00649                 // remember that the new coset has to be added to ro and roDividers
00650                 addSet.push_back(&W[index]);
00651                 roDividers.insert(&W[index]);                
00652                 OP_DF("Bisimulation::partitionClass: the coset with index " << (&W[index])->index << " has been added to addSet and to roDividers");
00653 
00654                 index++;
00655                 
00656                 // compute difference-coset and set cross references and properties
00657                 Partition diff;
00658                 W[index]=diff;
00659                 W[index].states = ((*roIt)->states) - W[index-1].states;
00660                 W[index].index=index;
00661                 W[index].pBrother=&W[index-1];
00662                 W[index-1].pBrother=&W[index];
00663                 W[index].pFirstChild=NULL;
00664                 W[index].pSecondChild=NULL;
00665                 W[index].pFather=*roIt;
00666                 W[index].numberOfStates=W[index].states.Size();
00667                 (*roIt)->pSecondChild=&W[index];
00668                 
00669                 // remember that the new coset has to be added to ro and roDividers
00670                 addSet.push_back(&W[index]);
00671                 roDividers.insert(&W[index]);
00672                 OP_DF("Bisimulation::partitionClass: the coset with index " << (&W[index])->index << " has been added to addSet and to roDividers");
00673                 
00674                 index++;
00675                 OP_DF("Bisimulation::partitionClass: the candidate coset has been split");
00676 
00677                 // delete info-map of parent coset of split coset if no longer needed
00678                 if((*roIt)->pFather!=NULL)
00679                 {
00680                     OP_DF("Bisimulation::partitionClass: split coset has parent coset with index " << (*roIt)->pFather->index);
00681                     if((*roIt)->pFather->pFirstChild->pFirstChild!=NULL && (*roIt)->pFather->pSecondChild->pSecondChild!=NULL)
00682                     {
00683                         (*roIt)->pFather->infoMap.clear();
00684                         OP_DF("Bisimulation::partitionClass: info map of parent coset deleted");
00685                     }
00686                 }
00687                 
00688                 // delete stateSet of split coset as the states are now stored in the child cosets
00689                 (*roIt)->states.Clear();
00690                 OP_DF("Bisimulation::partitionClass: states of split coset " << (*roIt)->index << " have been deleted");
00691             }
00692             else
00693             {
00694                 // candidate is not split
00695                 W.erase(index); 
00696             }
00697         }
00698 
00699         // delete split partitions from ro
00700         OP_DF("Bisimulation::partitionClass: deleting split cosets from ro");
00701         for(remIt=removeSet.begin(); remIt!=removeSet.end();remIt++)
00702         {
00703             vector<Partition*>::iterator delRoIt = ro.begin();
00704             vector<Partition*>::iterator delRoItEnd = ro.end();
00705             for(; delRoIt!=delRoItEnd; ++delRoIt)
00706             {
00707                 if((*delRoIt)->index==*remIt)
00708                 {
00709                     ro.erase(delRoIt);
00710                     OP_DF("Bisimulation::partitionClass: coset " << (*delRoIt)->index << " was deleted from ro");
00711                     break;
00712                 }
00713             }
00714         }
00715         removeSet.clear();
00716  
00717         // insert the new cosets into ro
00718         OP_DF("Bisimulation::partitionClass: inserting the new cosets into ro");
00719         for(addIt=addSet.begin();addIt!=addSet.end();addIt++)
00720         {
00721             ro.push_back(*addIt);
00722             OP_DF("Bisimulation::partitionClass: coset with index " << (*addIt)->index << " was inserted into ro"); 
00723         }
00724         addSet.clear();
00725 
00726 
00727     } //end loop over events
00728 
00729     // ro is now stable with respect to coset B
00730     B.nonSplitting = true;
00731     
00732     // delete stateSet of coset B if no longer needed
00733     if(B.pFirstChild != NULL)
00734         B.states.Clear();
00735         
00736     // delete coset B from roDividers
00737     roDividers.erase(&B);
00738     
00739     OP_DF("Bisimulation::partitionClass: leaving function");
00740 }
00741 
00742 // Bisimulation::computeInfoMap(B, Bstates, eIt, tb)
00743 void Bisimulation::computeInfoMap(Partition& B, Partition& Bstates, EventSet::Iterator eIt, StateSet& tb)
00744 {
00745   OP_DF("Bisimulation::computeInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(*eIt) << ", Stateset&)");
00746   OP_DF("Bisimulation::computeInfoMap: consider stateSet of coset " << Bstates.index);
00747   
00748   // helpers
00749   Idx temp;
00750   
00751   // iterators over StateSets
00752   StateSet::Iterator sIt;
00753   StateSet::Iterator sItBegin = Bstates.states.Begin();
00754   StateSet::Iterator sItEnd  = Bstates.states.End();
00755   
00756   // iterators over TransSets ordered by EvX2X1
00757   TransSetEvX2X1::Iterator tIt;
00758   TransSetEvX2X1::Iterator tItBegin;
00759   TransSetEvX2X1::Iterator tItEnd;
00760   map<Idx, map<Idx, Idx> >::iterator imIt;
00761   // loop over all states of current partition B
00762   for(sIt=sItBegin; sIt != sItEnd; ++sIt)
00763   {
00764   tItBegin=tset_evx2x1.BeginByEvX2(*eIt,*sIt);
00765   tItEnd=tset_evx2x1.EndByEvX2(*eIt,*sIt);
00766   
00767     // loop over all transitions of current state ordered
00768     for(tIt=tItBegin; tIt != tItEnd; ++tIt)
00769     {
00770       imIt = B.infoMap.find(*eIt);
00771       // if the infoMap does not contaion the event *eIt, yet, an entry is inserted
00772       if(imIt == B.infoMap.end() )
00773         imIt = B.infoMap.insert(B.infoMap.begin(), make_pair(*eIt, map<Idx,Idx>() ) );
00774       
00775       temp=tIt->X1;
00776       tb.Insert(temp);
00777     
00778       // increase number of occurrences for found predecessor state and current event eIt in info-map of coset B
00779       if(imIt->second.find(temp)==imIt->second.end())
00780         imIt->second[temp]=1;
00781       else
00782         imIt->second[temp]++;
00783     }
00784   }
00785   // recursively call this function if coset Bstates has child cosets that contain the state informaton of B
00786   if(Bstates.pFirstChild!=NULL)
00787   {
00788   computeInfoMap(B, *(Bstates.pFirstChild), eIt, tb);
00789   }
00790   if(Bstates.pSecondChild!=NULL)
00791   {
00792   computeInfoMap(B, *(Bstates.pSecondChild), eIt, tb);
00793   }
00794   OP_DF("Bisimulation::computeInfoMap: leaving function");
00795 }
00796 
00797 // Bisimulation::partition(rMapStateToPartition, rGenPart, rNewPartitions)
00798 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart, std::vector<Idx>& rNewPartitions)
00799 {
00800     OP_DF("Bisimulation::partition(rMapStateToPartition," << rGenPart.Name() << ", rNewPartitions)");
00801     
00802     //helpers
00803     set<Partition*>::iterator roDivIt;
00804     set<Partition*>::iterator roDivItEnd=roDividers.end();
00805     Partition* pFather;
00806     bool done=false;
00807 
00808     // choose first entry of roDividers to start the partition refinement
00809     roDivIt=roDividers.begin();
00810     
00811     // repeat refinement steps performed by the functions partitionClass and partitionSplitter 
00812     // as long as there are elements in roDividers
00813     while(done == false)
00814     {
00815         // iterate over roDividers and try to find a coset that has a parent coset B' such that ro is stable w.r.t. B'
00816         // (note that the order in which the dividers are chosen is in principle arbitrary)
00817         while(roDivIt != roDivItEnd && !roDividers.empty())
00818         {
00819             pFather=(*roDivIt)->pFather;
00820             if(pFather != NULL) 
00821             {
00822                 if(pFather->nonSplitting == true) 
00823                 {
00824                     partitionSplitter(**roDivIt);
00825                     
00826                     // roDividers might have been manipulated by the function partitionSplitter. Recompute iterators.
00827                     roDivItEnd=roDividers.end();
00828                     roDivIt=roDividers.begin();
00829                     continue;
00830                 }
00831             }
00832             roDivIt++;
00833         }
00834         // no element B' could be found such that ro is stable w.r.t. it, but roDividers is not empty. In that case,
00835         // the first element of roDividers is chosen to serve as a "class" in the bisimulation algorithm. 
00836         if(!roDividers.empty())
00837         {
00838             roDivIt=roDividers.begin();
00839             partitionClass(**roDivIt);
00840             
00841             // roDividers might have been manipulated by the function partitionClass. Recompute iterators.
00842             roDivItEnd=roDividers.end();
00843             roDivIt=roDividers.begin();
00844         }
00845         if(roDividers.empty())
00846             done=true;
00847     }
00848 
00849     // The following part of the algorithm computes the quotient automaton rGenPart resulting from the 
00850     // equivalence relation determined above. 
00851     OP_DF("Bisimulation::partition: entering function: building generator from equivalence classes");
00852     
00853     Idx newstate;
00854     // loop over all elements of ro and create a new state for every coset in ro (ro contains the set of equivalence classes)
00855     vector<Partition*>::const_iterator cRoIt    = ro.begin();
00856     vector<Partition*>::const_iterator cRoItEnd = ro.end();
00857     StateSet::Iterator cSIt;
00858     StateSet::Iterator cSItEnd;
00859     for (; cRoIt != cRoItEnd; ++cRoIt) 
00860     {
00861         std::ostringstream ostr;
00862         newstate = rGenPart.InsState();
00863         
00864 
00865         OP_DF("Bisimulation::partition: new state " << newstate << " for coset " 
00866         << (*cRoIt)->index << " :"<< (*cRoIt)->states.ToString());
00867 
00868         // store the index of the equivalence class (new state) in the vector rNewPartitions
00869         rNewPartitions.push_back(newstate);
00870         
00871         cSIt=(*cRoIt)->states.Begin();
00872         cSItEnd=(*cRoIt)->states.End();
00873         
00874         // loop over all states of current coset
00875         for (; cSIt != cSItEnd; ++cSIt) 
00876         {
00877             // map every state of the original generator to its equivalence class (= state in rGenPart) 
00878             // by creating an entry in the map rMapStateToPartition 
00879             rMapStateToPartition[*cSIt] = newstate;
00880             
00881             // set state names for resulting generator
00882             if (rGenPart.StateNamesEnabled()) 
00883             {
00884                 if (gen->StateName(*cSIt) == "") 
00885                 {
00886                     ostr << ToStringInteger(*cSIt) << ",";
00887                 }
00888                 else 
00889                 {
00890                     ostr << gen->StateName(*cSIt) << ",";
00891                 }
00892             }
00893 
00894             // set init states
00895             if (gen->ExistsInitState(*cSIt)) 
00896             {
00897                 rGenPart.SetInitState(newstate);
00898             }
00899             // set marked states
00900             if (gen->ExistsMarkedState(*cSIt)) 
00901             {
00902                 rGenPart.SetMarkedState(newstate);
00903             }
00904         }
00905         
00906         if (rGenPart.StateNamesEnabled()) 
00907         {
00908             std::string statename = ostr.str();
00909             if(statename.length()>=1) statename.erase(statename.length()-1);
00910             statename = "{" + statename + "}";
00911             rGenPart.StateName(newstate, statename); 
00912             OP_DF("Bisimulation::partition: new state " << statename);
00913         }
00914     }
00915     // create transition relation
00916     // iterate over all transitions of the original generator
00917     TransSet::Iterator tIt = gen->TransRelBegin();
00918     TransSet::Iterator tItEnd = gen->TransRelEnd();
00919     for (; tIt != tItEnd; ++tIt) 
00920     {
00921         rGenPart.InsEvent(tIt->Ev); // ??
00922         rGenPart.SetTransition(rMapStateToPartition[tIt->X1], tIt->Ev, rMapStateToPartition[tIt->X2]);
00923         OP_DF("Bisimulation::partition: adding transition: X1=" << rGenPart.TStr(*tIt) );
00924     }
00925     OP_DF("Bisimulation::partition: leaving function");
00926 }
00927 
00928 // Bisimulation::partition(rMapStateToPartition, rNewPartitions)
00929 void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, std::vector<Idx>& rNewPartitions)
00930 {
00931     OP_DF("Bisimulation::partition(rMapStateToPartition, rNewPartitions)");
00932     
00933     // this function is equivalent to the other function Bisimulation:partition, but no generator is built from the result
00934     set<Partition*>::iterator roDivIt;
00935     set<Partition*>::iterator roDivItEnd=roDividers.end();
00936     Partition* pFather;
00937     bool done=false;
00938     // choose first entry of roDividers to start the partition refinement
00939     roDivIt=roDividers.begin();
00940     // repeat refinement steps performed by the functions partitionClass and partitionSplitter 
00941     // as long as there are elements in roDividers    
00942     while(done==false)
00943     {
00944         // iterate over roDividers and try to find a coset that has a parent coset B' such that ro is stable w.r.t. B'
00945         // (note that the order in which the dividers are chosen is in principle arbitrary)
00946         while(roDivIt!=roDivItEnd && !roDividers.empty())
00947         {
00948             pFather=(*roDivIt)->pFather;
00949             if(pFather!=NULL)
00950             {
00951                 if(pFather->nonSplitting == true) 
00952                 {
00953                     partitionSplitter(**roDivIt);
00954                     // roDividers might have been manipulated by the function partitionSplitter. Recompute iterators.
00955                     roDivItEnd=roDividers.end();
00956                     roDivIt=roDividers.begin();
00957                     continue;
00958                 }
00959             }
00960             roDivIt++;
00961         }
00962         // no element B' could be found such that ro is stable w.r.t. it, but roDividers is not empty. In that case,
00963         // the first element of roDividers is chosen to serve as a "class" in the bisimulation algorithm. 
00964         if(!roDividers.empty())
00965         {
00966             roDivIt=roDividers.begin();
00967             partitionClass(**roDivIt);
00968             // roDividers might have been manipulated by the function partitionClass. Recompute iterators.
00969             roDivItEnd=roDividers.end();
00970             roDivIt=roDividers.begin();
00971         }
00972         if(roDividers.empty())
00973             done=true;
00974     }
00975 
00976 
00977     // create an index for every coset in ro an write it to vector rNewPartitions
00978     OP_DF("Bisimulation::partition: writing vector rMapStateToPartition");
00979     
00980     Idx newstate;
00981     // loop over all elements of ro
00982     vector<Partition*>::const_iterator cRoIt = ro.begin();
00983     vector<Partition*>::const_iterator cRoItEnd = ro.end();
00984     StateSet::Iterator cSIt;
00985     StateSet::Iterator cSItEnd;
00986     for (; cRoIt != cRoItEnd; ++cRoIt) 
00987     {
00988         Generator dummy;
00989         newstate = dummy.InsState();
00990         rNewPartitions.push_back(newstate);
00991         cSIt=(*cRoIt)->states.Begin();
00992         cSItEnd=(*cRoIt)->states.End();
00993         for ( ; cSIt!=cSItEnd; ++ cSIt) 
00994         {
00995             // map every state in the current coset to the index of this coset by creating an entry in the map rMapStateToPartition
00996             rMapStateToPartition[*cSIt] = newstate;
00997         }
00998     }
00999     OP_DF("Bisimulation::partition: leaving function");
01000 }
01001 
01002 // Bisimulation::writeW()
01003 void Bisimulation::writeW(void)
01004 {
01005     OP_DF("Bisimulation:writeW()");
01006     cout << "Plotting the W-tree:" << endl;
01007     writeNode(W.find(1)->second);
01008 }
01009 
01010 // Bisimulation::writeNode(node)
01011 void Bisimulation::writeNode(Partition& node)
01012 {
01013         OP_DF("Bisimulation::writeNode(" << node.index << ")");
01014         cout << "Coset with index " << node.index << " has the following states:" << endl;
01015         node.states.Write();
01016         if(node.pFather!=NULL)
01017             cout << "Parent coset has index: " << node.pFather->index << endl;
01018         else
01019             cout << "Coset is the root of the tree" << endl;
01020         if(node.pBrother!=NULL)
01021             cout << "Coset has brother coset with index: " << node.pBrother->index << endl;
01022         else
01023             cout << "Coset has no brother" << endl;
01024         if(node.pFirstChild!=NULL && node.pSecondChild!=NULL)
01025             cout << "Child cosets have indices : " << node.pFirstChild->index << " and " << node.pSecondChild->index << endl;
01026         else
01027             cout << "Coset has no children" << endl;
01028         cout << "ro is stable with respect to this coset (1=yes; 0=no): " << node.nonSplitting << endl;
01029         cout << "Info-map of coset: " << endl;
01030         EventSet::Iterator eIt;
01031         for(eIt=gen->AlphabetBegin();eIt != gen->AlphabetEnd(); ++eIt)
01032             node.writeInfoMap(*eIt);
01033 
01034         if(node.pFirstChild!=NULL)
01035             writeNode(*(node.pFirstChild));
01036         if(node.pSecondChild!=NULL)
01037             writeNode(*(node.pSecondChild));
01038 }
01039 
01040 // Bisimulation::writeRo()
01041 void Bisimulation::writeRo(void)
01042 {
01043     OP_DF("Bisimulation::writeRo()");
01044     cout << "The Cosets with the following indices are in ro: " << endl;
01045     vector<Partition*>::iterator roIt;
01046     vector<Partition*>::iterator roItBegin =ro.begin();
01047     vector<Partition*>::iterator roItEnd = ro.end();
01048     for(roIt=roItBegin; roIt!=roItEnd; roIt++)
01049         cout << (*roIt)->index << endl;
01050     cout << endl;
01051 }
01052 
01053 }

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen