op_obserververification.cpp
Go to the documentation of this file.
1 /** @file op_obserververification.cpp
2 
3 Methods to verify the obsrver condition for natural projections.
4 The observer condition is, e.g., defined in
5 K. C. Wong and W. M. Wonham, “Hierarchical control of discrete-event
6 systems,” Discrete Event Dynamic Systems: Theory and Applications, 1996.
7 In addition, methods to verify output control consistency (OCC) and
8 local control consistency (LCC) are provided. See for example
9 K. Schmidt and C. Breindl, "On Maximal Permissiveness of Hierarchical and Modular Supervisory
10 Control Approaches for Discrete Event Systems," Workshop on Discrete Event Systems, 2008.
11 */
12 
13 /* FAU Discrete Event Systems Library (libfaudes)
14 
15  Copyright (C) 2006 Bernd Opitz
16  Exclusive copyright is granted to Klaus Schmidt
17 
18  This library is free software; you can redistribute it and/or
19  modify it under the terms of the GNU Lesser General Public
20  License as published by the Free Software Foundation; either
21  version 2.1 of the License, or (at your option) any later version.
22 
23  This library is distributed in the hope that it will be useful,
24  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26  Lesser General Public License for more details.
27 
28  You should have received a copy of the GNU Lesser General Public
29  License along with this library; if not, write to the Free Software
30  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
32 
33 
34 using namespace std;
35 
36 namespace faudes {
37 
38 bool IsObs(const Generator& rLowGen, const EventSet& rHighAlph){
39  OP_DF("IsObs(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
40  // Initialization of variables
41  EventSet newHighAlph = rHighAlph;
42  EventSet controllableEvents;
43  map<Transition,Idx> mapChangedTrans;
44  Generator genDyn(rLowGen);
45  map<Transition,Transition> mapChangedTransReverse;
46  vector<Idx> newPartitions;
47  map<Idx,Idx> mapStateToPartition;
48  map<Idx, EventSet> mapRelabeledEvents;
49  // One step of the observer algorithm: A dynamic system is computed that fulfills the one-step observer condition.
50  // if the result is equal to the original generator, then the natural projection on the high-level alphabet fulfills the observer property
51  calculateDynamicSystemClosedObs(rLowGen, newHighAlph, genDyn);
52  calculateDynamicSystemObs(rLowGen, newHighAlph, genDyn);
53  Generator genPart;
54  // compute coarsest quasi-congruence on the dynamic system
55  calcBisimulation(genDyn, mapStateToPartition, genPart, newPartitions);
56  // Extend the high-level alphabet according to the algorithm of Lei
57  ExtendHighAlphabet(rLowGen, newHighAlph, mapStateToPartition);
58  // return the result of the event extension
59  return newHighAlph == rHighAlph;
60 
61 }
62 
63 bool IsMSA(const Generator& rLowGen, const EventSet& rHighAlph){
64  OP_DF("IsMSA(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
65  // Initialization of variables
66  EventSet newHighAlph = rHighAlph;
67  EventSet controllableEvents;
68  map<Transition,Idx> mapChangedTrans;
69  Generator genDyn(rLowGen);
70  map<Transition,Transition> mapChangedTransReverse;
71  vector<Idx> newPartitions;
72  map<Idx,Idx> mapStateToPartition;
73  map<Idx, EventSet> mapRelabeledEvents;
74  // One step of the observer algorithm: A dynamic system is computed that fulfills the one-step observer condition.
75  // if the result is equal to the original generator, then the natural projection on the high-level alphabet fulfills the observer property
76  calculateDynamicSystemClosedObs(rLowGen, newHighAlph, genDyn);
77  calculateDynamicSystemMSA(rLowGen, newHighAlph, genDyn);
78  Generator genPart;
79  // compute coarsest quasi-congruence on the dynamic system
80  calcBisimulation(genDyn, mapStateToPartition, genPart, newPartitions);
81  // Extend the high-level alphabet according to the algorithm of Lei
82  ExtendHighAlphabet(rLowGen, newHighAlph, mapStateToPartition);
83  // return the result of the event extension
84  return newHighAlph == rHighAlph;
85 
86 }
87 
88 bool IsOCC(const System& rLowGen, const EventSet& rHighAlph){
89  OP_DF("IsOCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
90  EventSet controllableEvents = rLowGen.ControllableEvents();
91  // call the function that implements the algorithm
92  return IsOCC(rLowGen, controllableEvents, rHighAlph);
93 }
94 
95 bool IsOCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
96  OP_DF("IsOCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
97  //helpers:
98  StateSet::Iterator stIt, stEndIt;
99  stIt = rLowGen.StatesBegin();
100  stEndIt = rLowGen.StatesEnd();
101  TransSet::Iterator tIt, tEndIt;
102  // iteration over all states of rLowGen. If there is an uncontrollable feasible high-level event, backward reachability is conducted to determine if OCC holds.
103  for( ; stIt != stEndIt; stIt++){
104  tIt = rLowGen.TransRelBegin(*stIt);
105  tEndIt = rLowGen.TransRelEnd(*stIt);
106  for( ; tIt != tEndIt; tIt++){
107  if(rHighAlph.Exists(tIt->Ev) && !rControllableEvents.Exists(tIt->Ev) ){
108  // check if all local backward paths are uncontrollable
109  bool uncontrollable = backwardVerificationOCC(rLowGen, rControllableEvents, rHighAlph, *stIt);
110  // if not all paths are uncontrollable, OCC is violated
111  if(uncontrollable == false)
112  return false;
113  // otherwise, go to the next state
114  else
115  break;
116  }
117  }
118  }
119  return true;
120 }
121 
122 bool backwardVerificationOCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph, Idx currentState){
123  OP_DF("backwardVerificationOCC(" << rLowGen.Name() << "," << rControllableEvents.Name() << "," << rHighAlph.Name() << "," << currentState << ")");
124  // reverse transition relation
125  TransSetX2EvX1 tset_X2EvX1;
126  rLowGen.TransRel(tset_X2EvX1);
127  TransSetX2EvX1::Iterator tsIt, tsEndIt;
128  // todo list
129  std::stack<Idx> todo;
130  // algorithm: the locally backwards reachable states from current staet are
131  // evaluated. If a controllable event is found, OCC is violated.
132  StateSet doneStates;
133  doneStates.Insert(currentState);
134  todo.push(currentState);
135  // the local reachability is evaluated until no new state is found
136  while( !todo.empty() ){
137  const Idx current = todo.top();
138  todo.pop();
139  tsIt = tset_X2EvX1.BeginByX2(current);
140  tsEndIt = tset_X2EvX1.EndByX2(current);
141  for(; tsIt != tsEndIt; tsIt++){
142  // if the current transition is labeled with a high-level evnet
143  // it is skipped
144  if(rHighAlph.Exists(tsIt->Ev) )
145  continue;
146  // if the current transition is controllable, OCC is violated
147  else if( rControllableEvents.Exists(tsIt->Ev) )
148  return false;
149  else if( !doneStates.Exists(tsIt->X1) ){
150  todo.push(tsIt->X1);
151  doneStates.Insert(tsIt->X1);
152  }
153  }
154  }
155  return true;
156 }
157 
158 
159 bool IsLCC(const System& rLowGen, const EventSet& rHighAlph){
160  OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
161  EventSet controllableEvents = rLowGen.ControllableEvents();
162  // call the function that implements the algorithm
163  return IsLCC(rLowGen, controllableEvents, rHighAlph);
164 }
165 
166 
167 /*
168 
169 In my opinion, the below algorithm to test LCC is incorrect.
170 It gives false negatives; e.g. stackfeeder example from
171 LRT "Uebung 12", data given below. I've
172 temporarily replaced IsLCC by a naive algorithm
173 which should be correct. This topic needs further
174 attentio .. tmoor, 07/20012
175 
176 
177 <Generator>
178 "Generator"
179 <Alphabet>
180 "wpar" "mv" +C+ "wplv" "r" "nr"
181 "stp" +C+
182 </Alphabet>
183 
184 <States>
185 <Consecutive>
186 1 8
187 </Consecutive>
188 </States>
189 
190 <TransRel>
191 1 "wpar" 2
192 2 "mv" 3
193 3 "nr" 4
194 4 "wplv" 5
195 5 "wpar" 8
196 5 "r" 6
197 6 "wpar" 7
198 6 "stp" 1
199 7 "stp" 2
200 8 "r" 7
201 </TransRel>
202 
203 <InitStates> 1 </InitStates>
204 <MarkedStates> 1 </MarkedStates>
205 </Generator>
206 
207 with high-level alphabet wpar and mv
208 */
209 
210 /*
211 bool IsLCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
212  OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
213  // reverse transition relation
214  TransSetX2EvX1 tset_X2EvX1;
215  rLowGen.TransRel(tset_X2EvX1);
216  //helpers:
217  StateSet::Iterator stIt, stEndIt;
218  stIt = rLowGen.StatesBegin();
219  stEndIt = rLowGen.StatesEnd();
220  TransSet::Iterator tIt, tEndIt;
221  StateSet doneStates;
222  map<Idx, bool> localStatesMap;
223  map<Idx, bool>::const_iterator lsIt, lsEndIt;
224  // iteration over all states of rLowGen. If there is an uncontrollable feasible high-level event,
225  // backward reachability is conducted to determine if LCC holds.
226  for( ; stIt != stEndIt; stIt++){
227  tIt = rLowGen.TransRelBegin(*stIt);
228  tEndIt = rLowGen.TransRelEnd(*stIt);
229  for( ; tIt != tEndIt; tIt++){
230  if(rHighAlph.Exists(tIt->Ev) && !rControllableEvents.Exists(tIt->Ev) ){
231  doneStates.Clear();
232  localStatesMap.clear();
233  localStatesMap[*stIt] = false;
234  doneStates.Insert(*stIt);
235  // check if for all backward reachable states, a local uncontrollable backward paths exists
236  FD_WARN("IsLCC(): analyse state " << rLowGen.SStr(*stIt));
237  backwardVerificationLCC(tset_X2EvX1, rControllableEvents, rHighAlph, *stIt, *stIt, false, localStatesMap, doneStates);
238  // if for some state, all paths are controllable, LCC is violated
239  lsIt = localStatesMap.begin();
240  lsEndIt = localStatesMap.end();
241  for( ; lsIt != lsEndIt; lsIt++){
242  // if there is a state with only controllable paths, LCC is violated
243  if(lsIt->second == true) {
244  FD_WARN("IsLCC(): fail for state " << lsIt->first);
245  return false;
246  }
247  }
248  // the evaluation for the current state is finished
249  break;
250  }
251  }
252  }
253  FD_WARN("IsLCC(): pass");
254  return true;
255 }
256 
257 
258 void backwardVerificationLCC(
259  const TransSetX2EvX1& rTransSetX2EvX1,
260  const EventSet& rControllableEvents,
261  const EventSet& rHighAlph,
262  Idx exitState,
263  Idx currentState,
264  bool controllablePath,
265  map<Idx, bool>& rLocalStatesMap,
266  StateSet& rDoneStates)
267 {
268  OP_DF("backwardVerificationLCC(rTransSetX2EvX1," <<
269  rControllableEvents.Name() << "," << rHighAlph.Name() << "," << exitState << ","
270  << currentState << "," << controllablePath << ",rExitLocalStatesMap, rDoneStates)");
271  FD_WARN("IsLCC(): b-reach at state " << currentState);
272  // 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
273  // the controllability properties of the state do not change on the current path
274 
275  // helpers
276  TransSetX2EvX1::Iterator tsIt, tsEndIt;
277  tsIt = rTransSetX2EvX1.BeginByX2(currentState);
278  tsEndIt = rTransSetX2EvX1.EndByX2(currentState);
279  bool currentControllablePath;
280  // we iterate over all backward transitions of the currentState to establish backward reachability
281  for( ;tsIt != tsEndIt; tsIt++){
282  // states reachable via a high-level event
283  // are not in the local backward reach and the controllability property of the current exitState does not change
284  if( !rHighAlph.Exists(tsIt->Ev) && tsIt->X1 != exitState){
285  // if the state has not been visited, yet, the controllability of the current path are set in the rExitLocalStatesMap
286  if( !rDoneStates.Exists(tsIt->X1) ){
287  rDoneStates.Insert(tsIt->X1);
288  // the path is uncontrollable if the current transition has an uncontrollable event or the path was already uncontrollable
289  currentControllablePath = rControllableEvents.Exists(tsIt->Ev) || controllablePath;
290  FD_WARN("IsLCC(): record new state " << tsIt->X1 << " cntr=" << currentControllablePath);
291  rLocalStatesMap[tsIt->X1] = currentControllablePath;
292  // as the state has not been visited, yet, it is subject to a new backward reachability
293  backwardVerificationLCC(rTransSetX2EvX1, rControllableEvents, rHighAlph, exitState, tsIt->X1, currentControllablePath, rLocalStatesMap, rDoneStates);
294  }
295  else{ // for an existing state, the controllability value can change from controllable to uncontrollable (if
296  // a new uncontrollable path has been found). It is important to note, that the LCC condition implies that
297  // if there is one uncontrollable path, then the state is flagged uncontrollable except for the case of the
298  // given exitState that is always uncontrollable
299  currentControllablePath = rControllableEvents.Exists(tsIt->Ev) || controllablePath;
300  if(rLocalStatesMap[tsIt->X1] != currentControllablePath && currentControllablePath == false){
301  rLocalStatesMap[tsIt->X1] = false;
302  // as the controllabiity attribute of the current state changed it is subject to a new backward reachability
303  backwardVerificationLCC(rTransSetX2EvX1, rControllableEvents, rHighAlph, exitState, tsIt->X1, false, rLocalStatesMap, rDoneStates);
304  }
305  }
306  }
307  }
308 }
309 
310 */
311 
312 
313 // Naive replacement to test LCC with std. forward search for each state
314 // (complexity is quadratic in the number of states and
315 // linear in the number of events; actual performance is suboptimal,
316 // but I don't see how to get lower complexity)
317 
318 bool IsLCC(const Generator& rLowGen, const EventSet& rControllableEvents, const EventSet& rHighAlph){
319  OP_DF("IsLCC(" << rLowGen.Name() << "," << rHighAlph.Name() << ")");
320  // iteration over all states of rLowGen.
321  StateSet::Iterator sit=rLowGen.StatesBegin();
322  for( ; sit != rLowGen.StatesEnd(); sit++){
323  // forward reachablity to figure all next high-level events
324  StateSet freach;
325  StateSet todo;
326  EventSet hievs;
327  todo.Insert(*sit);
328  while(!todo.Empty()) {
329  // take from todo stack
330  Idx cs = *todo.Begin();
331  todo.Erase(todo.Begin());
332  freach.Insert(cs);
333  // figure next states
334  TransSet::Iterator tit = rLowGen.TransRelBegin(cs);
335  TransSet::Iterator tit_end=rLowGen.TransRelEnd(cs);
336  for( ; tit != tit_end; tit++){
337  if(rHighAlph.Exists(tit->Ev)) {
338  hievs.Insert(tit->Ev);
339  } else {
340  if(!freach.Exists(cs)) todo.Insert(cs);
341  }
342  }
343  }
344  // forward reachablity to figure next high-level events by uncontr. paths
345  EventSet hievs_ucpath;
346  todo.Clear();
347  freach.Clear();
348  todo.Insert(*sit);
349  while(!todo.Empty()) {
350  // take from todo stack
351  Idx cs = *todo.Begin();
352  todo.Erase(todo.Begin());
353  freach.Insert(cs);
354  // figure next states
355  TransSet::Iterator tit = rLowGen.TransRelBegin(cs);
356  TransSet::Iterator tit_end=rLowGen.TransRelEnd(cs);
357  for( ; tit != tit_end; tit++){
358  if(rControllableEvents.Exists(tit->Ev)) continue;
359  if(rHighAlph.Exists(tit->Ev)) {
360  hievs_ucpath.Insert(tit->Ev);
361  } else {
362  if(!freach.Exists(cs)) todo.Insert(cs);
363  }
364  }
365  }
366  // test lcc
367  hievs = hievs - rControllableEvents;
368  hievs_ucpath = hievs_ucpath - rControllableEvents;
369  if(hievs_ucpath != hievs) {
370  OP_DF("IsLCC: failed at state " << rLowGen.SStr(*sit))
371  return false;
372  }
373  }
374  // no issues found
375  OP_DF(y"IsLCC: passed");
376  return true;
377 }
378 
379 
380 }// namespace faudes

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen