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