| |
libFAUDES
Sections
Index
|
diag_languagediagnosis.cppGo to the documentation of this file.00001 /** @file diag_languagediagnosis.cpp 00002 Functions to check a system's language-diagnosability and compute a language-diagnoser. 00003 00004 (c) 2009, Tobias Barthel, Thomas Moor, Klaus Schmidt. 00005 */ 00006 00007 #include "diag_languagediagnosis.h" 00008 00009 using namespace std; 00010 00011 namespace faudes { 00012 00013 00014 /////////////////////////////////////////////////////////////////////////////// 00015 // Functions for specification framework 00016 /////////////////////////////////////////////////////////////////////////////// 00017 00018 00019 // rti function interface 00020 void IsLanguageDiagnosable(const cGenerator& rGen, const cGenerator& rSpec, bool& rRes, std::string& rReportString) { 00021 rRes=IsLanguageDiagnosable(rGen,rSpec,rReportString); 00022 } 00023 00024 // rti function interface 00025 void IsLanguageDiagnosable(const cGenerator& rGen, const cGenerator& rSpec, bool& rRes) { 00026 std::string ignore; 00027 rRes=IsLanguageDiagnosable(rGen,rSpec,ignore); 00028 } 00029 00030 00031 // ComputeGobs() 00032 void ComputeGobs(const cGenerator& rGenMarkedNonSpecBehaviour, diagGenerator& rGobs) { 00033 EventSet gObservableEvents, gUnobservableEvents; 00034 StateSet newGobsStates; 00035 Idx currDState = 0; 00036 Idx nextDState = 0; 00037 Idx gStateEstimate = 0; 00038 Idx newState = 0; 00039 map<Idx,multimap<Idx,DiagLabelSet> > reachMap; // maps executable events to all reachable states and occuring relative failure types 00040 map<Idx,multimap<Idx,DiagLabelSet> >::iterator it; 00041 multimap<Idx,DiagLabelSet>::iterator mmit, mmit2; 00042 pair<Idx,DiagLabelSet> reachMapPair; 00043 TransSet transitions; 00044 DiagLabelSet oldLabel, newLabel, occFailureTypes; 00045 DiagLabelSet::Iterator labelIt; 00046 StateSet gObsStates; 00047 StateSet::Iterator stateIt, initStateIt; 00048 EventSet activeEvents; 00049 AttributeDiagnoserState newAttr; 00050 const TaIndexSet<DiagLabelSet>* pDiagState; 00051 00052 FD_DD("ComputeGobs()"); 00053 00054 // clear Gobs 00055 rGobs.Clear(); 00056 rGobs.ClearAttributes(); 00057 00058 // get observable events of original generator 00059 gObservableEvents = rGenMarkedNonSpecBehaviour.ObservableEvents(); 00060 FD_DD( "Observable events: " << gObservableEvents.ToString() ); 00061 00062 // get unobservable events of original generator 00063 gUnobservableEvents = rGenMarkedNonSpecBehaviour.UnobservableEvents(); 00064 FD_DD( "Unobservable events: " << gUnobservableEvents.ToString() ); 00065 00066 // parse through init states of rGenMarkedNonSpecBehaviour 00067 for (initStateIt = rGenMarkedNonSpecBehaviour.InitStatesBegin(); initStateIt != rGenMarkedNonSpecBehaviour.InitStatesEnd(); initStateIt++) { 00068 newGobsStates.Clear(); 00069 newLabel.Clear(); 00070 newAttr.Clear(); 00071 00072 // create newAttr with state index of current initial state of rGenMarkedNonSpecBehaviour and label "N" 00073 newLabel.Insert(DiagLabelSet::IndexOfLabelN()); 00074 newAttr.AddStateLabelMap(*initStateIt,newLabel); 00075 00076 // if newAttr equals any existing state attribute then use this state and make it an initial state 00077 gObsStates = rGobs.States(); 00078 stateIt = gObsStates.Begin(); 00079 while (stateIt != gObsStates.End()) { 00080 if (newAttr == rGobs.StateAttribute(*stateIt)) { 00081 FD_DD("Statelabel " << *initStateIt << "N already exists at state " << *stateIt << " --> make it init state."); 00082 rGobs.SetInitState(*stateIt); 00083 break; 00084 } 00085 stateIt++; 00086 } 00087 // if newAttribute is new to Gobs 00088 if (stateIt == gObsStates.End()) { 00089 // create new initial state of Gobs and its attribute with label "normal" 00090 currDState = rGobs.InsInitState(); 00091 rGobs.StateAttribute(currDState, newAttr); 00092 newGobsStates.Insert(currDState); 00093 } 00094 00095 // parse through new Gobs states 00096 while (!newGobsStates.Empty()) { 00097 // set current Gobs state 00098 currDState = *newGobsStates.Begin(); 00099 00100 // get unique state estimate and unique failure label from Gobs 00101 pDiagState = rGobs.StateAttribute(currDState).DiagnoserStateMapp(); 00102 gStateEstimate = *(pDiagState->Begin()); 00103 oldLabel = pDiagState->Attribute(*(pDiagState->Begin())); 00104 00105 // generate reachMap for current state estimate 00106 ComputeReachability(rGenMarkedNonSpecBehaviour, gUnobservableEvents, gStateEstimate, reachMap); 00107 00108 00109 #ifdef FAUDES_DEBUG_DIAGNOSIS 00110 FD_DD("reachMap: "); 00111 for (it = reachMap.begin(); it != reachMap.end(); it++) { 00112 //print reachMap for current event 00113 FD_DD("_" << rGenMarkedNonSpecBehaviour.EventName(it->first) << " ("<< it->second.size() << " state estimates)"); 00114 for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) { 00115 FD_DD(mmit->first << " " << mmit->second.ToString()); 00116 } 00117 } 00118 #endif 00119 00120 // parse through reachMap (eventwise) 00121 for (it = reachMap.begin(); it != reachMap.end(); it++) { 00122 #ifdef FAUDES_DEBUG_DIAGNOSIS 00123 // print reachMap for current event 00124 FD_DD("Parsing reachMap: " << "_" << rGenMarkedNonSpecBehaviour.EventName(it->first)); 00125 for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) { 00126 FD_DD(mmit->first << " " << mmit->second.ToString()); 00127 } 00128 #endif 00129 00130 FD_DD("old label: " << oldLabel.ToString()); 00131 00132 newState = 0; 00133 // parse through state failure type map (for current event in reachMap) 00134 for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) { 00135 newState = mmit->first; 00136 FD_DD("new state: " << newState); 00137 occFailureTypes = mmit->second; 00138 FD_DD("failure types occurred: " << occFailureTypes.ToString()); 00139 LabelPropagation(oldLabel, occFailureTypes, newLabel); 00140 FD_DD("new label: " << newLabel.ToString()); 00141 newAttr.Clear(); 00142 newAttr.AddStateLabelMap(newState,newLabel); 00143 00144 // if newAttr equals any existing state attribute then we create a transition to this very state 00145 gObsStates = rGobs.States(); 00146 stateIt = gObsStates.Begin(); 00147 while (stateIt != gObsStates.End()) { 00148 if (newAttr == rGobs.StateAttribute(*stateIt)) { 00149 FD_DD("realising as back- or self-loop to existing state " << *stateIt); 00150 if (!rGobs.ExistsTransition(currDState,it->first,*stateIt)) { 00151 if (!rGobs.ExistsEvent(it->first)) { 00152 rGobs.InsEvent(it->first); 00153 } 00154 rGobs.SetTransition(currDState,it->first,*stateIt); 00155 } 00156 break; 00157 } 00158 stateIt++; 00159 } 00160 // if newAttribute is new to Gobs 00161 if (stateIt == gObsStates.End()) { 00162 // create new Gobs state and add it to new states 00163 nextDState = rGobs.InsState(); 00164 FD_DD("Create new state " << nextDState << " and transition " << currDState << " --" << rGenMarkedNonSpecBehaviour.EventName(it->first) << "--> " << nextDState); 00165 newGobsStates.Insert(nextDState); 00166 rGobs.InsEvent(it->first); 00167 rGobs.SetTransition(currDState,it->first,nextDState); 00168 00169 //rGobs.InsStateLabelMap(nextDState,newState,newLabel); 00170 rGobs.StateAttribute(nextDState, newAttr); 00171 } 00172 } 00173 } 00174 00175 activeEvents = rGobs.ActiveEventSet(currDState); 00176 transitions = rGobs.ActiveTransSet(currDState); 00177 00178 // delete current Gobs state from new states 00179 newGobsStates.Erase(currDState); 00180 } 00181 } 00182 } 00183 00184 // ComputeReachability() 00185 void ComputeReachability(const cGenerator& rGen, const EventSet& rUnobsEvents, Idx State, 00186 map<Idx,multimap<Idx,DiagLabelSet> >& rReachabilityMap) { 00187 00188 FD_DD("ComputeReachability() for state " << State << "..."); 00189 StateSet doneStates; 00190 00191 doneStates.Clear(); 00192 rReachabilityMap.clear(); 00193 ComputeReachabilityRecursive(rGen, rUnobsEvents, State, doneStates, rReachabilityMap); 00194 FD_DD("ComputeReachability for state " << State << ": done"); 00195 00196 #ifdef FAUDES_DEBUG_DIAGNOSIS 00197 map<Idx,multimap<Idx,DiagLabelSet> >::iterator it; 00198 multimap<Idx,DiagLabelSet>::iterator mmLabelIt; 00199 FD_DD("rReachabilityMap: "); 00200 for (it = rReachabilityMap.begin(); it != rReachabilityMap.end(); it++) { 00201 // print rReachabilityMap for current event 00202 FD_DD("_" << rGen.EventName(it->first) << " ("<< it->second.size() << " state estimates)"); 00203 for (mmLabelIt = it->second.begin(); mmLabelIt != it->second.end(); mmLabelIt++) { 00204 FD_DD(mmLabelIt->first << " " << mmLabelIt->second.ToString()); 00205 } 00206 } 00207 FD_DD(""); 00208 #endif 00209 } 00210 00211 // ComputeReachabilityRecursive() 00212 void ComputeReachabilityRecursive(const cGenerator& rGen, const EventSet& rUnobsEvents, Idx State, StateSet done, 00213 map<Idx,multimap<Idx,DiagLabelSet> >& rReachabilityMap) { 00214 TransSet trans; 00215 TransSet::Iterator tIt; 00216 EventSet tmpFailureSet; 00217 EventSet::Iterator evIt; 00218 multimap<Idx,DiagLabelSet> stateFailureTypeMap; // maps generator states onto occurred failures types (=labels), part of rReachabilityMap 00219 multimap<Idx,DiagLabelSet>::iterator mmLabelIt; 00220 map<Idx,multimap<Idx,DiagLabelSet> >::iterator it; 00221 DiagLabelSet newFT; 00222 bool mappingExists; 00223 00224 if (done.Exists(State)) { 00225 FD_DD( "State " << State << " has already been processed." ); 00226 return; 00227 } 00228 trans = rGen.ActiveTransSet(State); 00229 00230 FD_DD("ComputeReachabilityRecursive() for state " << State << ": Events in ActiveTransSet: "); 00231 // parse through active transitions of current generator state 00232 for (tIt = trans.Begin(); tIt != trans.End(); tIt++) { 00233 FD_DD(tIt->X1 << "--" << rGen.EventName(tIt->Ev) << "-->" << tIt->X2); 00234 // if current event is unobservable 00235 if (rUnobsEvents.Exists(tIt->Ev)) { 00236 // call ComputeReachabilityRecursive for successor state 00237 done.Insert(tIt->X1); 00238 ComputeReachabilityRecursive(rGen, rUnobsEvents, tIt->X2, done, rReachabilityMap); 00239 } 00240 // if current event is observable add failure (spec violation) to rReachabilityMap 00241 else { 00242 FD_DD(rGen.EventName(tIt->Ev) << " is observable: add it to rReachabilityMap "); 00243 // get old entry of rReachabilityMap if it exists 00244 stateFailureTypeMap.clear(); 00245 if (rReachabilityMap.find(tIt->Ev) != rReachabilityMap.end()) { 00246 stateFailureTypeMap = rReachabilityMap[tIt->Ev]; 00247 #ifdef FAUDES_DEBUG_DIAGNOSIS 00248 FD_DD("old entry of rReachabilityMap for " << rGen.EventName(tIt->Ev)); 00249 for (mmLabelIt = stateFailureTypeMap.begin(); mmLabelIt != stateFailureTypeMap.end(); mmLabelIt++) { 00250 FD_DD(mmLabelIt->first << " " << mmLabelIt->second.ToString()); 00251 } 00252 #endif 00253 } 00254 newFT.Clear(); 00255 // if successor state is marked: add failure label 00256 if (rGen.ExistsMarkedState(tIt->X2)) { 00257 newFT.Insert(DiagLabelSet::IndexOfLabelSpecViolated()); 00258 } 00259 // if no failure occurred add normal label 00260 if (newFT.Empty()) { 00261 newFT.Insert(DiagLabelSet::IndexOfLabelRelN()); 00262 } 00263 // check if new mapping does already exist 00264 mappingExists = false; 00265 for (mmLabelIt = stateFailureTypeMap.lower_bound(tIt->X2); mmLabelIt != stateFailureTypeMap.upper_bound(tIt->X2); mmLabelIt++) { 00266 if (mmLabelIt->second == newFT) { 00267 mappingExists = true; 00268 } 00269 } 00270 // if new mapping does not yet exist: add it to rReachabilityMap 00271 if (!mappingExists) { 00272 stateFailureTypeMap.insert(pair<Idx,DiagLabelSet>(tIt->X2,newFT)); 00273 rReachabilityMap[tIt->Ev] = stateFailureTypeMap; 00274 } 00275 } 00276 } 00277 } 00278 00279 // ComputeLanguageDiagnoser() 00280 void ComputeLanguageDiagnoser(const cGenerator& rGen, const cGenerator& rSpec, diagGenerator& rDiagGen) { 00281 cGenerator genMarkedNonSpecBehaviour, specComplement; 00282 diagGenerator genGobs; 00283 00284 FD_DD("ComputeLanguageDiagnoser()"); 00285 00286 // copy const arguments 00287 cGenerator gen = rGen; 00288 cGenerator spec = rSpec; 00289 00290 // prepare result 00291 rDiagGen.Clear(); 00292 00293 // mark all states in generator and specification 00294 StateSet::Iterator sit; 00295 for (sit = gen.StatesBegin(); sit != gen.StatesEnd(); sit++) 00296 gen.SetMarkedState(*sit); 00297 for (sit = spec.StatesBegin(); sit != spec.StatesEnd(); sit++) 00298 spec.SetMarkedState(*sit); 00299 00300 // lift spec to same alphabet (insert missing events) 00301 EventSet diffEventsGenAndSpec = gen.Alphabet() - spec.Alphabet(); 00302 FD_DD("diffEventsGenAndSpec: " << diffEventsGenAndSpec.ToString() ); 00303 spec.InsEvents(diffEventsGenAndSpec); 00304 00305 // figure failure behaviour Gtilde= Closure(G) ^ Complement(Closure(Specification)) 00306 // technical note: to obtain a diagnoser that refers to G state indicees, we use the reverse 00307 // composition map to track the correspondance to the original state space. 00308 specComplement = spec; 00309 LanguageComplement(specComplement); 00310 std::map< std::pair<Idx,Idx>, Idx> rcmap; 00311 Parallel(gen, specComplement, rcmap, genMarkedNonSpecBehaviour); 00312 std::map<Idx, Idx> gen1cmap; 00313 CompositionMap1(rcmap,gen1cmap); 00314 rcmap.clear(); 00315 00316 genMarkedNonSpecBehaviour.ClrObservable(gen.UnobservableEvents()); 00317 #ifdef FAUDES_DEBUG_DIAGNOSIS 00318 genMarkedNonSpecBehaviour.GraphWrite("tmp_wrtb_Gtilde_spec.png"); 00319 genMarkedNonSpecBehaviour.Write("tmp_wrtb_Gtilde_spec.gen"); 00320 #endif 00321 00322 // bail out trivial case "no failures" 00323 if (genMarkedNonSpecBehaviour.MarkedStatesEmpty()) { 00324 rDiagGen.InjectAlphabet(gen.ObservableEvents()); 00325 Idx dstate = rDiagGen.InsInitState(); 00326 // TODO: loop over all possible states 00327 rDiagGen.InsStateLabelMapping(dstate,rGen.InitState(),DiagLabelSet::IndexOfLabelN()); 00328 SelfLoop(rDiagGen,gen.ObservableEvents()); 00329 return; 00330 } 00331 00332 // compute the observer, i.e. non-deterministic basis for diagnoser 00333 ComputeGobs(genMarkedNonSpecBehaviour, genGobs); 00334 00335 #ifdef FAUDES_DEBUG_DIAGNOSIS 00336 genGobs.GraphWrite("tmp_wrtb_gobs.png"); 00337 #endif 00338 00339 00340 // post process 00341 // We construct a deterministic diagnoser from the non-deterministic GObs by 00342 // parsing the transition structure of GObs and merging possible diagnosis 00343 // labels. 00344 00345 // have all observable events 00346 rDiagGen.InjectAlphabet(gen.ObservableEvents()); 00347 00348 00349 // create initial state of diagnoser and its attribute with label "normal" 00350 #ifdef FAUDES_CHECKED 00351 if(genGobs.InitStatesSize() != 1) { 00352 std::stringstream errstr; 00353 errstr << "Diagnosis: Internal Error: Go must have one initial state only" << std::endl; 00354 throw Exception("ComputeLanguageDiagnoser()", errstr.str(), 301); 00355 } 00356 #endif 00357 Idx gInitState = genGobs.InitState(); 00358 Idx dInitState = rDiagGen.InsInitState(); 00359 rDiagGen.InsStateLabelMapping(dInitState,gInitState,DiagLabelSet::IndexOfLabelN()); 00360 00361 // track state correspondence (map diagnoser states to genObs states) 00362 std::multimap<Idx,Idx> dgmap; 00363 dgmap.insert(std::pair<Idx,Idx>(dInitState,gInitState)); 00364 00365 // loop variables 00366 EventSet activeEvents; 00367 AttributeDiagnoserState newDAttr; 00368 00369 // parse through gObsStates states 00370 StateSet dStates; 00371 dStates.Insert(dInitState); 00372 while (!dStates.Empty()) { 00373 // set current diagnoser state 00374 Idx dstate = *dStates.Begin(); 00375 // prepare reachmap: ev -> gSuccessors 00376 std::multimap<Idx,Idx> gSuccessors; 00377 // iterate over corresponding genObs States 00378 std::multimap<Idx,Idx>::iterator gsit= dgmap.lower_bound(dstate); 00379 std::multimap<Idx,Idx>::iterator gsit_end= dgmap.upper_bound(dstate); 00380 for(;gsit!=gsit_end; gsit++) { 00381 Idx gState = gsit->second; 00382 // iterate over all successors 00383 TransSet::Iterator tit= genGobs.TransRelBegin(gState); 00384 TransSet::Iterator tit_end= genGobs.TransRelEnd(gState); 00385 for(; tit!=tit_end; tit++) 00386 gSuccessors.insert(std::pair<Idx,Idx>(tit->Ev,tit->X2)); 00387 } 00388 // per event, accumulate estimates 00389 gsit= gSuccessors.begin(); 00390 gsit_end= gSuccessors.end(); 00391 std::multimap<Idx,Idx>::iterator gsit_beg= gsit; 00392 newDAttr.Clear(); 00393 while(gsit!=gsit_end) { 00394 Idx ev= gsit->first; 00395 // TODO: need merge method for diagnoser estimates 00396 const AttributeDiagnoserState sestimate= genGobs.StateAttribute(gsit->second); 00397 StateSet::Iterator lit=sestimate.DiagnoserStateMap().Begin(); 00398 StateSet::Iterator lit_end=sestimate.DiagnoserStateMap().End(); 00399 for(; lit!=lit_end; lit++) { 00400 //newDAttr.AddStateLabelMap(*lit, sestimate.DiagnoserStateMap().Attribute(*lit)); 00401 newDAttr.AddStateLabelMap(gen1cmap[*lit], sestimate.DiagnoserStateMap().Attribute(*lit)); 00402 } 00403 // increment 00404 gsit++; 00405 // sense new event to set label 00406 bool nextev=false; 00407 if(gsit== gsit_end) nextev=true; 00408 if(gsit!= gsit_end) if(gsit->first!=ev) nextev=true; 00409 if(!nextev) continue; 00410 // insert new diag state set attribute 00411 // case 1: attribute exists, so use the corresponding diagnoser state 00412 // note: rather hold a map rather than to iterate over all attributes 00413 StateSet::Iterator sit= rDiagGen.StatesBegin(); 00414 StateSet::Iterator sit_end= rDiagGen.StatesEnd(); 00415 for(; sit!=sit_end; sit++) { 00416 if(!(newDAttr == rDiagGen.StateAttribute(*sit))) continue; 00417 FD_DD("ComputeLanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,*sit))); 00418 rDiagGen.SetTransition(dstate,ev,*sit); 00419 break; 00420 } 00421 // case 2: attribute does not exist, so insert new diagnoser state 00422 if(sit==sit_end) { 00423 // insert new dstate 00424 Idx newDState=rDiagGen.InsState(); 00425 dStates.Insert(newDState); 00426 rDiagGen.StateAttribute(newDState,newDAttr); 00427 FD_DD("ComputeLanguageDiagnoser(): insert state with attr " << newDAttr.Str()); 00428 // track corresponding gstates 00429 std::multimap<Idx,Idx>::iterator gesit= gsit_beg; 00430 for(;gesit!=gsit;gesit++) { 00431 FD_DD("ComputeLanguageDiagnoser(): corresponding gstate " << gesit->second); 00432 dgmap.insert(std::pair<Idx,Idx>(newDState,gesit->second)); 00433 } 00434 // insert transition 00435 FD_DD("ComputeLanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,newDState))); 00436 rDiagGen.SetTransition(dstate,ev,newDState); 00437 } 00438 // initialise per event variables in multimap loop 00439 gsit_beg=gsit; 00440 newDAttr.Clear(); 00441 } 00442 // delete current state from todo list 00443 dStates.Erase(dstate); 00444 } 00445 00446 #ifdef FAUDES_DEBUG_DIAGNOSIS 00447 rDiagGen.GraphWrite("tmp_wrtb_diag.png"); 00448 #endif 00449 } 00450 00451 00452 // IsLanguageDiagnosable 00453 bool IsLanguageDiagnosable(const cGenerator& rGen, const cGenerator rSpec, std::string& rReportString){ 00454 FD_DD("IsLanguageDiagnosable()"); 00455 EventSet obsEvents = rGen.ObservableEvents(); 00456 #ifdef FAUDES_DEBUG_DIAGNOSIS 00457 obsEvents.DWrite(); 00458 #endif 00459 Generator verifier; // Graph for diagnosability verification 00460 Idx nullEvent = verifier.InsEvent("nullEvent"); // event that corresponds to the value 0 00461 Idx negEvent = verifier.InsEvent("negEvent"); // event that corresponds to the value -1 00462 //Generator verifierTest; // verifier with eeent information 00463 //verifierTest.InjectAlphabet(rGen.Alphabet() ); // FIXME remove this. 00464 //verifierTest.InsEvent(nullEvent); 00465 map<Idx, VerifierState> stateToVerifierMap; 00466 map<VerifierState, Idx> verifierToStateMap; 00467 stack<pair<Idx, VerifierState> > waitingStates; 00468 StateSet doneStates; 00469 // initialize the algorithm 00470 EventSet fullAlphabet = rGen.Alphabet(); 00471 EventSet::Iterator eIt, eEndIt; 00472 eEndIt = fullAlphabet.End(); 00473 Idx newState = verifier.InsInitState(); 00474 //verifierTest.InsInitState(newState); 00475 VerifierState newVerifierState = VerifierState(rSpec.InitState(), rSpec.InitState(), rGen.InitState(),NORMAL); 00476 stateToVerifierMap[newState] = newVerifierState; 00477 verifierToStateMap[newVerifierState ] = newState; 00478 waitingStates.push(make_pair(newState, newVerifierState) ); 00479 // extend the verifier graph until no new nodes can be added 00480 pair<Idx, VerifierState> currentState; 00481 Idx blockingState; // = verifier.InsMarkedState(); 00482 TransSet::Iterator tIt; 00483 map<VerifierState, Idx>::const_iterator vsIt; 00484 Idx X2; 00485 bool block = false; // set to true if the BLOCK state is reachable 00486 FD_DD("Main loop"); 00487 while(waitingStates.empty() == false){ 00488 // take the first element from the stack 00489 currentState = waitingStates.top(); 00490 waitingStates.pop(); 00491 doneStates.Insert(currentState.first); 00492 FD_DD("currentState: " + ToStringInteger(currentState.first) + " VerifierState: (" + rSpec.StateName(currentState.second.mSpec1State) + "," + rSpec.StateName(currentState.second.mSpec2State) + "," + rGen.StateName(currentState.second.mPlantState) + "," + ToStringInteger(currentState.second.mLabel) + ")"); 00493 // go over all possible events 00494 eIt = fullAlphabet.Begin(); 00495 for(; eIt != eEndIt; eIt++){ 00496 // if the event is not observable, the specification and the plant can evolve independently 00497 if(obsEvents.Exists(*eIt) == false){ 00498 tIt = rSpec.TransRelBegin(currentState.second.mSpec1State,*eIt); 00499 // transition in Spec1 exists 00500 if(tIt != rSpec.TransRelEnd(currentState.second.mSpec1State,*eIt) ){ 00501 if(currentState.second.mLabel == NORMAL ){ // transition in spec1 from normal state 00502 newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, NORMAL); 00503 } 00504 else // transition in spec1 from confused state 00505 newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, CONFUSED); 00506 // check if the new VerifierState already exist snd insert new transitions (rule 1 and 4) 00507 vsIt = verifierToStateMap.find(newVerifierState); 00508 // a new state is inserted into the verifier 00509 if(vsIt == verifierToStateMap.end() ){ 00510 newState = verifier.InsState(); 00511 //verifierTest.InsState(newState); 00512 verifier.SetTransition(currentState.first,nullEvent,newState); 00513 //verifierTest.SetTransition(currentState.first,*eIt,newState); 00514 verifierToStateMap[newVerifierState] = newState; 00515 stateToVerifierMap[newState] = newVerifierState; 00516 if(doneStates.Exists(newState) == false) 00517 waitingStates.push(make_pair(newState,newVerifierState) ); 00518 } 00519 // a transition to the existing state is added 00520 else{ 00521 //verifierTest.SetTransition(currentState.first,*eIt,vsIt->second); 00522 verifier.SetTransition(currentState.first,nullEvent,vsIt->second); 00523 00524 } 00525 } 00526 tIt = rGen.TransRelBegin(currentState.second.mPlantState,*eIt); 00527 // transition in plant exists 00528 if(tIt != rGen.TransRelEnd(currentState.second.mPlantState,*eIt) ){ 00529 X2 = tIt->X2; 00530 if(currentState.second.mLabel == CONFUSED) 00531 newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED); 00532 else{ // current state is NORMAL 00533 tIt = rSpec.TransRelBegin(currentState.second.mSpec2State,*eIt); 00534 if(tIt == rSpec.TransRelEnd(currentState.second.mSpec2State,*eIt) ){ // violation of the specification 00535 newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED); 00536 } 00537 else{ // correct behavior 00538 newVerifierState = VerifierState(currentState.second.mSpec1State, tIt->X2, X2, NORMAL); 00539 } 00540 } 00541 // check if a new state has to be inserted into the verifier a 00542 vsIt = verifierToStateMap.find(newVerifierState); 00543 // a new state is inserted into the verifier 00544 if(vsIt == verifierToStateMap.end() ){ 00545 newState = verifier.InsState(); 00546 //verifierTest.InsState(newState); 00547 verifierToStateMap[newVerifierState] = newState; 00548 stateToVerifierMap[newState] = newVerifierState; 00549 if(doneStates.Exists(newState) == false) 00550 waitingStates.push(make_pair(newState,newVerifierState) ); 00551 } 00552 else 00553 newState = vsIt->second; 00554 // new transition in the verifier 00555 if(newVerifierState.mLabel == NORMAL || (currentState.second.mLabel == CONFUSED && newVerifierState.mPlantState == currentState.second.mPlantState) ){ // normal behavior or confused behavior extended in the specification (rule 3 or 4) 00556 //verifierTest.SetTransition(currentState.first,*eIt,newState); 00557 verifier.SetTransition(currentState.first,nullEvent,newState); 00558 } 00559 else{ // faulty behavior extended in the plant (rule 5) 00560 //verifierTest.SetTransition(currentState.first,*eIt,newState); 00561 verifier.SetTransition(currentState.first,negEvent,newState); 00562 } 00563 } 00564 }// (obsEvents.Exists(*eIt) == false) 00565 else{ 00566 TransSet::Iterator plantIt, specIt; 00567 Idx eventIdx; 00568 tIt = rSpec.TransRelBegin(currentState.second.mSpec1State, *eIt); 00569 plantIt= rGen.TransRelBegin(currentState.second.mPlantState, *eIt); 00570 specIt = rSpec.TransRelBegin(currentState.second.mSpec2State, *eIt); 00571 if(tIt != rSpec.TransRelEnd(currentState.second.mSpec1State, *eIt) && plantIt != rGen.TransRelEnd(currentState.second.mPlantState, *eIt) ){ // event occurs in the potentially confused specification and in the plant 00572 if(currentState.second.mLabel == NORMAL && specIt != rSpec.TransRelEnd(currentState.second.mSpec2State, *eIt) ){ // no confusion (rule 6) 00573 newVerifierState = VerifierState(tIt->X2, specIt->X2, plantIt->X2, NORMAL); 00574 eventIdx = nullEvent; 00575 } 00576 else if(currentState.second.mLabel == NORMAL){// faulty behavior occurs (rule 7) 00577 newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED); 00578 eventIdx = negEvent; 00579 } 00580 else{ // there is already confusion (rule 8) 00581 newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED); 00582 eventIdx = negEvent; 00583 } 00584 // check if a new state has to be inserted into the verifier a 00585 vsIt = verifierToStateMap.find(newVerifierState); 00586 // a new state is inserted into the verifier 00587 if(vsIt == verifierToStateMap.end() ){ 00588 newState = verifier.InsState(); 00589 //verifierTest.InsState(newState); 00590 verifierToStateMap[newVerifierState] = newState; 00591 stateToVerifierMap[newState] = newVerifierState; 00592 if(doneStates.Exists(newState) == false) 00593 waitingStates.push(make_pair(newState,newVerifierState) ); 00594 } 00595 else 00596 newState = vsIt->second; 00597 00598 // update the verifier 00599 //verifierTest.SetTransition(currentState.first,*eIt,newState); 00600 verifier.SetTransition(currentState.first,eventIdx,newState); 00601 } 00602 } 00603 } 00604 // check if the Block state is reachable 00605 if(rGen.TransRelBegin(currentState.second.mPlantState) == rGen.TransRelEnd(currentState.second.mPlantState) && currentState.second.mLabel == CONFUSED){ 00606 blockingState = verifier.InsMarkedState(); 00607 verifier.SetTransition(currentState.first,nullEvent,blockingState); 00608 //verifierTest.InsMarkedState(blockingState); 00609 //verifierTest.SetTransition(currentState.first,nullEvent,blockingState); 00610 FD_DD("Blocking State Reachable"); 00611 block = true; 00612 } 00613 } 00614 #ifdef FAUDES_DEBUG_DIAGNOSIS 00615 verifier.GraphWrite("data/verifier.png"); 00616 #endif 00617 //verifierTest.GraphWrite("data/verifierTest.png"); 00618 // Seach for cycles with "-1"-transitions (negEvent) in the verifier 00619 list<StateSet> sccList; 00620 StateSet rootSet; 00621 // compute the strongly connected components in the verifier 00622 ComputeScc(verifier,sccList,rootSet); 00623 // Check if there is a "-1"-transition in any of the SCCs 00624 list<StateSet>::const_iterator sccIt, sccEndIt; 00625 sccIt = sccList.begin(); 00626 sccEndIt = sccList.end(); 00627 StateSet::Iterator stIt, stEndIt; 00628 bool existsCycle = false; 00629 for( ; sccIt != sccEndIt; sccIt++){ 00630 #ifdef FAUDES_DEBUG_DIAGNOSIS 00631 sccIt->Write(); 00632 #endif 00633 stIt = sccIt->Begin(); 00634 stEndIt = sccIt->End(); 00635 for(; stIt != stEndIt; stIt++){// check all states in the SCC 00636 tIt = verifier.TransRelBegin(*stIt, negEvent); 00637 if(tIt != verifier.TransRelEnd(*stIt, negEvent) && sccIt->Exists(tIt->X2) ){ // there is a transition with negEvent within the SCC 00638 FD_DD("Confused Cycle Found"); 00639 existsCycle = true; 00640 break; 00641 } 00642 } 00643 if(existsCycle == true) 00644 break; 00645 } 00646 if(block == true || existsCycle == true) 00647 return false; 00648 else 00649 return true; 00650 } 00651 00652 //IsLoopPreservingObserver() 00653 bool IsLoopPreservingObserver(const cGenerator& rGen, const EventSet& rHighAlph){ 00654 cGenerator genCopy; 00655 TransSet::Iterator tit; 00656 string report; 00657 FD_DD("IsLoopPreservingObserver()"); 00658 genCopy = rGen; 00659 genCopy.InjectMarkedStates(genCopy.States() ); 00660 // Verify if the observer condition is fulfilled 00661 if(IsObs(genCopy,rHighAlph) == false){ 00662 FD_DD("Observer Condition violated"); 00663 return false; 00664 } 00665 FD_DD("Observer Condition fulfilled"); 00666 // Verify if there are loops with abstracted events 00667 // delete all transitions that do not belong to local high-alphabet 00668 for (tit = genCopy.TransRelBegin(); tit != genCopy.TransRelEnd();) { 00669 if (rHighAlph.Exists(tit->Ev)) 00670 tit=genCopy.ClrTransition(tit); 00671 else 00672 ++tit; 00673 } 00674 // search for cycles in remainder automaton 00675 std::list<StateSet> sccList; 00676 StateSet sccRoots; 00677 ComputeScc(genCopy,sccList,sccRoots); 00678 std::list<StateSet>::const_iterator sIt = sccList.begin(); 00679 for( ; sIt != sccList.end(); sIt++){ 00680 if(sIt->Size() > 1){ 00681 #ifdef FAUDES_DEBUG_DIAGNOSIS 00682 cout << "Bad states that form a cycle with abstracted events: " << endl; 00683 StateSet::Iterator stIt = sIt->Begin(); 00684 for(; stIt != sIt->End(); stIt++) 00685 cout << *stIt << " "; 00686 cout << endl; 00687 #endif 00688 return false; 00689 } 00690 } 00691 return true; 00692 } 00693 00694 //IsLoopPreservingObserver() 00695 void IsLoopPreservingObserver(const cGenerator& rGen, const EventSet& rHighAlph, bool& rRes){ 00696 rRes = IsLoopPreservingObserver(rGen,rHighAlph); 00697 } 00698 00699 void ComputeLoopPreservingObserver(const cGenerator& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph){ 00700 // Verify if the projection with the given initial alphabet is already a loop-preserving observer 00701 rHighAlph = rInitialHighAlph; 00702 rHighAlph.Name("HiAlph"); 00703 FD_DD("ComputeLoopPreservingObserver()"); 00704 if(IsLoopPreservingObserver(rGen,rHighAlph) == true) 00705 return; 00706 00707 // check all combinations of events from the difference set 00708 EventSet diffSet = rGen.Alphabet() - rHighAlph; 00709 EventSet::Iterator eIt = diffSet.Begin(); 00710 std::vector<Idx> diffVector; 00711 for( ; eIt != diffSet.End(); eIt++) // ordered list of events in the diffSet 00712 diffVector.push_back(*eIt); 00713 00714 for(Idx numberEvents = 1; numberEvents <= diffVector.size(); numberEvents++){// number events that are chosen in this step 00715 FD_DD("numberEvents: " + ToStringInteger(numberEvents)); 00716 Idx currentNumberEvents = 1; // number of events under investigation 00717 Idx currentLocation = 0; // start position for the search for new events 00718 EventSet chosenEvents; 00719 if(rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,diffVector,numberEvents,currentNumberEvents,currentLocation,chosenEvents) == true) 00720 break; 00721 } 00722 // fix name 00723 rHighAlph.Name("HiAlph"); 00724 } 00725 00726 // rec_ComputeLoopPreservingObserver(rGen, 00727 bool rec_ComputeLoopPreservingObserver(const cGenerator& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph, const std::vector<Idx>& rDiffVector, Idx numberEvents, Idx currentNumberEvents, Idx currentLocation, EventSet chosenEvents){ 00728 FD_DD("rec_ComputeLoopPreservingObserver()"); 00729 bool valid; 00730 for(Idx i = currentLocation; i < rDiffVector.size(); i++){ 00731 FD_DD("currentNumberEvents: " + ToStringInteger(currentNumberEvents) + "currentLocation: " + ToStringInteger(i) + " event: " + SymbolTable::GlobalEventSymbolTablep()->Symbol(rDiffVector[i])); 00732 chosenEvents.Insert(rDiffVector[i]); 00733 rHighAlph = rInitialHighAlph + chosenEvents; 00734 if(currentNumberEvents == numberEvents){// enough events found 00735 valid = IsLoopPreservingObserver(rGen,rHighAlph); 00736 if(valid == true){ 00737 return true; 00738 } 00739 } 00740 else if(rDiffVector.size() - 1 - i < numberEvents - currentNumberEvents){ // not enough events left to find numberEvents 00741 return false; 00742 } 00743 else{// go to the next level to add events 00744 FD_DD("currentLevel: " + ToStringInteger(i)); 00745 valid = rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,rDiffVector,numberEvents,currentNumberEvents + 1,i + 1, chosenEvents); 00746 if(valid == true){ 00747 return true; 00748 } 00749 } 00750 chosenEvents.Erase(rDiffVector[i]); 00751 } 00752 return false; 00753 } 00754 00755 } // namespace faudes |
libFAUDES 2.14g --- 2009-12-3 --- c++ source docu by doxygen 1.5.6