diag_languagediagnosis.cpp

Go 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