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 /**
41  * Data structure for identifying states in the same coset for supervisor reduction
42  */
49 };
50 
51 
52 /*
53 Reduction mergibility algorithm
54 
55 This recursive algorithm determines if two supervisor states can be merged to the same coset.
56 It is called by the main procedure SupReduce.
57 -- stateI, stateJ: pair of states to be tested
58 -- rWaitList: list of waiting state pairs
59 -- cNode: record first state to be checked
60 -- rSupGen: const ref to supervisor
61 -- rSupStateInfo: ref to state info
62 -- rState2Class: const ref to state->coset map
63 -- rClass2State: const ref to coset->states
64 
65 return True if the classes of the two states can be merged
66 */
67 
68 bool CheckMergibility(Idx stateI, Idx stateJ, std::vector<std::set<Idx> >& rWaitList, Idx cNode, const System& rSupGen,
69  const std::map<Idx,ReductionStateInfo>& rSupStateInfo, const std::map<Idx,Idx>& rState2Class, const std::vector<StateSet>& rClass2States){
70  // Loop through all state combinations in the current classes
71  //std::cout << "stateI " << stateI << " stateJ " << stateJ << " show Waitlist" << std::endl;
72  /* for(unsigned int i = 0; i < rWaitList.size(); i++)
73  std::cout << *rWaitList[i].begin() << " " << *(++rWaitList[i].begin() ) << std::endl;*/
74  StateSet::Iterator siIt, siEndIt, sjIt, sjEndIt;
75  StateSet statesI, statesJ;
76  statesI = rClass2States[rState2Class.find(stateI)->second]; // all states of the class of stateI
77  statesJ = rClass2States[rState2Class.find(stateJ)->second ]; // all states of the class of stateJ
78  // add the states on the waitlist to statesI and statesJ
79  for(unsigned int i = 0; i < rWaitList.size(); i++){
80  // StateI
81  if(*rWaitList[i].begin() == stateI )
82  statesI = statesI + rClass2States[rState2Class.find(*(++rWaitList[i].begin() ) )->second]; // add classes for corresponding state on waitList
83  if(*(++rWaitList[i].begin() ) == stateI )
84  statesI = statesI + rClass2States[rState2Class.find(*rWaitList[i].begin() )->second]; // add classes for corresponding state on waitList
85  // StateJ
86  if(*rWaitList[i].begin() == stateJ )
87  statesJ = statesJ + rClass2States[rState2Class.find(*(++rWaitList[i].begin() ) )->second]; // add classes for corresponding state on waitList
88  if(*(++rWaitList[i].begin() ) == stateJ )
89  statesJ = statesJ + rClass2States[rState2Class.find(*rWaitList[i].begin() )->second]; // add classes for corresponding state on waitList
90  }
91  //std::cout << "statesI " << statesI.ToString() << " stateJ " << statesJ.ToString() << std::endl;// REMOVE
92  siIt = statesI.Begin(); // Iterators for states of class for stateI
93  siEndIt = statesI.End();
94  sjIt = statesJ.Begin(); // Iterators for states of class for stateJ
95  sjEndIt = statesJ.End();
96  std::set<Idx> statePair;
97  for( ; siIt != siEndIt; siIt++){// loop over states for stateI
98  sjIt = statesJ.Begin();
99  for(; sjIt != sjEndIt; sjIt++){ // loop over states for stateJ
100  // only look at state pairs that are not already in the same class2ReducedStates
101  if(rClass2States[rState2Class.find(*siIt)->second].Exists(*sjIt) )
102  continue;
103 
104  statePair.clear();
105  statePair.insert(*siIt);
106  statePair.insert(*sjIt);
107  //std::cout << "mergibility states: " << *siIt << " and " << *sjIt << std::endl;
108 
109  if(*siIt == *sjIt)
110  continue;
111  bool continueLoop = false;
112  for(unsigned int i = 0; i < rWaitList.size(); i++)
113  if(rWaitList[i] == statePair){
114  continueLoop = true;
115  break;
116  }
117  if(continueLoop == true)// the current state pair is already on the waiting list
118  continue;
119 
120  // tmoor: fix nonstandard std::map::at()
121  const ReductionStateInfo& siinf=rSupStateInfo.find(*siIt)->second;
122  const ReductionStateInfo& sjinf=rSupStateInfo.find(*sjIt)->second;
123 
124  // Check if the state pair belongs to the control relation \mathcal{R}:
125  // E(*siIt) \cap D(*sjIt) = E(*sjIt) \cap D(*siIt) = \emptyset and C(*siIt) = C(*sjIt) \Rightarrow M(*siIt) = M(*sjIt)
126  if( !(siinf.mEnabledEvents * sjinf.mDisabledEvents).Empty() ) return false;
127  if( !(sjinf.mEnabledEvents * siinf.mDisabledEvents).Empty() ) return false;
128 
129  // Check if the marking of the states is consistent
130  if( (siinf.mPlantMarked == sjinf.mPlantMarked) && (siinf.mPlantMarked != sjinf.mPlantMarked) )
131  return false;
132 
133 
134 
135  /*
136  // original (for reference)
137 
138  // Check if the state pair belongs to the control relation \mathcal{R}:
139  // E(*siIt) \cap D(*sjIt) = E(*sjIt) \cap D(*siIt) = \emptyset and C(*siIt) = C(*sjIt) \Rightarrow M(*siIt) = M(*sjIt)
140  if( !(rSupStateInfo.at(*siIt).mEnabledEvents * rSupStateInfo.at(*sjIt).mDisabledEvents).Empty() ||
141  !(rSupStateInfo.at(*sjIt).mEnabledEvents * rSupStateInfo.at(*siIt).mDisabledEvents).Empty() )
142  return false;
143 
144  // Check if the marking of the states is consistent
145  if( (rSupStateInfo.at(*siIt).mPlantMarked == rSupStateInfo.at(*sjIt).mPlantMarked) && (rSupStateInfo.at(*siIt).mPlantMarked != rSupStateInfo.at(*sjIt).mPlantMarked) )
146  return false;
147 
148  */
149  rWaitList.push_back(std::set<Idx>() );
150  rWaitList.back().insert(*siIt);
151  rWaitList.back().insert(*sjIt);
152 
153  EventSet sharedEvents = rSupGen.ActiveEventSet(*siIt) * rSupGen.ActiveEventSet(*sjIt);
154  EventSet::Iterator eIt, eEndIt;
155  eIt = sharedEvents.Begin();
156  eEndIt = sharedEvents.End();
157  Idx goalStateI, goalStateJ;
158  for( ; eIt != eEndIt; eIt++){// go over all shared active events of the current states
159  goalStateI = (rSupGen.TransRelBegin(*siIt,*eIt) )->X2;
160  goalStateJ = (rSupGen.TransRelBegin(*sjIt,*eIt) )->X2;
161  if(*rState2Class.find( goalStateI ) == *rState2Class.find( goalStateJ ) )// event leads to same class
162  continue;
163  statePair.clear();
164  statePair.insert(goalStateI);
165  statePair.insert(goalStateJ);
166  continueLoop = false;
167  for(unsigned int i = 0; i < rWaitList.size(); i++){
168  if(rWaitList[i] == statePair)// the current goal state pair is already on the waiting list
169  continueLoop = true;
170  break;
171  }
172  if(continueLoop == true)// the current state pair is already on the waiting list
173  continue;
174 
175  // find classes of goalStateI and goalStateJ and check if they are already merged
176  if( *(rClass2States.at( rState2Class.find(goalStateI)->second ).Begin() ) < cNode)
177  return false;
178  if( *(rClass2States.at(rState2Class.find(goalStateJ)->second ).Begin() ) < cNode)
179  return false;
180  bool flag = CheckMergibility(goalStateI, goalStateJ, rWaitList, cNode, rSupGen, rSupStateInfo, rState2Class, rClass2States);
181  if(flag == false){
182  return false;
183  }
184  }
185  }
186  }
187  return true;
188 }
189 
190 
191 
192 
193 // SupReduce(rPlantGen, rSupGen, rReducedSup)
194 bool SupReduce(const System& rPlantGen, const System& rSupGen, System& rReducedSup) {
195  FD_DF("SupReduce...");
196 
197  // CONSISTENCY CHECK:
198 
199  // alphabets must match
200  if (rPlantGen.Alphabet() != rSupGen.Alphabet()) {
201  EventSet only_in_plant = rPlantGen.Alphabet() - rSupGen.Alphabet();
202  EventSet only_in_spec = rSupGen.Alphabet() - rPlantGen.Alphabet();
203  std::stringstream errstr;
204  errstr << "Alphabets of generators do not match. Only in plant: "
205  << only_in_plant.ToString() << ". Only in spec: "
206  << only_in_spec.ToString() << ".";
207  throw Exception("SupReduce", errstr.str(), 100);
208  }
209 
210  // plant and spec must be deterministic
211  bool plant_det = rPlantGen.IsDeterministic();
212  bool sup_det = rSupGen.IsDeterministic();
213 
214  if ((plant_det == false) && (sup_det == true)) {
215  std::stringstream errstr;
216  errstr << "Plant generator must be deterministic, " << "but is nondeterministic";
217  throw Exception("SupReduce", errstr.str(), 201);
218  }
219  else if ((plant_det == true) && (sup_det == false)) {
220  std::stringstream errstr;
221  errstr << "Supervisor generator must be deterministic, " << "but is nondeterministic";
222  throw Exception("SupReduce", errstr.str(), 203);
223  }
224  else if ((plant_det == false) && (sup_det == false)) {
225  std::stringstream errstr;
226  errstr << "Plant and supervisor generator must be deterministic, "
227  << "but both are nondeterministic";
228  throw Exception("SupReduce", errstr.str(), 204);
229  }
230  // Clear the result generator rReducedsup
231  rReducedSup.Clear();
232 
233  // HELPERS:
234  System previousSupReduced = rSupGen;
235  std::vector<StateSet> class2States; // control equivalent states in supervisor
236  std::map<Idx, Idx> state2Class; // map from state Idx to its control equivalent class
237  std::vector<std::set<Idx> > waitList; // list of states for classes to be merged
238  EventSet alwaysEnabledEvents = rSupGen.Alphabet(); // set of events that are never disabled
239  // Initialize the helpers that store information about the equivalence classes
240  StateSet::Iterator sIt, sEndIt;
241  sIt = rSupGen.States().Begin();
242  sEndIt = rSupGen.States().End();
243  for(; sIt != sEndIt; sIt++){ // Note: States are ordered by index
244  class2States.push_back(StateSet() );
245  class2States.back().Insert(*sIt);
246  state2Class[*sIt] = class2States.size() - 1;
247  }
248  // Evaluate the composition of plant and supervisor in order to classify corresponding states
249  System tmp;
250  std::map<std::pair<Idx,Idx>, Idx> reverseCompositionMap;
251  std::map<std::pair<Idx,Idx>, Idx>::const_iterator rcIt, rcEndIt;
252  Parallel(rPlantGen, rSupGen, reverseCompositionMap, tmp);
253  rcIt = reverseCompositionMap.begin();
254  rcEndIt = reverseCompositionMap.end();
255  std::map<Idx,ReductionStateInfo> supStateInfo;
256  std::map<Idx,ReductionStateInfo>::iterator rsIt;
257  // Find the plant states that belong to each supervisor state
258  for(; rcIt != rcEndIt; rcIt++){
259  rsIt = supStateInfo.find(rcIt->first.second);
260  if(rsIt == supStateInfo.end() )
261  supStateInfo[rcIt->first.second] = ReductionStateInfo();
262 
263  supStateInfo[rcIt->first.second].mPlantStates.Insert(rcIt->first.first);
264  }
265  /*std::cout << "States per supervisor state " << std::endl;
266  for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
267  std::cout << "sup state: " << rsIt->first << " plant states " << rsIt->second.mPlantStates.ToString() << std::endl;*/ // REMOVE
268  // Determine the state properties for all supervisor stateset
269  for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++){
270  rsIt->second.mEnabledEvents = rSupGen.ActiveEventSet(rsIt->first); // all events enabled at current state2Class
271  sIt = rsIt->second.mPlantStates.Begin();
272  sEndIt = rsIt->second.mPlantStates.End();
273  rsIt->second.mPlantMarked = false;
274  for(; sIt != sEndIt; sIt++){
275  rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents + rPlantGen.ActiveEventSet(*sIt); // compute active events in plant_det for state *sIt
276  rsIt->second.mPlantMarked = rsIt->second.mPlantMarked || rPlantGen.ExistsMarkedState(*sIt); // compute colors of corresponding plant states
277  }
278 
279  rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents - rsIt->second.mEnabledEvents; // compute disable events (events that are not enabled
280  rsIt->second.mMarkedState = rSupGen.ExistsMarkedState(rsIt->first);
281  alwaysEnabledEvents = alwaysEnabledEvents - rsIt->second.mDisabledEvents; // subtract disabled events from always enabled events
282  }
283  //std::cout << "Always enabled events: " << alwaysEnabledEvents.ToString() << std::endl;
284  // if no events are disabled, then the reduced supervisor has only one state without events
285  if(rSupGen.Alphabet() == alwaysEnabledEvents){
286  Idx state = rReducedSup.InsState();
287  rReducedSup.SetMarkedState(state);
288  rReducedSup.SetInitState(state);
289  return true;
290  }
291  /*for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
292  std::cout << "state: " << rsIt->first << " enabled: " << rsIt->second.mEnabledEvents.ToString() << " disabled: " << rsIt->second.mDisabledEvents.ToString() << std::endl;*/ // REMOVE
293 
294  std::map<Idx,bool> usedEventsMap;
295  EventSet::Iterator eIt = alwaysEnabledEvents.Begin();
296  for( ; eIt != alwaysEnabledEvents.End(); eIt++)// map that indicates if always enabled event is relevant for supervisor (true) or not (false)
297  usedEventsMap[*eIt] = false;
298  // ==========================
299  // Algorithm
300  //===========================
301  // go through all supervisor states
302  std::map<Idx,Idx>::const_iterator mIt;
303  std::map<Idx,Idx>::const_iterator mEndIt = state2Class.end();
304  mEndIt--;
305  std::map<Idx,Idx>::const_iterator mbIt, mbEndIt;
306  mbEndIt = state2Class.end();
307 
308  /* std::cout << "Classes to states" << std::endl;
309  for(unsigned int i = 0; i < class2States.size(); i ++)
310  std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
311 
312  std::cout << "State to class" << std::endl;
313  for(mIt = state2Class.begin(); mIt != state2Class.end(); mIt++)
314  std::cout << "state: " << mIt->first << " class: " << mIt->second << std::endl; */ // REMOVE
315 
316  for(mIt = state2Class.begin(); mIt != mEndIt; mIt++){
317  // 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
318  if( mIt->first > *class2States[mIt->second].Begin() ){// state is already in other equivalence class
319  continue;
320  }
321  mbIt = ++mIt;
322  mIt--;
323  //std::cout << "state i: " << mIt->first << std::endl;
324  for(; mbIt != mbEndIt; mbIt++) {// approach from back
325  //if(j > min{k \in I | x_k \in [x_j]}
326  if(mbIt->first > *class2States[mbIt->second].Begin() ){
327  continue;
328  }
329  //std::cout << "state j: " << mbIt->first << std::endl;
330 
331  // Start actual algorithm after filtering
332  waitList.clear();
333  //if((mIt->first == 1 && mbIt->first == 4) ){
334  //waitList.push_back(std::set<Idx>() );
335  //waitList.back().insert(mIt->first);
336  //waitList.back().insert(mbIt->first); REMOVE
337  //}
338  bool flag = CheckMergibility(mIt->first,mbIt->first,waitList,mIt->first, rSupGen, supStateInfo, state2Class, class2States);
339  if(flag == true){// merge classes indicated by waitList
340  std::vector<std::set<Idx> >::const_iterator wlIt, wlEndIt;
341  //std::cout << "size of weitlist " << waitList.size() << std::endl;
342  wlIt = waitList.begin();
343  wlEndIt = waitList.end();
344  for(; wlIt != wlEndIt; wlIt++){// go through waiting list
345  //std::cout << " states " << *wlIt->begin() << " " << *(++wlIt->begin() ) << std::endl;
346  if(state2Class[*wlIt->begin() ] == state2Class[*(++(wlIt->begin() ) ) ])// no action is required if the states are already in the same class
347  continue;
348  class2States[state2Class[*wlIt->begin() ] ] = class2States[state2Class[*wlIt->begin()] ] + class2States[state2Class[*(++(wlIt->begin() ) ) ] ]; // union of state sets of both classes
349  Idx removeClass = state2Class[*(++(wlIt->begin() ) ) ];
350  sIt = class2States[removeClass ].Begin();
351  sEndIt = class2States[removeClass ].End();
352  for(; sIt != sEndIt; sIt++)
353  state2Class[*sIt] = state2Class[*wlIt->begin() ]; // change class of all states that were merged
354 
355  class2States[removeClass ].Clear(); // clear merged class
356 
357  /*std::cout << "Classes to states" << std::endl;
358  for(unsigned int i = 0; i < class2States.size(); i ++)
359  std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
360 
361  std::cout << "State to class" << std::endl;
362  std::map<Idx,Idx>::const_iterator cIt;
363  for(cIt = state2Class.begin(); cIt != state2Class.end(); cIt++)
364  std::cout << "state: " << cIt->first << " class: " << cIt->second << std::endl; */ // REMOVE
365  }
366  }
367  }
368  }
369 
370  // ===============================
371  // Construct the reduced superisor
372  // ===============================
373  // Every state corresponds to a class that we found and we try to avoid adding trnasitions with always enabled events
374  std::map<Idx,Idx> class2ReducedStates;
375  Idx newStateIdx;
376  rReducedSup.InjectAlphabet(rSupGen.Alphabet() );
377  // First generate one state for each class in the reduced generator
378  for(unsigned int i = 0; i < class2States.size(); i++){
379  if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
380  continue;
381  else{// create new state in the reduced supervisor for the class
382  newStateIdx = rReducedSup.InsState();
383  class2ReducedStates[i ] = newStateIdx; // save state for the class
384  }
385  }// all states of the reduced generator are now generated and stored
386 
387  // Now add the transitions to the reduced generator
388  TransSet::Iterator tIt, tEndIt;
389  Idx newGoalState; // goal state for transition to be added
390  for(unsigned int i = 0; i < class2States.size(); i++){
391  if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
392  continue;
393  sIt = class2States[i].Begin();
394  sEndIt = class2States[i].End();
395  newStateIdx = class2ReducedStates[i];
396  for(; sIt != sEndIt; sIt++){// go through all states of the current class
397  if(rSupGen.ExistsInitState(*sIt) )// determine the initial state of the reduced supervisor
398  rReducedSup.InsInitState(newStateIdx);
399 
400  if(rSupGen.ExistsMarkedState(*sIt) )
401  rReducedSup.SetMarkedState(newStateIdx); // insert the supervisor colors per state
402 
403  tIt = rSupGen.TransRelBegin(*sIt); // transitions of state *sIt in supervisor
404  tEndIt = rSupGen.TransRelEnd(*sIt);
405  for( ; tIt != tEndIt; tIt++){
406  newGoalState = class2ReducedStates[state2Class[tIt->X2] ]; // goal state of transition in the reduced supervisor
407  if(alwaysEnabledEvents.Exists(tIt->Ev) == true && newGoalState != newStateIdx )// always enabled event changes class and is thus relevant for supervisor
408  usedEventsMap[tIt->Ev] = true;
409 
410  rReducedSup.SetTransition(newStateIdx, tIt->Ev, newGoalState);
411  }
412  }
413  }
414  if(previousSupReduced.Size() == rReducedSup.Size() ){
415  std::map<Idx,bool>::const_iterator uIt = usedEventsMap.begin();
416  for(; uIt != usedEventsMap.end(); uIt++){// delete the unused events from the reduced supervisor
417  if(uIt->second == false){
418  rReducedSup.DelEvent(uIt->first);
419  }
420  }
421  }
422  else{
423  previousSupReduced.Clear();
424  Deterministic(rReducedSup,previousSupReduced);
425  SupReduce(rPlantGen,previousSupReduced,rReducedSup);
426  }
427  return true;
428 }
429 
430 
431 
432 } // name space

libFAUDES 2.28c --- 2016.09.30 --- c++ api documentaion by doxygen