op_obserververification.cppGo 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 |