mtc_observercomputation.cpp
Go to the documentation of this file.
1 /** @file mtc_observercomputation.cpp
2 
3 Methods to compute natural projections that exhibit the obsrver property.
4 The observer algorithm is elaborated in
5 K. C. Wong and W. M. Wonham, "On the Computation of Observers in Discrete Event
6 Systems," Discrete Event Dynamic Systems, vol. 14, no. 1, pp. 55-107, 2004.
7 In addition, methods to compute natural projections that exhibit
8 output control consistency (OCC) and 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 */
31 
33 #include "cfl_localgen.h"
34 
35 using namespace std;
36 namespace faudes{
37 
38 
39 // calcNaturalObserver(rGen,rHighAlph)
40 Idx calcNaturalObserver(const MtcSystem& rGen, EventSet& rHighAlph){
41  // helpers
42  Generator dynGen;
43  map<Idx,Idx> mapStateToPartition;
44  vector<Idx> newPartitions;
45  EventSet origAlph;
46  Generator genPart;
47  while(origAlph != rHighAlph){
48  origAlph = rHighAlph;
49  // compute the dynamic system for the given generator and high-level alphabet
50  calculateDynamicSystemObs(rGen, rHighAlph, dynGen);
51  // compute the quasi conqruence
52  mapStateToPartition.clear();
53  newPartitions.clear();
54  genPart.Clear();
55  calcBisimulation(dynGen, mapStateToPartition, genPart, newPartitions);
56  // Extend the high-level alphabet according to the algorithm of Lei
57  ExtendHighAlphabet(rGen, rHighAlph, mapStateToPartition);
58  }
59  return genPart.Size();
60 }
61 
62 // calcAbstAlphObs(rGenObs, rHighAlph, rNewHighAlph, rMapRelabeledEvents)
63 void calcAbstAlphObs(MtcSystem& rGenObs, EventSet& rHighAlph, EventSet& rNewHighAlph, map<Idx,set<Idx > > & rMapRelabeledEvents) {
64  OP_DF("calcAbstAlphObs(" << rGenObs.Name() << "," << "rHighAlph, rNewHighAlph, rMapRelabeledEvents)");
65  // The controllable events are separated from the System. All functions that are successively
66  // called, are defined for Generators
67  EventSet cntrevs = rGenObs.ControllableEvents();
68  calcAbstAlphObs(rGenObs, cntrevs , rHighAlph, rNewHighAlph, rMapRelabeledEvents);
69  // the controllable events that have been changed by the called function are set in the System cGenObs
70  rGenObs.SetControllable(cntrevs);
71 }
72 
73 // calcAbstAlphObs(rGenObs, rControllableEvents, rHighAlph, rNewHighAlph, rMapRelabeledEvents)
74 void calcAbstAlphObs(MtcSystem& rGenObs, EventSet& rControllableEvents, EventSet& rHighAlph, EventSet& rNewHighAlph, map<Idx,set<Idx > > & rMapRelabeledEvents) {
75  OP_DF("calcAbstAlphObs(" << rGenObs.Name() << "," << "rControllableEvents, rHighAlph, rNewHighAlph, rMapRelabeledEvents)");
76  // The function called next returns a relabeled generator and a map of relabeled transitions
77  map<Transition,Idx> changedtrans;
78  calcAbstAlphObs(rGenObs, rControllableEvents, rHighAlph, rNewHighAlph, changedtrans);
79  // for later use, the relabeled transitions are converted into relabeled events
80  // note that this function is accumulative, i.e., rMapRelabeledEvents need not be empty
81  map<Transition,Idx>::iterator rtEndIt = changedtrans.end();
82  map<Transition,Idx>::iterator rtIt = changedtrans.begin();
83  for(; rtIt != rtEndIt; rtIt++){
84  if(rMapRelabeledEvents.find(rtIt->first.Ev) == rMapRelabeledEvents.end() ){// if the event does not exist, yet, a nex element in the map is created
85  rMapRelabeledEvents[rtIt->first.Ev] = set<Idx>();
86  if(rGenObs.Alphabet().Exists(rtIt->second) )// FIXME: there seem to be relabeled transitions that do not exist
87  rMapRelabeledEvents[rtIt->first.Ev].insert(rtIt->second);
88  }
89  else { // a new label is inserted into the map
90  if(rGenObs.Alphabet().Exists(rtIt->second) )// FIXME: there seem to be relabeled transitions that do not exist
91  rMapRelabeledEvents[rtIt->first.Ev].insert(rtIt->second);
92  }
93  }
94 }
95 
96 // calcAbstAlphObs(rGenObs, rControllableEvents, rHighAlph, rNewHighAlph, rMapChangedTrans)
97 void calcAbstAlphObs(MtcSystem& rGenObs, EventSet& rControllableEvents, EventSet& rHighAlph, EventSet& rNewHighAlph, map<Transition,Idx>& rMapChangedTrans)
98 {
99  OP_DF("calcAbstAlphObs(" << rGenObs.Name() << ", rControllableEvents, rHighAlph, rNewHighAlph, rMapChangedTRans)");
100  // Initialization of variables
101  rNewHighAlph = rHighAlph;
102  rMapChangedTrans.clear();
103  Generator genDyn(rGenObs);
104  map<Transition,Transition> mapChangedTransReverse;
105  vector<Idx> newPartitions;
106  map<Idx,Idx> mapStateToPartition;
107  map<Idx, EventSet> mapRelabeledEvents;
108  bool done=false;
109  #ifdef DF_PLOT
110  Idx iterationCount=1;
111  string name;
112  #endif
113  // observer algorithm: In each step, a dynamic system is computed that fulfills the one-step observer condition.
114  // Iterative application of the bisimulation algorithm and the relabeling procedure yields an automaton rGenObs
115  // that, together with the new high-level alphabet rNewHighAlph fulfills the observer condition.
116  while(done==false)
117  {
118  // compute dynamic system for Lm-observer on rGenObs
119  calculateDynamicSystemObs(rGenObs, rNewHighAlph, genDyn);
120  #ifdef DF_PLOT
121  name = ("./Automata/Plots/" + rGenObs.Name() + "DynamicSystem_" + ToStringInteger(iterationCount));
122  genDyn.DotWrite(name);
123  #endif
124 
125  Generator genPart;
126  mapStateToPartition.clear();
127  newPartitions.clear();
128 
129  // compute coarsest quasi-congruence on the dynamic system
130  calcBisimulation(genDyn, mapStateToPartition, genPart, newPartitions);
131  #ifdef DF_PLOT
132  name = ("./Automata/Plots/" + rGenObs.Name() + "Bisimulation_" + ToStringInteger(iterationCount));
133  genPart.DotWrite(name);
134  ++iterationCount;
135  #endif
136 
137  // check if quotient automaton is deterministic and free of unobservable events
138  // and relabel transitions in rGenObs if necessary. The high-level alphabet is modified accordingly
139  done=relabel(rGenObs, rControllableEvents, rNewHighAlph, newPartitions, mapStateToPartition, mapChangedTransReverse, rMapChangedTrans, mapRelabeledEvents);
140  }
141 }
142 
143 // calculateDynamicSystemObs(rGen, rHighAlph, rGenDyn)
144 void calculateDynamicSystemObs(const MtcSystem& rGen, EventSet& rHighAlph, Generator& rGenDyn)
145 {
146  OP_DF("calculateDynamicSystemObs(" << rGen.Name() << "," << rHighAlph.Name() << "," << rGenDyn.Name() << ")");
147  // transition relation sorted in reverse order for backwards reachability
148  TransSetX2EvX1 tset_X2EvX1;
149  rGen.TransRel(tset_X2EvX1);
150 
151  // prepare generator rGenDyn
152  rGenDyn.ClearTransRel();
153  rGenDyn.InjectAlphabet(rHighAlph); // all high-level events are contained in the alphabet of rGenDyn
154 
155  // helpers
156  EventSet::Iterator eIt = rGenDyn.AlphabetBegin();
157  EventSet::Iterator eItEnd = rGenDyn.AlphabetEnd();
158 
159  TransSetX2EvX1::Iterator tItByX2Ev;
160  TransSetX2EvX1::Iterator tItByX2EvEnd;
161  StateSet reach;
162  StateSet::Iterator sIt;
163  StateSet::Iterator sItEnd;
164  TransSet::Iterator tIt;
165  TransSet::Iterator tItEnd;
166  map<Idx,StateSet> entryStateToLocalReach;
167  set<Idx>::iterator esIt, esItEnd;
168  // map that maps a state (first Idx) to a reachable entry state (second Idx) via a high-level event (third Idx)
169  map<Idx,vector<pair<Idx,Idx> > > stateToEntryState;
170  map<Idx,vector<pair<Idx,Idx> > >::iterator stesIt;
171  map<Idx,vector<pair<Idx,Idx> > >::iterator stesItEnd;
172 
173  // generate the color labels for the dynamic system
174  ColorSet allColors = rGen.Colors();
175  ColorSet::Iterator csIt, csEndIt;
176  csIt = allColors.Begin();
177  csEndIt = allColors.End();
178  std::string colorLabel;
179  // maps a unique color index to the index of the associated transition label in teh dynamic system
180  map<Idx,Idx> colorEventMap;
181  for(; csIt != csEndIt; csIt++){
182  colorLabel = ( rGenDyn.EventSymbolTablep())->UniqueSymbol("colorLabel" + rGen.ColorName(*csIt) + "_1");
183  colorEventMap[*csIt] = (rGenDyn.EventSymbolTablep())->InsEntry(colorLabel);
184  }
185 
186  // algorithm for computing the dynamic system
187 
188  // loop over all states of original generator
189  StateSet::Iterator stateSetIt = rGen.StatesBegin();
190  StateSet::Iterator stateSetItEnd = rGen.StatesEnd();
191  for( ; stateSetIt != stateSetItEnd; ++stateSetIt) {
192  OP_DF("calculateDynamicSystemObs: loop over all states; current state: " << rGen.StateName(*stateSetIt)
193  << " [" << *stateSetIt << "]");
194 
195  // compute locally reachable states for current state
196  reach.Clear();
197  LocalAccessibleReach(rGen, rHighAlph, *stateSetIt, reach);
198  OP_DF("calculateDynamicSystemObs: states in local reach: \n " << reach.ToString() );
199 
200  // check if current state (*stateSetIt) is an entry-state (a backward transition with
201  // a high-level event exists. If yes, the locally reachable states (reach) are stored in
202  // the entryStateToLocalReach map
203  tItByX2Ev=tset_X2EvX1.BeginByX2(*stateSetIt);
204  tItByX2EvEnd=tset_X2EvX1.EndByX2(*stateSetIt);
205  for(; tItByX2Ev != tItByX2EvEnd; ++tItByX2Ev)
206  {
207  OP_DF("calculateDynamicSystemObs: checking transition : " << rGen.TStr(*tItByX2Ev));
208  if(rHighAlph.Exists(tItByX2Ev->Ev)){
209  OP_DF("calculateDynamicSystemObs: current state is an entry-state");
210  // map entry-state to its locally reachable states
211  entryStateToLocalReach[*stateSetIt]=reach;
212  break;
213  }
214  }
215  vector<pair<Idx,Idx> > emptyVector;
216  stateToEntryState[*stateSetIt]=emptyVector;
217  // loop over all states in the local reach of current state to determine which marked states
218  // are locally reachable and to determine which high-level events can occur after local strings
219  sIt=reach.Begin();
220  sItEnd=reach.End();
221  Idx colorEvent;
222  for( ; sIt != sItEnd; ++sIt)
223  {
224  // check if state sIt is marked; if yes, create an m-transition (mLabel) between current state and sIt
225  const ColorSet& stateColors = rGen.Colors(*sIt);
226  csIt = stateColors.Begin();
227  csEndIt = stateColors.End();
228  for( ; csIt != csEndIt; csIt++){
229  OP_DF("calculateDynamicSystemObs: marked state " << rGen.SStr(*sIt)
230  << " is locally reachable from current state");
231  colorEvent = colorEventMap[*csIt];
232  rGenDyn.InsEvent(colorEvent ); // ??
233  rGenDyn.InsState(*stateSetIt); // ??
234  rGenDyn.InsState(*sIt); //??
235  rGenDyn.SetTransition(*stateSetIt, colorEvent, *sIt);
236  }
237  // loop over all transitions of current state sIt to determine if high-level events are possible
238  tIt = rGen.TransRelBegin(*sIt);
239  tItEnd = rGen.TransRelEnd(*sIt);
240  for(; tIt != tItEnd; ++tIt)
241  {
242  OP_DF("calculateDynamicSystemObs: Loop over all states in reach; checking transition: "
243  << rGen.TStr(*tIt));
244  if(rHighAlph.Exists(tIt->Ev))
245  {
246  OP_DF("calculateDynamicSystemObs: state " << rGen.SStr(tIt->X2) <<
247  " is an entry state and can be reached from current state" << rGen.SStr(*stateSetIt) << " by event " << rGen.EventName(tIt->Ev));
248  pair<Idx,Idx> newPair;
249  newPair.first=tIt->X2;
250  newPair.second=tIt->Ev;
251  // store the reachable entry state and the corresponding high-level event
252  stateToEntryState[*stateSetIt].push_back(newPair);
253  }
254  }
255  }
256  }
257 
258  // create the transition structure of the dynamic system
259  stesIt = stateToEntryState.begin();
260  stesItEnd = stateToEntryState.end();
261  vector<pair <Idx,Idx> >* pPairs;
262  vector<pair <Idx,Idx> >::iterator vIt;
263  vector<pair <Idx,Idx> >::iterator vItEnd;
264  // To construct the dynamic system, each local state has to be connected to all states in
265  // the local accessible reach of entry states that can be reached via a high-level event.
266  // This information is contained in the stateToEntryState map combined with the entryStateToLocalReach map.
267  // iteration over all entries (X1) of map stateToEntryState
268  for(; stesIt != stesItEnd; ++stesIt)
269  {
270  pPairs=&(stesIt->second);
271  vIt = (*pPairs).begin();
272  vItEnd = (*pPairs).end();
273  // loop over all pairs (Ev,X2) of current entry
274  for( ; vIt != vItEnd; ++vIt)
275  {
276  // check if transition already exists
277  if(!((rGenDyn.TransRel()).Exists(stesIt->first,vIt->second,vIt->first)))
278  {
279  // find local reach of entry state X2
280  StateSet* pLocalReach = &((entryStateToLocalReach.find(vIt->first))->second);
281 
282  // Add a Ev-transition from X1 to every state in the local reach of X2
283  StateSet::Iterator lrsIt = pLocalReach->Begin();
284  StateSet::Iterator lrsItEnd = pLocalReach->End();
285  for(; lrsIt != lrsItEnd; ++lrsIt)
286  {
287  rGenDyn.InsEvent(vIt->second); // ??
288  rGenDyn.InsState(stesIt->first); // ??
289  rGenDyn.InsState(*lrsIt); //??
290  rGenDyn.SetTransition(stesIt->first,vIt->second,*lrsIt);
291  OP_DF("calculateDynamicSystemObs: Transition added to resulting generator: " <<
292  rGenDyn.TStr(Transition(stesIt->first,vIt->second,*lrsIt)));
293  }
294  }
295  }
296  }
297  OP_DF("calculateDynamicSystemObs: leaving function");
298 }
299 
300 }

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