op_bisimulation.cpp

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

Generated on Fri May 9 11:26:47 2008 for libFAUDES 2.09b by  doxygen 1.4.4