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

libFAUDES 2.34d --- 2026.03.11 --- c++ api documentaion by doxygen