syn_supreduce.cpp
Go to the documentation of this file.
1 /** @file syn_supreduce.cpp Supervisor Reduction */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2006 Bernd Opitz
6  Exclusive copyright is granted to Klaus Schmidt
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Lesser General Public
10  License as published by the Free Software Foundation; either
11  version 2.1 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public
19  License along with this library; if not, write to the Free Software
20  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21 
22 
23 #include "syn_supreduce.h"
24 
25 
26 namespace faudes {
27 
28 
29 
30 
31 /*
32 ***************************************************************************************
33 ***************************************************************************************
34  Implementation
35 ***************************************************************************************
36 ***************************************************************************************
37 */
38 
39 
40 // SupReduce(rPlantGen, rSupGen, rReducedSup)
41 bool SupReduce(const System& rPlantGen, const System& rSupGen, System& rReducedSup) {
42  FD_DF("SupReduce...");
43 
44  // CONSISTENCY CHECK:
45 
46  // alphabets must match
47  if (rPlantGen.Alphabet() != rSupGen.Alphabet()) {
48  EventSet only_in_plant = rPlantGen.Alphabet() - rSupGen.Alphabet();
49  EventSet only_in_spec = rSupGen.Alphabet() - rPlantGen.Alphabet();
50  std::stringstream errstr;
51  errstr << "Alphabets of generators do not match. Only in plant: "
52  << only_in_plant.ToString() << ". Only in spec: "
53  << only_in_spec.ToString() << ".";
54  throw Exception("SupReduce", errstr.str(), 100);
55  }
56 
57  // plant and spec must be deterministic
58  bool plant_det = rPlantGen.IsDeterministic();
59  bool sup_det = rSupGen.IsDeterministic();
60 
61  if ((plant_det == false) && (sup_det == true)) {
62  std::stringstream errstr;
63  errstr << "Plant generator must be deterministic, " << "but is nondeterministic";
64  throw Exception("SupReduce", errstr.str(), 201);
65  }
66  else if ((plant_det == true) && (sup_det == false)) {
67  std::stringstream errstr;
68  errstr << "Supervisor generator must be deterministic, " << "but is nondeterministic";
69  throw Exception("SupReduce", errstr.str(), 203);
70  }
71  else if ((plant_det == false) && (sup_det == false)) {
72  std::stringstream errstr;
73  errstr << "Plant and supervisor generator must be deterministic, "
74  << "but both are nondeterministic";
75  throw Exception("SupReduce", errstr.str(), 204);
76  }
77  // Clear the result generator rReducedsup
78  rReducedSup.Clear();
79 
80  // HELPERS:
81  System previousSupReduced = rSupGen;
82  std::vector<StateSet> class2States; // control equivalent states in supervisor
83  std::map<Idx, Idx> state2Class; // map from state Idx to its control equivalent class
84  std::vector<std::set<Idx> > waitList; // list of states for classes to be merged
85  EventSet alwaysEnabledEvents = rSupGen.Alphabet(); // set of events that are never disabled
86  // Initialize the helpers that store information about the equivalence classes
87  StateSet::Iterator sIt, sEndIt;
88  sIt = rSupGen.States().Begin();
89  sEndIt = rSupGen.States().End();
90  for(; sIt != sEndIt; sIt++){ // Note: States are ordered by index
91  class2States.push_back(StateSet() );
92  class2States.back().Insert(*sIt);
93  state2Class[*sIt] = class2States.size() - 1;
94  }
95  // Evaluate the composition of plant and supervisor in order to classify corresponding states
96  System tmp;
97  std::map<std::pair<Idx,Idx>, Idx> reverseCompositionMap;
98  std::map<std::pair<Idx,Idx>, Idx>::const_iterator rcIt, rcEndIt;
99  Parallel(rPlantGen, rSupGen, reverseCompositionMap, tmp);
100  rcIt = reverseCompositionMap.begin();
101  rcEndIt = reverseCompositionMap.end();
102  std::map<Idx,ReductionStateInfo> supStateInfo;
103  std::map<Idx,ReductionStateInfo>::iterator rsIt;
104  // Find the plant states that belong to each supervisor state
105  for(; rcIt != rcEndIt; rcIt++){
106  rsIt = supStateInfo.find(rcIt->first.second);
107  if(rsIt == supStateInfo.end() )
108  supStateInfo[rcIt->first.second] = ReductionStateInfo();
109 
110  supStateInfo[rcIt->first.second].mPlantStates.Insert(rcIt->first.first);
111  }
112  /*std::cout << "States per supervisor state " << std::endl;
113  for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
114  std::cout << "sup state: " << rsIt->first << " plant states " << rsIt->second.mPlantStates.ToString() << std::endl;*/ // REMOVE
115  // Determine the state properties for all supervisor stateset
116  for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++){
117  rsIt->second.mEnabledEvents = rSupGen.ActiveEventSet(rsIt->first); // all events enabled at current state2Class
118  sIt = rsIt->second.mPlantStates.Begin();
119  sEndIt = rsIt->second.mPlantStates.End();
120  rsIt->second.mPlantMarked = false;
121  for(; sIt != sEndIt; sIt++){
122  rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents + rPlantGen.ActiveEventSet(*sIt); // compute active events in plant_det for state *sIt
123  rsIt->second.mPlantMarked = rsIt->second.mPlantMarked || rPlantGen.ExistsMarkedState(*sIt); // compute colors of corresponding plant states
124  }
125 
126  rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents - rsIt->second.mEnabledEvents; // compute disable events (events that are not enabled
127  rsIt->second.mMarkedState = rSupGen.ExistsMarkedState(rsIt->first);
128  alwaysEnabledEvents = alwaysEnabledEvents - rsIt->second.mDisabledEvents; // subtract disabled events from always enabled events
129  }
130  //std::cout << "Always enabled events: " << alwaysEnabledEvents.ToString() << std::endl;
131  // if no events are disabled, then the reduced supervisor has only one state without events
132  if(rSupGen.Alphabet() == alwaysEnabledEvents){
133  Idx state = rReducedSup.InsState();
134  rReducedSup.SetMarkedState(state);
135  rReducedSup.SetInitState(state);
136  return true;
137  }
138  /*for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
139  std::cout << "state: " << rsIt->first << " enabled: " << rsIt->second.mEnabledEvents.ToString() << " disabled: " << rsIt->second.mDisabledEvents.ToString() << std::endl;*/ // REMOVE
140 
141  std::map<Idx,bool> usedEventsMap;
142  EventSet::Iterator eIt = alwaysEnabledEvents.Begin();
143  for( ; eIt != alwaysEnabledEvents.End(); eIt++)// map that indicates if always enabled event is relevant for supervisor (true) or not (false)
144  usedEventsMap[*eIt] = false;
145  // ==========================
146  // Algorithm
147  //===========================
148  // go through all supervisor states
149  std::map<Idx,Idx>::const_iterator mIt;
150  std::map<Idx,Idx>::const_iterator mEndIt = state2Class.end();
151  mEndIt--;
152  std::map<Idx,Idx>::const_iterator mbIt, mbEndIt;
153  mbEndIt = state2Class.end();
154 
155  /* std::cout << "Classes to states" << std::endl;
156  for(unsigned int i = 0; i < class2States.size(); i ++)
157  std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
158 
159  std::cout << "State to class" << std::endl;
160  for(mIt = state2Class.begin(); mIt != state2Class.end(); mIt++)
161  std::cout << "state: " << mIt->first << " class: " << mIt->second << std::endl; */ // REMOVE
162 
163  for(mIt = state2Class.begin(); mIt != mEndIt; mIt++){
164  // Evaluate min{k \in I | x_k \in [x_i]}; since StateSets are ordered by index, this simply means finding the first state in the class of x_i
165  if( mIt->first > *class2States[mIt->second].Begin() ){// state is already in other equivalence class
166  continue;
167  }
168  mbIt = ++mIt;
169  mIt--;
170  //std::cout << "state i: " << mIt->first << std::endl;
171  for(; mbIt != mbEndIt; mbIt++) {// approach from back
172  //if(j > min{k \in I | x_k \in [x_j]}
173  if(mbIt->first > *class2States[mbIt->second].Begin() ){
174  continue;
175  }
176  //std::cout << "state j: " << mbIt->first << std::endl;
177 
178  // Start actual algorithm after filtering
179  waitList.clear();
180  //if((mIt->first == 1 && mbIt->first == 4) ){
181  //waitList.push_back(std::set<Idx>() );
182  //waitList.back().insert(mIt->first);
183  //waitList.back().insert(mbIt->first); REMOVE
184  //}
185  bool flag = CheckMergibility(mIt->first,mbIt->first,waitList,mIt->first, rSupGen, supStateInfo, state2Class, class2States);
186  if(flag == true){// merge classes indicated by waitList
187  std::vector<std::set<Idx> >::const_iterator wlIt, wlEndIt;
188  //std::cout << "size of weitlist " << waitList.size() << std::endl;
189  wlIt = waitList.begin();
190  wlEndIt = waitList.end();
191  for(; wlIt != wlEndIt; wlIt++){// go through waiting list
192  //std::cout << " states " << *wlIt->begin() << " " << *(++wlIt->begin() ) << std::endl;
193  if(state2Class[*wlIt->begin() ] == state2Class[*(++(wlIt->begin() ) ) ])// no action is required if the states are already in the same class
194  continue;
195  class2States[state2Class[*wlIt->begin() ] ] = class2States[state2Class[*wlIt->begin()] ] + class2States[state2Class[*(++(wlIt->begin() ) ) ] ]; // union of state sets of both classes
196  Idx removeClass = state2Class[*(++(wlIt->begin() ) ) ];
197  sIt = class2States[removeClass ].Begin();
198  sEndIt = class2States[removeClass ].End();
199  for(; sIt != sEndIt; sIt++)
200  state2Class[*sIt] = state2Class[*wlIt->begin() ]; // change class of all states that were merged
201 
202  class2States[removeClass ].Clear(); // clear merged class
203 
204  /*std::cout << "Classes to states" << std::endl;
205  for(unsigned int i = 0; i < class2States.size(); i ++)
206  std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
207 
208  std::cout << "State to class" << std::endl;
209  std::map<Idx,Idx>::const_iterator cIt;
210  for(cIt = state2Class.begin(); cIt != state2Class.end(); cIt++)
211  std::cout << "state: " << cIt->first << " class: " << cIt->second << std::endl; */ // REMOVE
212  }
213  }
214  }
215  }
216 
217  // ===============================
218  // Construct the reduced superisor
219  // ===============================
220  // Every state corresponds to a class that we found and we try to avoid adding trnasitions with always enabled events
221  std::map<Idx,Idx> class2ReducedStates;
222  Idx newStateIdx;
223  rReducedSup.InjectAlphabet(rSupGen.Alphabet() );
224  // First generate one state for each class in the reduced generator
225  for(unsigned int i = 0; i < class2States.size(); i++){
226  if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
227  continue;
228  else{// create new state in the reduced supervisor for the class
229  newStateIdx = rReducedSup.InsState();
230  class2ReducedStates[i ] = newStateIdx; // save state for the class
231  }
232  }// all states of the reduced generator are now generated and stored
233 
234  // Now add the transitions to the reduced generator
235  TransSet::Iterator tIt, tEndIt;
236  Idx newGoalState; // goal state for transition to be added
237  for(unsigned int i = 0; i < class2States.size(); i++){
238  if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
239  continue;
240  sIt = class2States[i].Begin();
241  sEndIt = class2States[i].End();
242  newStateIdx = class2ReducedStates[i];
243  for(; sIt != sEndIt; sIt++){// go through all states of the current class
244  if(rSupGen.ExistsInitState(*sIt) )// determine the initial state of the reduced supervisor
245  rReducedSup.InsInitState(newStateIdx);
246 
247  if(rSupGen.ExistsMarkedState(*sIt) )
248  rReducedSup.SetMarkedState(newStateIdx); // insert the supervisor colors per state
249 
250  tIt = rSupGen.TransRelBegin(*sIt); // transitions of state *sIt in supervisor
251  tEndIt = rSupGen.TransRelEnd(*sIt);
252  for( ; tIt != tEndIt; tIt++){
253  newGoalState = class2ReducedStates[state2Class[tIt->X2] ]; // goal state of transition in the reduced supervisor
254  if(alwaysEnabledEvents.Exists(tIt->Ev) == true && newGoalState != newStateIdx )// always enabled event changes class and is thus relevant for supervisor
255  usedEventsMap[tIt->Ev] = true;
256 
257  rReducedSup.SetTransition(newStateIdx, tIt->Ev, newGoalState);
258  }
259  }
260  }
261  if(previousSupReduced.Size() == rReducedSup.Size() ){
262  std::map<Idx,bool>::const_iterator uIt = usedEventsMap.begin();
263  for(; uIt != usedEventsMap.end(); uIt++){// delete the unused events from the reduced supervisor
264  if(uIt->second == false){
265  rReducedSup.DelEvent(uIt->first);
266  }
267  }
268  }
269  else{
270  previousSupReduced.Clear();
271  Deterministic(rReducedSup,previousSupReduced);
272  SupReduce(rPlantGen,previousSupReduced,rReducedSup);
273  }
274  return true;
275 }
276 
277 // CheckMergibility(statep, stateq, rWaitingList, cNode)
278 bool CheckMergibility(Idx stateI, Idx stateJ, std::vector<std::set<Idx> >& rWaitList, Idx cNode, const System& rSupGen,
279  const std::map<Idx,ReductionStateInfo>& rSupStateInfo, const std::map<Idx,Idx>& rState2Class, const std::vector<StateSet>& rClass2States){
280  // Loop through all state combinations in the current classes
281  //std::cout << "stateI " << stateI << " stateJ " << stateJ << " show Waitlist" << std::endl;
282  /* for(unsigned int i = 0; i < rWaitList.size(); i++)
283  std::cout << *rWaitList[i].begin() << " " << *(++rWaitList[i].begin() ) << std::endl;*/
284  StateSet::Iterator siIt, siEndIt, sjIt, sjEndIt;
285  StateSet statesI, statesJ;
286  statesI = rClass2States[rState2Class.find(stateI)->second]; // all states of the class of stateI
287  statesJ = rClass2States[rState2Class.find(stateJ)->second ]; // all states of the class of stateJ
288  // add the states on the waitlist to statesI and statesJ
289  for(unsigned int i = 0; i < rWaitList.size(); i++){
290  // StateI
291  if(*rWaitList[i].begin() == stateI )
292  statesI = statesI + rClass2States[rState2Class.find(*(++rWaitList[i].begin() ) )->second]; // add classes for corresponding state on waitList
293  if(*(++rWaitList[i].begin() ) == stateI )
294  statesI = statesI + rClass2States[rState2Class.find(*rWaitList[i].begin() )->second]; // add classes for corresponding state on waitList
295  // StateJ
296  if(*rWaitList[i].begin() == stateJ )
297  statesJ = statesJ + rClass2States[rState2Class.find(*(++rWaitList[i].begin() ) )->second]; // add classes for corresponding state on waitList
298  if(*(++rWaitList[i].begin() ) == stateJ )
299  statesJ = statesJ + rClass2States[rState2Class.find(*rWaitList[i].begin() )->second]; // add classes for corresponding state on waitList
300  }
301  //std::cout << "statesI " << statesI.ToString() << " stateJ " << statesJ.ToString() << std::endl;// REMOVE
302  siIt = statesI.Begin(); // Iterators for states of class for stateI
303  siEndIt = statesI.End();
304  sjIt = statesJ.Begin(); // Iterators for states of class for stateJ
305  sjEndIt = statesJ.End();
306  std::set<Idx> statePair;
307  for( ; siIt != siEndIt; siIt++){// loop over states for stateI
308  sjIt = statesJ.Begin();
309  for(; sjIt != sjEndIt; sjIt++){ // loop over states for stateJ
310  // only look at state pairs that are not already in the same class2ReducedStates
311  if(rClass2States[rState2Class.find(*siIt)->second].Exists(*sjIt) )
312  continue;
313 
314  statePair.clear();
315  statePair.insert(*siIt);
316  statePair.insert(*sjIt);
317  //std::cout << "mergibility states: " << *siIt << " and " << *sjIt << std::endl;
318 
319  if(*siIt == *sjIt)
320  continue;
321  bool continueLoop = false;
322  for(unsigned int i = 0; i < rWaitList.size(); i++)
323  if(rWaitList[i] == statePair){
324  continueLoop = true;
325  break;
326  }
327  if(continueLoop == true)// the current state pair is already on the waiting list
328  continue;
329 
330  // tmoor: fix nonstandard std::map::at()
331  const ReductionStateInfo& siinf=rSupStateInfo.find(*siIt)->second;
332  const ReductionStateInfo& sjinf=rSupStateInfo.find(*sjIt)->second;
333 
334  // Check if the state pair belongs to the control relation \mathcal{R}:
335  // E(*siIt) \cap D(*sjIt) = E(*sjIt) \cap D(*siIt) = \emptyset and C(*siIt) = C(*sjIt) \Rightarrow M(*siIt) = M(*sjIt)
336  if( !(siinf.mEnabledEvents * sjinf.mDisabledEvents).Empty() ) return false;
337  if( !(sjinf.mEnabledEvents * siinf.mDisabledEvents).Empty() ) return false;
338 
339  // Check if the marking of the states is consistent
340  if( (siinf.mPlantMarked == sjinf.mPlantMarked) && (siinf.mPlantMarked != sjinf.mPlantMarked) )
341  return false;
342 
343 
344 
345  /*
346  // original (for reference)
347 
348  // Check if the state pair belongs to the control relation \mathcal{R}:
349  // E(*siIt) \cap D(*sjIt) = E(*sjIt) \cap D(*siIt) = \emptyset and C(*siIt) = C(*sjIt) \Rightarrow M(*siIt) = M(*sjIt)
350  if( !(rSupStateInfo.at(*siIt).mEnabledEvents * rSupStateInfo.at(*sjIt).mDisabledEvents).Empty() ||
351  !(rSupStateInfo.at(*sjIt).mEnabledEvents * rSupStateInfo.at(*siIt).mDisabledEvents).Empty() )
352  return false;
353 
354  // Check if the marking of the states is consistent
355  if( (rSupStateInfo.at(*siIt).mPlantMarked == rSupStateInfo.at(*sjIt).mPlantMarked) && (rSupStateInfo.at(*siIt).mPlantMarked != rSupStateInfo.at(*sjIt).mPlantMarked) )
356  return false;
357 
358  */
359  rWaitList.push_back(std::set<Idx>() );
360  rWaitList.back().insert(*siIt);
361  rWaitList.back().insert(*sjIt);
362 
363  EventSet sharedEvents = rSupGen.ActiveEventSet(*siIt) * rSupGen.ActiveEventSet(*sjIt);
364  EventSet::Iterator eIt, eEndIt;
365  eIt = sharedEvents.Begin();
366  eEndIt = sharedEvents.End();
367  Idx goalStateI, goalStateJ;
368  for( ; eIt != eEndIt; eIt++){// go over all shared active events of the current states
369  goalStateI = (rSupGen.TransRelBegin(*siIt,*eIt) )->X2;
370  goalStateJ = (rSupGen.TransRelBegin(*sjIt,*eIt) )->X2;
371  if(*rState2Class.find( goalStateI ) == *rState2Class.find( goalStateJ ) )// event leads to same class
372  continue;
373  statePair.clear();
374  statePair.insert(goalStateI);
375  statePair.insert(goalStateJ);
376  continueLoop = false;
377  for(unsigned int i = 0; i < rWaitList.size(); i++){
378  if(rWaitList[i] == statePair)// the current goal state pair is already on the waiting list
379  continueLoop = true;
380  break;
381  }
382  if(continueLoop == true)// the current state pair is already on the waiting list
383  continue;
384 
385  // find classes of goalStateI and goalStateJ and check if they are already merged
386  if( *(rClass2States.at( rState2Class.find(goalStateI)->second ).Begin() ) < cNode)
387  return false;
388  if( *(rClass2States.at(rState2Class.find(goalStateJ)->second ).Begin() ) < cNode)
389  return false;
390  bool flag = CheckMergibility(goalStateI, goalStateJ, rWaitList, cNode, rSupGen, rSupStateInfo, rState2Class, rClass2States);
391  if(flag == false){
392  return false;
393  }
394  }
395  }
396  }
397  return true;
398 }
399 
400 } // name space

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