op_bisimulation.cppGo 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 |