libFAUDES

Sections

Index

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 cGenerator& rGen, const cGenerator& rSpec) {
00021   std::string ignore;
00022   return IsLanguageDiagnosable(rGen,rSpec,ignore);
00023 }
00024 
00025 
00026 // ComputeGobs()
00027 void ComputeGobs(const cGenerator& rGenMarkedNonSpecBehaviour, diagGenerator& 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 cGenerator& 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 cGenerator& 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 ComputeLanguageDiagnoser(const cGenerator& rGen, const cGenerator& rSpec, diagGenerator& rDiagGen) {
00276   cGenerator genMarkedNonSpecBehaviour, specComplement;
00277   diagGenerator genGobs;
00278   
00279   FD_DD("ComputeLanguageDiagnoser()");
00280 
00281   // copy const arguments
00282   cGenerator gen = rGen;
00283   cGenerator 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   std::map< std::pair<Idx,Idx>, Idx> rcmap;
00306   Parallel(gen, specComplement, rcmap, genMarkedNonSpecBehaviour);
00307   std::map<Idx, Idx> gen1cmap;
00308   CompositionMap1(rcmap,gen1cmap);
00309   rcmap.clear();
00310 
00311   genMarkedNonSpecBehaviour.ClrObservable(gen.UnobservableEvents());
00312 #ifdef FAUDES_DEBUG_DIAGNOSIS
00313   genMarkedNonSpecBehaviour.GraphWrite("tmp_wrtb_Gtilde_spec.png");
00314   genMarkedNonSpecBehaviour.Write("tmp_wrtb_Gtilde_spec.gen");
00315 #endif
00316   
00317   // bail out trivial case "no failures"
00318   if (genMarkedNonSpecBehaviour.MarkedStatesEmpty()) {
00319     rDiagGen.InjectAlphabet(gen.ObservableEvents());
00320     Idx dstate = rDiagGen.InsInitState();
00321     // TODO: loop over all possible states
00322     rDiagGen.InsStateLabelMapping(dstate,rGen.InitState(),DiagLabelSet::IndexOfLabelN());
00323     SelfLoop(rDiagGen,gen.ObservableEvents());
00324     return;
00325   }
00326 
00327   // compute the observer, i.e. non-deterministic basis for diagnoser  
00328   ComputeGobs(genMarkedNonSpecBehaviour, genGobs);
00329 
00330 #ifdef FAUDES_DEBUG_DIAGNOSIS
00331   genGobs.GraphWrite("tmp_wrtb_gobs.png");
00332 #endif
00333  
00334 
00335   // post process
00336   // We construct a deterministic diagnoser from the non-deterministic GObs by
00337   // parsing the transition structure of GObs and merging possible diagnosis 
00338   // labels.
00339 
00340   // have all observable events
00341   rDiagGen.InjectAlphabet(gen.ObservableEvents());
00342 
00343 
00344   // create initial state of diagnoser and its attribute with label "normal"
00345 #ifdef FAUDES_CHECKED
00346   if(genGobs.InitStatesSize() != 1) {    
00347     std::stringstream errstr;
00348     errstr << "Diagnosis: Internal Error: Go must have one initial state only" << std::endl;
00349     throw Exception("ComputeLanguageDiagnoser()", errstr.str(), 301);
00350   }
00351 #endif
00352   Idx gInitState = genGobs.InitState();
00353   Idx dInitState = rDiagGen.InsInitState();
00354   rDiagGen.InsStateLabelMapping(dInitState,gInitState,DiagLabelSet::IndexOfLabelN());
00355 
00356   // track state correspondence (map diagnoser states to genObs states)
00357   std::multimap<Idx,Idx> dgmap; 
00358   dgmap.insert(std::pair<Idx,Idx>(dInitState,gInitState));
00359 
00360   // loop variables  
00361   EventSet activeEvents;
00362   AttributeDiagnoserState newDAttr;
00363 
00364   // parse through gObsStates states
00365   StateSet dStates;
00366   dStates.Insert(dInitState);
00367   while (!dStates.Empty()) {
00368     // set current diagnoser state 
00369     Idx dstate = *dStates.Begin(); 
00370     // prepare reachmap: ev -> gSuccessors
00371     std::multimap<Idx,Idx> gSuccessors;
00372     // iterate over corresponding genObs States  
00373     std::multimap<Idx,Idx>::iterator gsit= dgmap.lower_bound(dstate);    
00374     std::multimap<Idx,Idx>::iterator gsit_end= dgmap.upper_bound(dstate);
00375     for(;gsit!=gsit_end; gsit++) {    
00376       Idx gState = gsit->second;
00377       // iterate over all successors
00378       TransSet::Iterator tit= genGobs.TransRelBegin(gState);
00379       TransSet::Iterator tit_end= genGobs.TransRelEnd(gState);
00380       for(; tit!=tit_end; tit++)  
00381   gSuccessors.insert(std::pair<Idx,Idx>(tit->Ev,tit->X2)); 
00382     }
00383     // per event, accumulate estimates
00384     gsit= gSuccessors.begin();
00385     gsit_end= gSuccessors.end();
00386     std::multimap<Idx,Idx>::iterator gsit_beg= gsit;
00387     newDAttr.Clear();
00388     while(gsit!=gsit_end) {
00389       Idx ev= gsit->first;
00390       // TODO: need merge method for diagnoser estimates
00391       const AttributeDiagnoserState sestimate= genGobs.StateAttribute(gsit->second);
00392       StateSet::Iterator lit=sestimate.DiagnoserStateMap().Begin();
00393       StateSet::Iterator lit_end=sestimate.DiagnoserStateMap().End();
00394       for(; lit!=lit_end; lit++) {
00395         //newDAttr.AddStateLabelMap(*lit, sestimate.DiagnoserStateMap().Attribute(*lit)); 
00396         newDAttr.AddStateLabelMap(gen1cmap[*lit], sestimate.DiagnoserStateMap().Attribute(*lit)); 
00397       }
00398       // increment 
00399       gsit++;
00400       // sense new event to set label
00401       bool nextev=false;
00402       if(gsit== gsit_end) nextev=true;
00403       if(gsit!= gsit_end) if(gsit->first!=ev) nextev=true;
00404       if(!nextev) continue;
00405       // insert new diag state set attribute
00406       // case 1: attribute exists, so use the corresponding diagnoser state
00407       // note: rather hold a map rather than to iterate over all attributes
00408       StateSet::Iterator sit= rDiagGen.StatesBegin();
00409       StateSet::Iterator sit_end= rDiagGen.StatesEnd();
00410       for(; sit!=sit_end; sit++) {
00411         if(!(newDAttr == rDiagGen.StateAttribute(*sit))) continue; 
00412         FD_DD("ComputeLanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,*sit)));
00413         rDiagGen.SetTransition(dstate,ev,*sit); 
00414         break;
00415       }
00416       // case 2: attribute does not exist, so insert new diagnoser state
00417       if(sit==sit_end) {
00418         // insert new dstate
00419         Idx newDState=rDiagGen.InsState();
00420         dStates.Insert(newDState);
00421         rDiagGen.StateAttribute(newDState,newDAttr);
00422         FD_DD("ComputeLanguageDiagnoser(): insert state with attr " << newDAttr.Str());
00423         // track corresponding gstates
00424         std::multimap<Idx,Idx>::iterator gesit= gsit_beg;
00425         for(;gesit!=gsit;gesit++) {
00426           FD_DD("ComputeLanguageDiagnoser(): corresponding gstate " << gesit->second);
00427     dgmap.insert(std::pair<Idx,Idx>(newDState,gesit->second));          
00428         }
00429         // insert transition
00430         FD_DD("ComputeLanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,newDState)));
00431         rDiagGen.SetTransition(dstate,ev,newDState);
00432       }
00433       // initialise per event variables in multimap loop
00434       gsit_beg=gsit;
00435       newDAttr.Clear();
00436     }
00437     // delete current state from todo list
00438     dStates.Erase(dstate);
00439   }
00440 
00441 #ifdef FAUDES_DEBUG_DIAGNOSIS
00442   rDiagGen.GraphWrite("tmp_wrtb_diag.png");
00443 #endif    
00444 }
00445 
00446 
00447 // IsLanguageDiagnosable
00448 bool IsLanguageDiagnosable(const cGenerator& rGen, const cGenerator rSpec, std::string& rReportString){
00449   FD_DD("IsLanguageDiagnosable()");
00450   EventSet obsEvents = rGen.ObservableEvents();
00451 #ifdef FAUDES_DEBUG_DIAGNOSIS
00452   obsEvents.DWrite();
00453 #endif
00454   Generator verifier; // Graph for diagnosability verification
00455   Idx nullEvent = verifier.InsEvent("nullEvent"); // event that corresponds to the value 0
00456   Idx negEvent = verifier.InsEvent("negEvent"); // event that corresponds to the value -1 
00457   //Generator verifierTest; // verifier with eeent information
00458   //verifierTest.InjectAlphabet(rGen.Alphabet() ); // FIXME remove this. 
00459   //verifierTest.InsEvent(nullEvent);
00460   map<Idx, VerifierState> stateToVerifierMap;
00461   map<VerifierState, Idx> verifierToStateMap;
00462   stack<pair<Idx, VerifierState> > waitingStates;
00463   StateSet doneStates;
00464   // initialize the algorithm 
00465   EventSet fullAlphabet = rGen.Alphabet();
00466   EventSet::Iterator eIt, eEndIt;
00467   eEndIt = fullAlphabet.End();
00468   Idx newState = verifier.InsInitState();
00469   //verifierTest.InsInitState(newState);
00470   VerifierState newVerifierState = VerifierState(rSpec.InitState(), rSpec.InitState(), rGen.InitState(),NORMAL);
00471   stateToVerifierMap[newState] = newVerifierState;
00472   verifierToStateMap[newVerifierState ] = newState;
00473   waitingStates.push(make_pair(newState, newVerifierState) );
00474   // extend the verifier graph until no new nodes can be added
00475   pair<Idx, VerifierState> currentState;
00476   Idx blockingState; // = verifier.InsMarkedState();
00477   TransSet::Iterator tIt;
00478   map<VerifierState, Idx>::const_iterator vsIt;
00479   Idx X2;
00480   bool block = false; // set to true if the BLOCK state is reachable  
00481   FD_DD("Main loop");
00482   while(waitingStates.empty() == false){
00483     // take the first element from the stack
00484     currentState = waitingStates.top();
00485     waitingStates.pop();
00486     doneStates.Insert(currentState.first);
00487     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) + ")");
00488     // go over all possible events
00489     eIt = fullAlphabet.Begin();
00490     for(; eIt != eEndIt; eIt++){
00491       // if the event is not observable, the specification and the plant can evolve independently
00492       if(obsEvents.Exists(*eIt) == false){
00493         tIt = rSpec.TransRelBegin(currentState.second.mSpec1State,*eIt);
00494         // transition in Spec1 exists
00495         if(tIt != rSpec.TransRelEnd(currentState.second.mSpec1State,*eIt) ){
00496           if(currentState.second.mLabel == NORMAL ){ // transition in spec1 from normal state
00497             newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, NORMAL);
00498           }
00499           else // transition in spec1 from confused state
00500             newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, CONFUSED);
00501           // check if the new VerifierState already exist snd insert new transitions (rule 1 and 4)
00502           vsIt = verifierToStateMap.find(newVerifierState);
00503           // a new state is inserted into the verifier
00504           if(vsIt == verifierToStateMap.end() ){
00505             newState = verifier.InsState();
00506             //verifierTest.InsState(newState);
00507             verifier.SetTransition(currentState.first,nullEvent,newState);
00508             //verifierTest.SetTransition(currentState.first,*eIt,newState);
00509             verifierToStateMap[newVerifierState] = newState;
00510             stateToVerifierMap[newState] = newVerifierState;
00511             if(doneStates.Exists(newState) == false)
00512               waitingStates.push(make_pair(newState,newVerifierState) );
00513           }
00514           // a transition to the existing state is added
00515           else{
00516             //verifierTest.SetTransition(currentState.first,*eIt,vsIt->second);
00517             verifier.SetTransition(currentState.first,nullEvent,vsIt->second);
00518             
00519           }
00520         }
00521         tIt = rGen.TransRelBegin(currentState.second.mPlantState,*eIt);
00522         // transition in plant exists
00523         if(tIt != rGen.TransRelEnd(currentState.second.mPlantState,*eIt) ){
00524           X2 = tIt->X2;
00525           if(currentState.second.mLabel == CONFUSED)
00526             newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED);
00527           else{ // current state is NORMAL
00528             tIt = rSpec.TransRelBegin(currentState.second.mSpec2State,*eIt); 
00529             if(tIt == rSpec.TransRelEnd(currentState.second.mSpec2State,*eIt) ){ // violation of the specification
00530               newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED);
00531             }
00532             else{ // correct behavior
00533               newVerifierState = VerifierState(currentState.second.mSpec1State, tIt->X2, X2, NORMAL);
00534             }
00535           }
00536           // check if a new state has to be inserted into the verifier a
00537           vsIt = verifierToStateMap.find(newVerifierState);
00538           // a new state is inserted into the verifier
00539           if(vsIt == verifierToStateMap.end() ){
00540             newState = verifier.InsState();
00541             //verifierTest.InsState(newState);
00542             verifierToStateMap[newVerifierState] = newState;
00543             stateToVerifierMap[newState] = newVerifierState;
00544             if(doneStates.Exists(newState) == false)
00545               waitingStates.push(make_pair(newState,newVerifierState) );
00546           }
00547           else  
00548             newState = vsIt->second;
00549           // new transition in the verifier
00550           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)
00551             //verifierTest.SetTransition(currentState.first,*eIt,newState);
00552             verifier.SetTransition(currentState.first,nullEvent,newState);
00553           }
00554           else{ // faulty behavior extended in the plant (rule 5)
00555             //verifierTest.SetTransition(currentState.first,*eIt,newState);
00556             verifier.SetTransition(currentState.first,negEvent,newState);
00557           }
00558         }
00559       }// (obsEvents.Exists(*eIt) == false)
00560       else{
00561         TransSet::Iterator plantIt, specIt;
00562         Idx eventIdx;
00563         tIt = rSpec.TransRelBegin(currentState.second.mSpec1State, *eIt);
00564         plantIt= rGen.TransRelBegin(currentState.second.mPlantState, *eIt);
00565         specIt = rSpec.TransRelBegin(currentState.second.mSpec2State, *eIt);
00566         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
00567           if(currentState.second.mLabel == NORMAL && specIt != rSpec.TransRelEnd(currentState.second.mSpec2State, *eIt) ){ // no confusion (rule 6)
00568             newVerifierState = VerifierState(tIt->X2, specIt->X2, plantIt->X2, NORMAL);
00569             eventIdx = nullEvent;
00570           }
00571           else if(currentState.second.mLabel == NORMAL){// faulty behavior occurs (rule 7)
00572             newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED);
00573             eventIdx = negEvent;
00574           }
00575           else{ // there is already confusion (rule 8)
00576             newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED);
00577             eventIdx = negEvent;
00578           }
00579           // check if a new state has to be inserted into the verifier a
00580           vsIt = verifierToStateMap.find(newVerifierState);
00581           // a new state is inserted into the verifier
00582           if(vsIt == verifierToStateMap.end() ){
00583             newState = verifier.InsState();
00584             //verifierTest.InsState(newState);
00585             verifierToStateMap[newVerifierState] = newState;
00586             stateToVerifierMap[newState] = newVerifierState;
00587             if(doneStates.Exists(newState) == false)
00588               waitingStates.push(make_pair(newState,newVerifierState) );
00589           }
00590           else  
00591             newState = vsIt->second;    
00592 
00593           // update the verifier
00594           //verifierTest.SetTransition(currentState.first,*eIt,newState);
00595           verifier.SetTransition(currentState.first,eventIdx,newState);
00596         }
00597       }
00598     }
00599     // check if the Block state is reachable 
00600     if(rGen.TransRelBegin(currentState.second.mPlantState) == rGen.TransRelEnd(currentState.second.mPlantState) && currentState.second.mLabel == CONFUSED){
00601       blockingState = verifier.InsMarkedState();
00602       verifier.SetTransition(currentState.first,nullEvent,blockingState);
00603       //verifierTest.InsMarkedState(blockingState);
00604       //verifierTest.SetTransition(currentState.first,nullEvent,blockingState);
00605       FD_DD("Blocking State Reachable");
00606       block = true;
00607     }
00608   }
00609   #ifdef FAUDES_DEBUG_DIAGNOSIS
00610   verifier.GraphWrite("data/verifier.png");
00611   #endif 
00612   //verifierTest.GraphWrite("data/verifierTest.png");
00613   // Seach for cycles with "-1"-transitions (negEvent) in the verifier
00614   list<StateSet> sccList;
00615   StateSet rootSet;
00616   // compute the strongly connected components in the verifier
00617   ComputeScc(verifier,sccList,rootSet);
00618   // Check if there is a "-1"-transition in any of the SCCs
00619   list<StateSet>::const_iterator sccIt, sccEndIt;
00620   sccIt = sccList.begin();
00621   sccEndIt = sccList.end();
00622   StateSet::Iterator stIt, stEndIt;
00623   bool existsCycle = false;
00624   for( ; sccIt != sccEndIt; sccIt++){
00625 #ifdef FAUDES_DEBUG_DIAGNOSIS
00626     sccIt->Write();
00627 #endif
00628     stIt = sccIt->Begin();
00629     stEndIt = sccIt->End();
00630     for(; stIt != stEndIt; stIt++){// check all states in the SCC
00631       tIt = verifier.TransRelBegin(*stIt, negEvent);
00632       if(tIt != verifier.TransRelEnd(*stIt, negEvent) && sccIt->Exists(tIt->X2) ){ // there is a transition with negEvent within the SCC
00633         FD_DD("Confused Cycle Found");
00634         existsCycle = true;
00635         break;
00636       }
00637     }
00638     if(existsCycle == true)
00639       break;
00640   }
00641   if(block == true || existsCycle == true)
00642     return false;
00643   else
00644     return true;
00645 }
00646 
00647 //IsLoopPreservingObserver()
00648 bool IsLoopPreservingObserver(const cGenerator& rGen, const EventSet& rHighAlph){
00649   cGenerator genCopy;
00650   TransSet::Iterator tit;
00651   string report;
00652   FD_DD("IsLoopPreservingObserver()");
00653   genCopy = rGen;
00654   genCopy.InjectMarkedStates(genCopy.States() );
00655   // Verify if the observer condition is fulfilled
00656   if(IsObs(genCopy,rHighAlph)  == false){ 
00657     FD_DD("Observer Condition violated");
00658     return false;
00659   }
00660   FD_DD("Observer Condition fulfilled");
00661   // Verify if there are loops with abstracted events
00662   // delete all transitions that do not belong to local high-alphabet
00663   for (tit = genCopy.TransRelBegin(); tit != genCopy.TransRelEnd();) {
00664     if (rHighAlph.Exists(tit->Ev)) 
00665       tit=genCopy.ClrTransition(tit);    
00666     else 
00667       ++tit;
00668   }
00669   // search for cycles in remainder automaton
00670   std::list<StateSet> sccList;
00671   StateSet sccRoots;
00672   ComputeScc(genCopy,sccList,sccRoots);
00673   std::list<StateSet>::const_iterator sIt = sccList.begin();
00674   for( ; sIt != sccList.end(); sIt++){
00675     if(sIt->Size() > 1){
00676       #ifdef FAUDES_DEBUG_DIAGNOSIS
00677       cout << "Bad states that form a cycle with abstracted events: " << endl;
00678       StateSet::Iterator stIt = sIt->Begin();
00679       for(; stIt != sIt->End(); stIt++)
00680         cout << *stIt << " ";
00681       cout << endl;
00682       #endif
00683       return false;
00684     }
00685   }
00686   return true;
00687 }
00688 
00689 
00690 void ComputeLoopPreservingObserver(const cGenerator& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph){
00691   // Verify if the projection with the given initial alphabet is already a loop-preserving observer
00692   rHighAlph = rInitialHighAlph;
00693         rHighAlph.Name("HiAlph");
00694   FD_DD("ComputeLoopPreservingObserver()");
00695   if(IsLoopPreservingObserver(rGen,rHighAlph) == true)
00696     return;
00697     
00698   // check all combinations of events from the difference set 
00699   EventSet diffSet = rGen.Alphabet() - rHighAlph;
00700   EventSet::Iterator eIt = diffSet.Begin();
00701   std::vector<Idx> diffVector;
00702   for( ; eIt != diffSet.End(); eIt++) // ordered list of events in the diffSet
00703     diffVector.push_back(*eIt);
00704     
00705   for(Idx numberEvents = 1; numberEvents <= diffVector.size(); numberEvents++){// number events that are chosen in this step
00706     FD_DD("numberEvents: " + ToStringInteger(numberEvents));
00707     Idx currentNumberEvents = 1; // number of events under investigation
00708     Idx currentLocation = 0; // start position for the search for new events
00709     EventSet chosenEvents;
00710     if(rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,diffVector,numberEvents,currentNumberEvents,currentLocation,chosenEvents) == true)
00711       break;
00712   }
00713         // fix name
00714         rHighAlph.Name("HiAlph");
00715 }
00716 
00717 // rec_ComputeLoopPreservingObserver(rGen,
00718 bool rec_ComputeLoopPreservingObserver(const cGenerator& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph, const std::vector<Idx>& rDiffVector, Idx numberEvents, Idx currentNumberEvents, Idx currentLocation, EventSet chosenEvents){
00719   FD_DD("rec_ComputeLoopPreservingObserver()");
00720   bool valid;
00721   for(Idx i = currentLocation; i < rDiffVector.size(); i++){
00722     FD_DD("currentNumberEvents: " + ToStringInteger(currentNumberEvents) + "currentLocation: " + ToStringInteger(i) + " event: " + SymbolTable::GlobalEventSymbolTablep()->Symbol(rDiffVector[i]));
00723     chosenEvents.Insert(rDiffVector[i]);
00724     rHighAlph = rInitialHighAlph + chosenEvents;
00725     if(currentNumberEvents == numberEvents){// enough events found
00726       valid = IsLoopPreservingObserver(rGen,rHighAlph);
00727       if(valid == true){
00728         return true;
00729       }
00730     }
00731     else if(rDiffVector.size() - 1 - i < numberEvents - currentNumberEvents){ // not enough events left to find numberEvents 
00732       return false;
00733     }
00734     else{// go to the next level to add events
00735       FD_DD("currentLevel: " + ToStringInteger(i));
00736       valid = rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,rDiffVector,numberEvents,currentNumberEvents + 1,i + 1, chosenEvents);
00737       if(valid == true){
00738         return true;
00739       }
00740     }
00741     chosenEvents.Erase(rDiffVector[i]);
00742   }
00743   return false;
00744 }
00745 
00746 } // namespace faudes

libFAUDES 2.16b --- 2010-9-8 --- c++ source docu by doxygen 1.6.3