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 }
188 if(continueLoop == true)// the current state pair is already on the waiting list
189 continue;
190
191 // find classes of goalStateI and goalStateJ and check if they are already merged
192 if( *(rClass2States.at( rState2Class.find(goalStateI)->second ).Begin() ) < cNode)
193 return false;
194 if( *(rClass2States.at(rState2Class.find(goalStateJ)->second ).Begin() ) < cNode)
195 return false;
196 bool flag = TestMergibility(goalStateI, goalStateJ, rWaitList, cNode, rSupGen, rSupStateInfo, rState2Class, rClass2States);
197 if(flag == false){
198 return false;
199 }
200 }
201 }
202 }
203 return true;
204}
205
206
207
208
209// SupReduce(rPlantGen, rSupGen, rReducedSup)
210bool SupReduce(const System& rPlantGen, const System& rSupGen, System& rReducedSup) {
211 FD_DF("SupReduce()");
212
213 // CONSISTENCY CHECK:
214
215 // alphabets must match
216 if (rPlantGen.Alphabet() != rSupGen.Alphabet()) {
217 EventSet only_in_plant = rPlantGen.Alphabet() - rSupGen.Alphabet();
218 EventSet only_in_spec = rSupGen.Alphabet() - rPlantGen.Alphabet();
219 std::stringstream errstr;
220 errstr << "Alphabets of generators do not match. Only in plant: "
221 << only_in_plant.ToString() << ". Only in spec: "
222 << only_in_spec.ToString() << ".";
223 throw Exception("SupReduce", errstr.str(), 100);
224 }
225
226 // plant and spec must be deterministic
227 bool plant_det = rPlantGen.IsDeterministic();
228 bool sup_det = rSupGen.IsDeterministic();
229
230 if ((plant_det == false) && (sup_det == true)) {
231 std::stringstream errstr;
232 errstr << "Plant generator must be deterministic, " << "but is nondeterministic";
233 throw Exception("SupReduce", errstr.str(), 201);
234 }
235 else if ((plant_det == true) && (sup_det == false)) {
236 std::stringstream errstr;
237 errstr << "Supervisor generator must be deterministic, " << "but is nondeterministic";
238 throw Exception("SupReduce", errstr.str(), 203);
239 }
240 else if ((plant_det == false) && (sup_det == false)) {
241 std::stringstream errstr;
242 errstr << "Plant and supervisor generator must be deterministic, "
243 << "but both are nondeterministic";
244 throw Exception("SupReduce", errstr.str(), 204);
245 }
246 // Clear the result generator rReducedsup
247 rReducedSup.Clear();
248
249 // HELPERS:
250 System previousSupReduced = rSupGen;
251 std::vector<StateSet> class2States; // control equivalent states in supervisor
252 std::map<Idx, Idx> state2Class; // map from state Idx to its control equivalent class
253 std::vector<std::set<Idx> > waitList; // list of states for classes to be merged
254 EventSet alwaysEnabledEvents = rSupGen.Alphabet(); // set of events that are never disabled
255 // Initialize the helpers that store information about the equivalence classes
256 StateSet::Iterator sIt, sEndIt;
257 sIt = rSupGen.States().Begin();
258 sEndIt = rSupGen.States().End();
259 for(; sIt != sEndIt; sIt++){ // Note: States are ordered by index
260 class2States.push_back(StateSet() );
261 class2States.back().Insert(*sIt);
262 state2Class[*sIt] = class2States.size() - 1;
263 }
264 // Evaluate the composition of plant and supervisor in order to classify corresponding states
265 System tmp;
266 std::map<std::pair<Idx,Idx>, Idx> reverseCompositionMap;
267 std::map<std::pair<Idx,Idx>, Idx>::const_iterator rcIt, rcEndIt;
268 Parallel(rPlantGen, rSupGen, reverseCompositionMap, tmp);
269 rcIt = reverseCompositionMap.begin();
270 rcEndIt = reverseCompositionMap.end();
271 std::map<Idx,ReductionStateInfo> supStateInfo;
272 std::map<Idx,ReductionStateInfo>::iterator rsIt;
273 // Find the plant states that belong to each supervisor state
274 for(; rcIt != rcEndIt; rcIt++){
275 rsIt = supStateInfo.find(rcIt->first.second);
276 if(rsIt == supStateInfo.end() )
277 supStateInfo[rcIt->first.second] = ReductionStateInfo();
278
279 supStateInfo[rcIt->first.second].mPlantStates.Insert(rcIt->first.first);
280 }
281 /*
282 FD_DF("SupReduce(): states per supervisor state ");
283 for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
284 FD_DF("sup state: " << rsIt->first << " plant states " << rsIt->second.mPlantStates.ToString());
285 */
286 // Determine the state properties for all supervisor stateset
287 for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++){
288 rsIt->second.mEnabledEvents = rSupGen.ActiveEventSet(rsIt->first); // all events enabled at current state2Class
289 sIt = rsIt->second.mPlantStates.Begin();
290 sEndIt = rsIt->second.mPlantStates.End();
291 rsIt->second.mPlantMarked = false;
292 for(; sIt != sEndIt; sIt++){
293 rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents + rPlantGen.ActiveEventSet(*sIt); // compute active events in plant_det for state *sIt
294 rsIt->second.mPlantMarked = rsIt->second.mPlantMarked || rPlantGen.ExistsMarkedState(*sIt); // compute colors of corresponding plant states
295 }
296
297 rsIt->second.mDisabledEvents = rsIt->second.mDisabledEvents - rsIt->second.mEnabledEvents; // compute disable events (events that are not enabled
298 rsIt->second.mMarkedState = rSupGen.ExistsMarkedState(rsIt->first);
299 alwaysEnabledEvents = alwaysEnabledEvents - rsIt->second.mDisabledEvents; // subtract disabled events from always enabled events
300 }
301 FD_DF("SupReduce(): Always enabled events: " << alwaysEnabledEvents.ToString());
302 // if no events are disabled, then the reduced supervisor has only one state without events
303 if(rSupGen.Alphabet() == alwaysEnabledEvents){
304 Idx state = rReducedSup.InsState();
305 rReducedSup.SetMarkedState(state);
306 rReducedSup.SetInitState(state);
307 return true;
308 }
309 /*for(rsIt = supStateInfo.begin(); rsIt != supStateInfo.end(); rsIt++)
310 std::cout << "state: " << rsIt->first << " enabled: " << rsIt->second.mEnabledEvents.ToString() << " disabled: " << rsIt->second.mDisabledEvents.ToString() << std::endl;*/ // REMOVE
311
312 std::map<Idx,bool> usedEventsMap;
313 EventSet::Iterator eIt = alwaysEnabledEvents.Begin();
314 for( ; eIt != alwaysEnabledEvents.End(); eIt++)// map that indicates if always enabled event is relevant for supervisor (true) or not (false)
315 usedEventsMap[*eIt] = false;
316 // ==========================
317 // Algorithm
318 //===========================
319 // go through all supervisor states
320 std::map<Idx,Idx>::const_iterator mIt;
321 std::map<Idx,Idx>::const_iterator mEndIt = state2Class.end();
322 mEndIt--;
323 std::map<Idx,Idx>::const_iterator mbIt, mbEndIt;
324 mbEndIt = state2Class.end();
325
326 /* std::cout << "Classes to states" << std::endl;
327 for(unsigned int i = 0; i < class2States.size(); i ++)
328 std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
329
330 std::cout << "State to class" << std::endl;
331 for(mIt = state2Class.begin(); mIt != state2Class.end(); mIt++)
332 std::cout << "state: " << mIt->first << " class: " << mIt->second << std::endl; */ // REMOVE
333
334 for(mIt = state2Class.begin(); mIt != mEndIt; mIt++){
335 // 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
336 if( mIt->first > *class2States[mIt->second].Begin() ){// state is already in other equivalence class
337 continue;
338 }
339 mbIt = ++mIt;
340 mIt--;
341 for(; mbIt != mbEndIt; mbIt++) {// approach from back
342 //if(j > min{k \in I | x_k \in [x_j]}
343 if(mbIt->first > *class2States[mbIt->second].Begin() ){
344 continue;
345 }
346 FD_DF("SupReduce(): loop state i " << mIt->first << "state j " << mbIt->first);
347
348 // Start actual algorithm after filtering
349 waitList.clear();
350 //if((mIt->first == 1 && mbIt->first == 4) ){
351 //waitList.push_back(std::set<Idx>() );
352 //waitList.back().insert(mIt->first);
353 //waitList.back().insert(mbIt->first); REMOVE
354 //}
355 bool flag = TestMergibility(mIt->first,mbIt->first,waitList,mIt->first, rSupGen, supStateInfo, state2Class, class2States);
356 if(flag == true){// merge classes indicated by waitList
357 FD_DF("SupReduce(): merging");
358 std::vector<std::set<Idx> >::const_iterator wlIt, wlEndIt;
359 //std::cout << "size of weitlist " << waitList.size() << std::endl;
360 wlIt = waitList.begin();
361 wlEndIt = waitList.end();
362 for(; wlIt != wlEndIt; wlIt++){// go through waiting list
363 //std::cout << " states " << *wlIt->begin() << " " << *(++wlIt->begin() ) << std::endl;
364 if(state2Class[*wlIt->begin() ] == state2Class[*(++(wlIt->begin() ) ) ])// no action is required if the states are already in the same class
365 continue;
366 class2States[state2Class[*wlIt->begin() ] ] = class2States[state2Class[*wlIt->begin()] ] + class2States[state2Class[*(++(wlIt->begin() ) ) ] ]; // union of state sets of both classes
367 Idx removeClass = state2Class[*(++(wlIt->begin() ) ) ];
368 sIt = class2States[removeClass ].Begin();
369 sEndIt = class2States[removeClass ].End();
370 for(; sIt != sEndIt; sIt++)
371 state2Class[*sIt] = state2Class[*wlIt->begin() ]; // change class of all states that were merged
372
373 class2States[removeClass ].Clear(); // clear merged class
374
375 /*std::cout << "Classes to states" << std::endl;
376 for(unsigned int i = 0; i < class2States.size(); i ++)
377 std::cout << "class: " << i << " state " << class2States[i].ToString() << std::endl;
378
379 std::cout << "State to class" << std::endl;
380 std::map<Idx,Idx>::const_iterator cIt;
381 for(cIt = state2Class.begin(); cIt != state2Class.end(); cIt++)
382 std::cout << "state: " << cIt->first << " class: " << cIt->second << std::endl; */ // REMOVE
383 }
384 }
385 }
386 }
387
388 // ===============================
389 // Construct the reduced superisor
390 // ===============================
391 // Every state corresponds to a class that we found and we try to avoid adding trnasitions with always enabled events
392 FD_DF("SupReduce(): construct quitient");
393 std::map<Idx,Idx> class2ReducedStates;
394 Idx newStateIdx;
395 rReducedSup.InjectAlphabet(rSupGen.Alphabet() );
396 // First generate one state for each class in the reduced generator
397 for(unsigned int i = 0; i < class2States.size(); i++){
398 if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
399 continue;
400 else{// create new state in the reduced supervisor for the class
401 newStateIdx = rReducedSup.InsState();
402 class2ReducedStates[i ] = newStateIdx; // save state for the class
403 }
404 }// all states of the reduced generator are now generated and stored
405
406 // Now add the transitions to the reduced generator
407 TransSet::Iterator tIt, tEndIt;
408 Idx newGoalState; // goal state for transition to be added
409 for(unsigned int i = 0; i < class2States.size(); i++){
410 if(class2States[i].Empty() == true)// if the state set is empty, then the class is not used
411 continue;
412 sIt = class2States[i].Begin();
413 sEndIt = class2States[i].End();
414 newStateIdx = class2ReducedStates[i];
415 for(; sIt != sEndIt; sIt++){// go through all states of the current class
416 if(rSupGen.ExistsInitState(*sIt) )// determine the initial state of the reduced supervisor
417 rReducedSup.InsInitState(newStateIdx);
418
419 if(rSupGen.ExistsMarkedState(*sIt) )
420 rReducedSup.SetMarkedState(newStateIdx); // insert the supervisor colors per state
421
422 tIt = rSupGen.TransRelBegin(*sIt); // transitions of state *sIt in supervisor
423 tEndIt = rSupGen.TransRelEnd(*sIt);
424 for( ; tIt != tEndIt; tIt++){
425 newGoalState = class2ReducedStates[state2Class[tIt->X2] ]; // goal state of transition in the reduced supervisor
426 if(alwaysEnabledEvents.Exists(tIt->Ev) == true && newGoalState != newStateIdx )// always enabled event changes class and is thus relevant for supervisor
427 usedEventsMap[tIt->Ev] = true;
428
429 rReducedSup.SetTransition(newStateIdx, tIt->Ev, newGoalState);
430 }
431 }
432 }
433 if(previousSupReduced.Size() == rReducedSup.Size() ){
434 std::map<Idx,bool>::const_iterator uIt = usedEventsMap.begin();
435 for(; uIt != usedEventsMap.end(); uIt++){// delete the unused events from the reduced supervisor
436 if(uIt->second == false){
437 rReducedSup.DelEvent(uIt->first);
438 }
439 }
440 }
441 else{
442 previousSupReduced.Clear();
443 Deterministic(rReducedSup,previousSupReduced);
444 SupReduce(rPlantGen,previousSupReduced,rReducedSup);
445 }
446 FD_DF("SupReduce(): done");
447 return true;
448}
449
450
451
452} // name space
#define FD_DF(message)
bool Exists(const Idx &rIndex) const
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen