op_obserververification.cpp

Go to the documentation of this file.
00001 /** @file op_obserververification.cpp 
00002 
00003 Methods to verify the obsrver condition for natural projections.
00004 The observer condition is, e.g., defined in 
00005 K. C. Wong and W. M. Wonham, “Hierarchical control of discrete-event
00006 systems,” Discrete Event Dynamic Systems: Theory and Applications, 1996.
00007 In addition, methods to verify output control consistency (OCC) and 
00008 local control consistency (LCC) are provided. See for example
00009 K. Schmidt and C. Breindl, "On Maximal Permissiveness of Hierarchical and Modular Supervisory
00010 Control Approaches for Discrete Event Systems," Workshop on Discrete Event Systems, 2008. 
00011 */
00012 
00013 /* FAU Discrete Event Systems Library (libfaudes)
00014 
00015    Copyright (C) 2006  Bernd Opitz
00016    Exclusive copyright is granted to Klaus Schmidt
00017 
00018    This library is free software; you can redistribute it and/or
00019    modify it under the terms of the GNU Lesser General Public
00020    License as published by the Free Software Foundation; either
00021    version 2.1 of the License, or (at your option) any later version.
00022 
00023    This library is distributed in the hope that it will be useful,
00024    but WITHOUT ANY WARRANTY; without even the implied warranty of
00025    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026    Lesser General Public License for more details.
00027 
00028    You should have received a copy of the GNU Lesser General Public
00029    License along with this library; if not, write to the Free Software
00030    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00031 #include "op_obserververification.h"
00032 
00033 
00034 using namespace std;
00035 
00036 namespace faudes {
00037 
00038 bool IsObs(const Generator& rLowGen, const EventSet& rHighAlph){
00039   OP_DF("IsObs(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00040   // Initialization of variables
00041   EventSet newHighAlph = rHighAlph;
00042   EventSet controllableEvents;
00043   map<Transition,Idx> mapChangedTrans;
00044   Generator genDyn(rLowGen);
00045   map<Transition,Transition> mapChangedTransReverse;
00046   vector<Idx> newPartitions;
00047   map<Idx,Idx> mapStateToPartition;
00048   map<Idx, EventSet> mapRelabeledEvents;
00049   // One step of the observer algorithm: A dynamic system is computed that fulfills the one-step observer condition. 
00050   // if the result is equal to the original generator, then the natural projection on the high-level alphabet fulfills the observer property
00051   calculateDynamicSystemClosedObs(rLowGen, newHighAlph, genDyn);
00052   calculateDynamicSystemObs(rLowGen, newHighAlph, genDyn);
00053   Generator genPart;
00054   // compute coarsest quasi-congruence on the dynamic system
00055   calcBisimulation(genDyn, mapStateToPartition, genPart, newPartitions);
00056   // Extend the high-level alphabet according to the algorithm of Lei
00057         ExtendHighAlphabet(rLowGen, newHighAlph, mapStateToPartition);
00058   // return the result of the event extension
00059   return newHighAlph == rHighAlph;
00060 
00061 }
00062 
00063 bool IsMSA(const Generator& rLowGen, const EventSet& rHighAlph){
00064   OP_DF("IsMSA(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00065   // Initialization of variables
00066   EventSet newHighAlph = rHighAlph;
00067   EventSet controllableEvents;
00068   map<Transition,Idx> mapChangedTrans;
00069   Generator genDyn(rLowGen);
00070   map<Transition,Transition> mapChangedTransReverse;
00071   vector<Idx> newPartitions;
00072   map<Idx,Idx> mapStateToPartition;
00073   map<Idx, EventSet> mapRelabeledEvents;
00074   // One step of the observer algorithm: A dynamic system is computed that fulfills the one-step observer condition. 
00075   // if the result is equal to the original generator, then the natural projection on the high-level alphabet fulfills the observer property
00076   calculateDynamicSystemClosedObs(rLowGen, newHighAlph, genDyn);
00077         calculateDynamicSystemMSA(rLowGen, newHighAlph, genDyn);
00078   Generator genPart;
00079   // compute coarsest quasi-congruence on the dynamic system
00080   calcBisimulation(genDyn, mapStateToPartition, genPart, newPartitions);
00081   // Extend the high-level alphabet according to the algorithm of Lei
00082         ExtendHighAlphabet(rLowGen, newHighAlph, mapStateToPartition);
00083   // return the result of the event extension
00084   return newHighAlph == rHighAlph;
00085 
00086 }
00087 
00088 bool IsOCC(const System& rLowGen, const EventSet& rHighAlph){
00089   OP_DF("IsOCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00090   EventSet controllableEvents = rLowGen.ControllableEvents();
00091   // call the function that implements the algorithm
00092   return IsOCC(rLowGen, controllableEvents, rHighAlph);
00093 }
00094 
00095 bool IsOCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
00096   OP_DF("IsOCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00097   //helpers:
00098   StateSet::Iterator stIt, stEndIt;
00099   stIt = rLowGen.StatesBegin();
00100   stEndIt = rLowGen.StatesEnd();
00101   TransSet::Iterator tIt, tEndIt;
00102   // iteration over all states of rLowGen. If there is an uncontrollable feasible high-level event, backward reachability is conducted to determine if OCC holds. 
00103   for( ; stIt != stEndIt; stIt++){
00104     tIt = rLowGen.TransRelBegin(*stIt);
00105     tEndIt = rLowGen.TransRelEnd(*stIt);
00106     for( ; tIt != tEndIt; tIt++){
00107       if(rHighAlph.Exists(tIt->Ev) && !rControllableEvents.Exists(tIt->Ev) ){
00108         // check if all local backward paths are uncontrollable
00109         bool uncontrollable = backwardVerificationOCC(rLowGen, rControllableEvents, rHighAlph, *stIt);
00110         // if not all paths are uncontrollable, OCC is violated
00111         if(uncontrollable == false)
00112           return false;
00113         // otherwise, go to the next state
00114         else
00115           break;
00116       }
00117     }
00118   }
00119   return true;
00120 }
00121 
00122 bool backwardVerificationOCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph, Idx currentState){
00123   OP_DF("backwardVerificationOCC(" << rLowGen.Name() << "," << rControllableEvents.Name() << "," << rHighAlph.Name() << "," << currentState << ")");
00124   // reverse transition relation
00125   TransSetX2EvX1 tset_X2EvX1;
00126   rLowGen.TransRel(tset_X2EvX1);
00127   TransSetX2EvX1::Iterator tsIt, tsEndIt;
00128   // todo list
00129   std::stack<Idx> todo;
00130   // algorithm: the locally backwards reachable states from current staet are 
00131   // evaluated. If a controllable event is found, OCC is violated.
00132   StateSet doneStates;
00133   doneStates.Insert(currentState);
00134   todo.push(currentState);
00135   // the local reachability is evaluated until no new state is found
00136   while( !todo.empty() ){
00137     const Idx current = todo.top();
00138     todo.pop();
00139     tsIt = tset_X2EvX1.BeginByX2(current);
00140     tsEndIt = tset_X2EvX1.EndByX2(current);
00141     for(; tsIt != tsEndIt; tsIt++){
00142       // if the current transition is labeled with a high-level evnet
00143       // it is skipped
00144       if(rHighAlph.Exists(tsIt->Ev) )
00145         continue;
00146       // if the current transition is controllable, OCC is violated
00147       else if( rControllableEvents.Exists(tsIt->Ev) )
00148         return false;
00149       else if( !doneStates.Exists(tsIt->X1) ){
00150         todo.push(tsIt->X1);
00151         doneStates.Insert(tsIt->X1);
00152       }
00153     }
00154   }
00155   return true;
00156 }
00157 
00158 
00159 bool IsLCC(const System& rLowGen, const EventSet& rHighAlph){
00160   OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00161   EventSet controllableEvents = rLowGen.ControllableEvents();
00162   // call the function that implements the algorithm
00163   return IsLCC(rLowGen, controllableEvents, rHighAlph);
00164 }
00165 
00166 
00167 /*
00168 
00169 In my opinion, the below algorithm to test LCC is incorrect. 
00170 It gives false negatives; e.g. stackfeeder example from 
00171 LRT "Uebung 12", data given below. I've
00172 temporarily replaced IsLCC by a naive algorithm
00173 which should be correct. This topic needs further 
00174 attentio .. tmoor, 07/20012
00175 
00176 
00177 <Generator> 
00178 "Generator"    
00179 <Alphabet>
00180 "wpar"          "mv"            +C+           "wplv"          "r"             "nr"           
00181 "stp"           +C+          
00182 </Alphabet>
00183 
00184 <States>
00185 <Consecutive>
00186 1              8             
00187 </Consecutive>
00188 </States>
00189 
00190 <TransRel>
00191 1              "wpar"          2             
00192 2              "mv"            3             
00193 3              "nr"            4             
00194 4              "wplv"          5             
00195 5              "wpar"          8             
00196 5              "r"             6             
00197 6              "wpar"          7             
00198 6              "stp"           1             
00199 7              "stp"           2             
00200 8              "r"             7             
00201 </TransRel>
00202 
00203 <InitStates>   1 </InitStates>
00204 <MarkedStates> 1 </MarkedStates>
00205 </Generator>
00206 
00207 with high-level alphabet wpar and mv
00208 */
00209 
00210 /*
00211 bool IsLCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
00212   OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00213   // reverse transition relation
00214   TransSetX2EvX1 tset_X2EvX1;
00215   rLowGen.TransRel(tset_X2EvX1);
00216   //helpers:
00217   StateSet::Iterator stIt, stEndIt;
00218   stIt = rLowGen.StatesBegin();
00219   stEndIt = rLowGen.StatesEnd();
00220   TransSet::Iterator tIt, tEndIt;
00221   StateSet doneStates;
00222   map<Idx, bool> localStatesMap;
00223   map<Idx, bool>::const_iterator lsIt, lsEndIt;
00224   // iteration over all states of rLowGen. If there is an uncontrollable feasible high-level event, 
00225   // backward reachability is conducted to determine if LCC holds. 
00226   for( ; stIt != stEndIt; stIt++){
00227     tIt = rLowGen.TransRelBegin(*stIt);
00228     tEndIt = rLowGen.TransRelEnd(*stIt);
00229     for( ; tIt != tEndIt; tIt++){
00230       if(rHighAlph.Exists(tIt->Ev) && !rControllableEvents.Exists(tIt->Ev) ){
00231         doneStates.Clear();
00232         localStatesMap.clear();
00233         localStatesMap[*stIt] = false;
00234         doneStates.Insert(*stIt);
00235         // check if for all backward reachable states, a local uncontrollable backward paths exists
00236         FD_WARN("IsLCC(): analyse state " << rLowGen.SStr(*stIt));
00237         backwardVerificationLCC(tset_X2EvX1, rControllableEvents, rHighAlph, *stIt, *stIt, false, localStatesMap, doneStates);
00238         // if for some state, all paths are controllable, LCC is violated
00239         lsIt = localStatesMap.begin();
00240         lsEndIt = localStatesMap.end();
00241         for( ; lsIt != lsEndIt; lsIt++){
00242           // if there is a state with only controllable paths, LCC is violated
00243           if(lsIt->second == true) {
00244             FD_WARN("IsLCC(): fail for state " << lsIt->first);
00245             return false; 
00246     }
00247         }
00248         // the evaluation for the current state is finished
00249         break;
00250       }
00251     }
00252   }
00253   FD_WARN("IsLCC(): pass");
00254   return true;
00255 }
00256 
00257 
00258 void backwardVerificationLCC(
00259   const TransSetX2EvX1& rTransSetX2EvX1, 
00260   const EventSet& rControllableEvents, 
00261   const EventSet& rHighAlph, 
00262   Idx exitState, 
00263   Idx currentState, 
00264   bool controllablePath, 
00265   map<Idx, bool>& rLocalStatesMap, 
00266   StateSet& rDoneStates)
00267 {
00268   OP_DF("backwardVerificationLCC(rTransSetX2EvX1," << 
00269       rControllableEvents.Name() << "," << rHighAlph.Name() << "," << exitState << "," 
00270     << currentState << "," << controllablePath << ",rExitLocalStatesMap, rDoneStates)");
00271   FD_WARN("IsLCC(): b-reach at state " << currentState);
00272   // go along all backward transitions. Discard the goal state if it is reached via a high-level event or if it is in the rDoneStates and 
00273   // the controllability properties of the state do not change on the current path
00274     
00275   // helpers
00276   TransSetX2EvX1::Iterator tsIt, tsEndIt;
00277   tsIt = rTransSetX2EvX1.BeginByX2(currentState);
00278   tsEndIt = rTransSetX2EvX1.EndByX2(currentState);
00279   bool currentControllablePath;
00280   // we iterate over all backward transitions of the currentState to establish backward reachability
00281   for( ;tsIt != tsEndIt; tsIt++){
00282     // states reachable via a high-level event 
00283     // are not in the local backward reach and the controllability property of the current exitState does not change
00284     if( !rHighAlph.Exists(tsIt->Ev) && tsIt->X1 != exitState){
00285       // if the state has not been visited, yet, the controllability of the current path are set in the rExitLocalStatesMap
00286       if( !rDoneStates.Exists(tsIt->X1) ){
00287   rDoneStates.Insert(tsIt->X1);
00288   // the path is uncontrollable if the current transition has an uncontrollable event or the path was already uncontrollable
00289   currentControllablePath = rControllableEvents.Exists(tsIt->Ev) || controllablePath;
00290         FD_WARN("IsLCC(): record new state " << tsIt->X1 << " cntr=" << currentControllablePath);
00291   rLocalStatesMap[tsIt->X1] = currentControllablePath;
00292   // as the state has not been visited, yet, it is subject to a new backward reachability
00293   backwardVerificationLCC(rTransSetX2EvX1, rControllableEvents, rHighAlph, exitState, tsIt->X1, currentControllablePath, rLocalStatesMap, rDoneStates);
00294       }
00295       else{ // for an existing state, the controllability value can change from controllable to uncontrollable (if 
00296   // a new uncontrollable path has been found). It is important to note, that the LCC condition implies that
00297   // if there is one uncontrollable path, then the state is flagged uncontrollable except for the case of the 
00298   // given exitState that is always uncontrollable
00299   currentControllablePath = rControllableEvents.Exists(tsIt->Ev) || controllablePath;
00300   if(rLocalStatesMap[tsIt->X1] != currentControllablePath && currentControllablePath == false){
00301     rLocalStatesMap[tsIt->X1] = false;
00302     // as the controllabiity attribute of the current state changed it is subject to a new backward reachability
00303     backwardVerificationLCC(rTransSetX2EvX1, rControllableEvents, rHighAlph, exitState, tsIt->X1, false, rLocalStatesMap, rDoneStates);
00304   }
00305       }
00306     }
00307   }
00308 }
00309 
00310 */
00311 
00312  
00313 // Naive replacement to test LCC with std. forward search for each state
00314 // (complexity is quadratic in the number of states and 
00315 // linear in the number of events; actual performance is suboptimal, 
00316 // but I don't see how to get lower complexity)
00317 
00318 bool IsLCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
00319   OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
00320   // iteration over all states of rLowGen. 
00321   StateSet::Iterator sit=rLowGen.StatesBegin();
00322   for( ; sit != rLowGen.StatesEnd(); sit++){
00323     // forward reachablity to figure all next high-level events
00324     StateSet freach;
00325     StateSet todo;
00326     EventSet hievs;
00327     todo.Insert(*sit);
00328     while(!todo.Empty()) {
00329       // take from todo stack
00330       Idx cs = *todo.Begin();
00331       todo.Erase(todo.Begin());
00332       freach.Insert(cs);
00333       // figure next states
00334       TransSet::Iterator tit = rLowGen.TransRelBegin(cs);
00335       TransSet::Iterator tit_end=rLowGen.TransRelEnd(cs);
00336       for( ; tit != tit_end; tit++){
00337         if(rHighAlph.Exists(tit->Ev)) {
00338           hievs.Insert(tit->Ev);
00339         } else {
00340           if(!freach.Exists(cs)) todo.Insert(cs);
00341   }
00342       }
00343     }
00344     // forward reachablity to figure next high-level events by uncontr. paths
00345     EventSet hievs_ucpath;
00346     todo.Clear();
00347     freach.Clear();
00348     todo.Insert(*sit);
00349     while(!todo.Empty()) {
00350       // take from todo stack
00351       Idx cs = *todo.Begin();
00352       todo.Erase(todo.Begin());
00353       freach.Insert(cs);
00354       // figure next states
00355       TransSet::Iterator tit = rLowGen.TransRelBegin(cs);
00356       TransSet::Iterator tit_end=rLowGen.TransRelEnd(cs);
00357       for( ; tit != tit_end; tit++){
00358         if(rControllableEvents.Exists(tit->Ev)) continue;
00359         if(rHighAlph.Exists(tit->Ev)) {
00360           hievs_ucpath.Insert(tit->Ev);
00361         } else {
00362           if(!freach.Exists(cs)) todo.Insert(cs);
00363   }
00364       }
00365     }
00366     // test lcc
00367     hievs = hievs - rControllableEvents;
00368     hievs_ucpath = hievs_ucpath - rControllableEvents;
00369     if(hievs_ucpath != hievs) {
00370       OP_DF("IsLCC: failed at state " << rLowGen.SStr(*sit))
00371       return false;
00372     }
00373   }
00374   // no issues found
00375   OP_DF(y"IsLCC: passed");
00376   return true;
00377 }
00378 
00379 
00380 }// namespace faudes

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen