mtc_statemin.cpp
Go to the documentation of this file.
1 /** @file mtc_statemin.cpp
2 
3 State space minimization
4 
5 */
6 
7 /* FAU Discrete Event Systems Library (libfaudes)
8 
9  Copyright (C) 2008 Matthias Singer
10  Copyright (C) 2006 Bernd Opitz
11  Exclusive copyright is granted to Klaus Schmidt
12 
13  This library is free software; you can redistribute it and/or
14  modify it under the terms of the GNU Lesser General Public
15  License as published by the Free Software Foundation; either
16  version 2.1 of the License, or (at your option) any later version.
17 
18  This library is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  Lesser General Public License for more details.
22 
23  You should have received a copy of the GNU Lesser General Public
24  License along with this library; if not, write to the Free Software
25  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
26 
27 #include "mtc_statemin.h"
28 
29 namespace faudes {
30 
31 // mtcStateMin(rGen, rResGen)
32 void mtcStateMin(MtcSystem& rGen, MtcSystem& rResGen) {
33  std::vector<StateSet> subsets;
34  std::vector<Idx> newindices;
35  mtcStateMin(rGen, rResGen, subsets, newindices);
36 }
37 
38 // mtcStateMin(rGen, rResGen, rSubSets, rNewIndices)
39 void mtcStateMin(MtcSystem& rGen, MtcSystem& rResGen,
40  std::vector<StateSet>& rSubsets, std::vector<Idx>& rNewIndices) {
41  FD_DF("statemin: *** computing state space minimization of multi-tasking generator "
42  << &rGen << " ***");
43  FD_DF("statemin: making generator accessible");
44 #ifdef FAUDES_DEBUG_FUNCTION
45  FD_WARN("mtcStateMin: debug out")
46  rGen.Write("tmp_smin_m.gen");
47 #endif
48  // make accessible
49  rGen.Accessible();
50 #ifdef FAUDES_DEBUG_FUNCTION
51  FD_WARN("mtcStateMin: debug out")
52  rGen.Write("tmp_smin_a.gen");
53 #endif
54 
55 
56  if (rGen.Size() < 2) {
57  FD_DF("statemin: generator size < 2. returning given generator");
58  //rGen.Copy(rResGen); changed !! test
59  rResGen = rGen;
60  rSubsets.push_back(rGen.States() );
61  rNewIndices.push_back(*( rResGen.States().Begin() ) );
62  return;
63  }
64 
65  // ensure generator is deterministic
66  if (! rGen.IsDeterministic()) {
67  throw Exception("mtcStateMin", "input automaton nondeterministic", 505);
68  }
69 
70  // prepare result
71  rResGen.Clear();
72  rResGen.Name(rGen.Name()+" [mtc minstate]");
73 
74  rResGen.ClearStateAttributes();
75  rResGen.InjectAlphabet(rGen.Alphabet());
76 
77  rResGen.SetControllable(rGen.ControllableEvents());
78  rResGen.SetForcible(rGen.ForcibleEvents());
79  rResGen.ClrObservable(rGen.UnobservableEvents());
80 
81 
82  // blocks B[i]
83  std::vector<StateSet>& b = rSubsets; // convenience notation "b"
84  Idx i, j;
85  // set of active b (iterators)
86  std::set<Idx> active;
87  std::set<Idx>::iterator ait;
88  // reverse transrel
89  TransSetEvX2X1 rtransrel;
90  rGen.TransRel(rtransrel);
91  TransSetEvX2X1::Iterator rtit, rtit_end;
92  // other stuff
93  StateSet::Iterator lit;
95 
96  // set up b "B[i]"
97  i = 0;
98 
99 #ifdef FAUDES_DEBUG_FUNCTION
100  FD_WARN("mtcStateMin: debug out: states");
101  rGen.States().Write();
102  FD_WARN("mtcStateMin: debug out: colored states");
103  rGen.ColoredStates().Write();
104  FD_WARN("mtcStateMin: debug out: unolored states");
105  rGen.UncoloredStates().Write();
106 #endif
107 
108  if (rGen.UncoloredStates().Size() > 0) {
109  b.push_back(rGen.UncoloredStates());
110  active.insert(i++);
111  FD_DF("statemin: new block B[" << i-1 << "] = {" <<
112  (rGen.UncoloredStates()).ToString() << "}");
113  }
114  // find states that have the same associated colors
115  std::map<Idx,ColorSet> stateColorMap = rGen.StateColorMap();
116  std::map<Idx,ColorSet>::const_iterator sit_end = stateColorMap.end();
117  std::map<ColorSet,StateSet> SameColors;
118  std::map<ColorSet,StateSet>::iterator csit;
119  std::map<Idx,ColorSet>::const_iterator sit;
120 
121  for(sit = stateColorMap.begin(); sit != sit_end; ++sit){
122  csit = SameColors.find(sit->second);
123  FD_DF("stateColorMap, state: " << ToStringInteger(sit->first) << ", colors: " << (sit->second).ToString());
124  if(csit != SameColors.end() )
125  csit->second.Insert(sit->first);
126  else{
127  StateSet NewStateSet;
128  NewStateSet.Insert(sit->first);
129  SameColors[sit->second] = NewStateSet;
130  }
131  }
132 
133  // create the initial set of equivalence classes
134  std::map<ColorSet,StateSet>::const_iterator csit_end = SameColors.end();
135  for(csit = SameColors.begin(); csit != csit_end; ++csit){
136  b.push_back(csit->second); // Colored StateSets
137  active.insert(i++);
138  FD_DF("statemin: new block B[" << i-1 << "] = {" <<
139  csit->second.ToString() << "}");
140  }
141 
142  // while there is an active block B
143  while (! active.empty()) {
144  FD_WP("mtcStateMin: blocks/active: " << b.size() << " / " << active.size());
145 #ifdef FD_DF
146  FD_DF("statemin: if there is an active block B...");
147  std::set<Idx>::iterator _it1;
148  std::stringstream str;
149  for (_it1 = active.begin(); _it1 != active.end(); ++_it1) {
150  str << *_it1 << " ";
151  }
152  FD_DF("active: "+str.str());
153  std::vector<StateSet>::iterator _it2;
154  str.clear();
155  for (_it2 = b.begin(); _it2 != b.end(); ++_it2) {
156  str << "{" << _it2->ToString() << "} ";
157  }
158  str << std::endl;
159  FD_DF("B: "+str.str());
160 #endif
161  // current block B[i]
162  i = *(active.begin());
163  // inactivate B[i]
164  active.erase(active.begin());
165  FD_DF("statemin: getting active block B[" << i << "] = {" <<
166  b.at(i).ToString() << "}");
167  // b_current <- B[i]
168  StateSet b_current = b.at(i);
169 
170  // compute C = f^-1(B[i]) for every event in B[i] (as b_current)
171  StateSet c;
172  EventSet::Iterator eit;
173  // iteration over alphabet
174  for (eit = rGen.AlphabetBegin(); eit != rGen.AlphabetEnd(); ++eit) {
175  c.Clear();
176  // iteration over states in current block
177  for (lit = b_current.Begin(); lit != b_current.End(); ++lit) {
178  // find predecessor states by current ev + x2
179  rtit = rtransrel.BeginByEvX2(*eit, *lit);
180  rtit_end = rtransrel.EndByEvX2(*eit, *lit);
181  for (; rtit != rtit_end; ++rtit) {
182  c.Insert(rtit->X1);
183  }
184  }
185  // if predecessor states where found
186  if (! c.Empty()) {
187  // search for new block on next event or coming end of rtransrel with
188  // x1 as *lit
189  FD_DF("statemin: computed predecessor states C = {" << c.ToString()
190  << "} for event " << rGen.EventName(*eit));
191 
192  // foreach block D
193  for (j=0; j < b.size(); ++j) {
194  FD_DF("statemin: examining block B[" << j << "] = {" <<
195  b.at(j).ToString() << "}");
196  // compute D' = D intersection C
197  StateSet d_ = b.at(j) * c;
198  // compute D'' = D - D'; remove D, add D''
199  StateSet d__ = b.at(j) - d_;
200  // check D split by B
201  if (d_.Empty() || d__.Empty()) {
202  FD_DF("statemin: -> no split");
203  continue;
204  }
205  FD_DF("statemin: -> split:");
206  b[j] = d_;
207  FD_DF("statemin: new block B[" << j << "] = {"
208  << d_.ToString() << "}");
209  b.push_back(d__);
210  FD_DF("statemin: new block B[" << b.size()-1 << "] = {"
211  << d__.ToString() << "}");
212  // if D was active
213  if (active.count(j) > 0) {
214  // then mark both D', D'' active
215  active.insert((Idx)b.size()- 1);
216  FD_DF("statemin: mark active: " << b.size()-1);
217  }
218  // else mark smaller of D', D'' active
219  else {
220  if (d_.Size() < d__.Size()) {
221  active.insert(j);
222  FD_DF("statemin: mark active: " << j);
223  }
224  else {
225  active.insert((Idx)b.size()-1);
226  FD_DF("statemin: mark active: " << b.size()-1);
227  }
228  }
229  } // foreach block D
230  c.Clear();
231  }
232  }
233  }
234 
235  FD_DF("statemin: *** building minimized generator ***");
236  // build minimized generator
237  std::map<Idx,Idx> minstatemap;
238  Idx newstate;
239  // loop over all blocks B
240  for (i = 0; i < b.size(); i++) {
241  // create state in new generator for every block
242  newstate = rResGen.InsState();
243  rNewIndices.push_back(newstate);
244  FD_DF("statemin: block {" << b.at(i).ToString()
245  << "} -> new state " << newstate);
246  std::ostringstream ostr;
247  Idx count = 0;
248  for (lit = b.at(i).Begin(); lit != b.at(i).End(); lit++) {
249  count++;
250  // set minstatemap entry for every state in gen
251  minstatemap[*lit] = newstate;
252  if (rResGen.StateNamesEnabled()) {
253  FD_DF("StateNamesEnabled: index: \""<< ToStringInteger(*lit) << "\", name: \"" << rGen.StateName(*lit) << "\"");
254  if (rGen.StateName(*lit) == "") {
255  ostr << ToStringInteger(*lit) << ",";
256  FD_DF("StateName \"\", ostr = " << ostr.str());
257  }
258  else {
259  ostr << rGen.StateName(*lit) << ",";
260  FD_DF("StateName exists, ostr = " << ostr.str());
261  }
262  }
263  // set istates
264  if (rGen.ExistsInitState(*lit)) {
265  rResGen.SetInitState(newstate);
266  FD_DF("statemin: -> initial state");
267  }
268  if(count == 1){ //all states in b.at(i) have the same colors
269  std::map<Idx,ColorSet>::const_iterator col_it;
270  col_it = stateColorMap.find(*lit);
271  // are there any colors to set for the current state?
272  if (col_it != stateColorMap.end()) {
273  // insert corresponding colors if they are not already set for the current state
274  FD_DF("mtcStateMin: insert colors " << col_it->second.ToString() << " to state " << newstate);
275  rResGen.InsColors(newstate, col_it->second);
276  }
277  }
278  }
279  if (rResGen.StateNamesEnabled()) {
280  std::string statename = ostr.str();
281  statename.erase(statename.length()-1);
282  statename = "{" + statename + "}";
283  FD_DF("Set state name: name: \"" << statename << "\", index: \"" << newstate << "\"");
284  rResGen.StateName(newstate, statename);
285  }
286  }
287  // create transition relation
288  for (tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
289  rResGen.SetTransition(minstatemap[tit->X1], tit->Ev, minstatemap[tit->X2]);
290  FD_DF("statemin: adding transition: "
291  << minstatemap[tit->X1] << "-" << tit->Ev << "-"
292  << minstatemap[tit->X2]);
293  }
294 #ifdef FAUDES_DEBUG_FUNCTION
295  FD_WARN("mtcStateMin: debug out: result")
296  rResGen.Write("tmp_smin_r.gen");
297 #endif
298 }
299 
300 // RTI wrapper
301 void mtcStateMin(const MtcSystem& rGen, MtcSystem& rResGen) {
302  MtcSystem gen(rGen);
303  mtcStateMin(gen,rResGen);
304 
305  FD_WARN("mtcStateMin: debug out")
306  rGen.GraphWrite("tmp_smin_w.png");
307  rGen.DotWrite("tmp_smin_w.dot");
308 
309 }
310 
311 } // namespace faudes
#define FD_WARN(message)
Debug: always report warnings.
#define FD_DF(message)
Debug: optional report on user functions.
#define FD_WP(message)
Application callback: optional write progress report to console or application.
Faudes exception class.
Set of indices.
Definition: cfl_indexset.h:78
Idx Insert(void)
Insert new index to set.
Iterator class for high-level api to TBaseSet.
Definition: cfl_baseset.h:387
Set of Transitions.
Definition: cfl_transset.h:242
Iterator EndByEvX2(Idx ev, Idx x2) const
Iterator to first Transition after specified event and next state.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
Iterator BeginByEvX2(Idx ev, Idx x2) const
Iterator to first Transition specified by event and next state.
Idx InsState(void)
Add new anonymous state to generator.
virtual void Clear(void)
Clear generator data.
const TaStateSet< StateAttr > & States(void) const
Return reference to state set.
const TaEventSet< EventAttr > & Alphabet(void) const
Return const reference to alphabet.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
const ATransSet & TransRel(void) const
Return reference to transition relation.
void InjectAlphabet(const EventSet &rNewalphabet)
Set mpAlphabet without consistency check.
void ClrObservable(Idx index)
Mark event unobservable (by index)
EventSet ControllableEvents(void) const
Get EventSet with controllable events.
void SetControllable(Idx index)
Mark event controllable (by index)
EventSet ForcibleEvents(void) const
Get EventSet with forcible events.
void SetForcible(Idx index)
Mark event forcible (by index)
EventSet UnobservableEvents(void) const
Get EventSet with unobservable events.
Allows to create colored marking generators (CMGs) as the common five tupel consisting of alphabet,...
Definition: mtc_generator.h:53
void InsColors(Idx stateIndex, const ColorSet &rColors)
Insert multiple colors from a color set into an existing state.
StateSet ColoredStates(Idx colorIndex) const
Returns a state set containing all states that are colored with the color given by index.
virtual void DotWrite(const std::string &rFileName) const
Writes generator to dot input format.
void ClearStateAttributes()
Clear all the generator's state attributes.
std::map< Idx, ColorSet > StateColorMap(void) const
Return a color map with state indices and their corresponding colors.
StateSet UncoloredStates() const
Returns a state set containing all states that are not colored.
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Write configuration data to a string.
Definition: cfl_types.cpp:169
void Write(const Type *pContext=0) const
Write configuration data to console.
Definition: cfl_types.cpp:139
TransSet::Iterator TransRelBegin(void) const
Iterator to Begin() of transition relation.
bool Accessible(void)
Make generator accessible.
EventSet::Iterator AlphabetBegin(void) const
Iterator to Begin() of alphabet.
void SetInitState(Idx index)
Set an existing state as initial state by index.
std::string StateName(Idx index) const
State name lookup.
void Name(const std::string &rName)
Set the generator's name.
TransSet::Iterator TransRelEnd(void) const
Iterator to End() of transition relation.
bool IsDeterministic(void) const
Check if generator is deterministic.
bool StateNamesEnabled(void) const
Whether libFAUEDS functions are requested to generate state names.
void GraphWrite(const std::string &rFileName, const std::string &rOutFormat="", const std::string &rDotExec="dot") const
Produce graphical representation of this generator.
std::string EventName(Idx index) const
Event name lookup.
EventSet::Iterator AlphabetEnd(void) const
Iterator to End() of alphabet.
Idx Size(void) const
Get generator size (number of states)
bool ExistsInitState(Idx index) const
Test existence of state in mInitStates.
bool Empty(void) const
Test whether if the TBaseSet is Empty.
Definition: cfl_baseset.h:1824
virtual void Clear(void)
Clear all set.
Definition: cfl_baseset.h:1902
Iterator End(void) const
Iterator to the end of set.
Definition: cfl_baseset.h:1896
Iterator Begin(void) const
Iterator to the begin of set.
Definition: cfl_baseset.h:1891
Idx Size(void) const
Get Size of TBaseSet.
Definition: cfl_baseset.h:1819
State space minimization.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
void mtcStateMin(MtcSystem &rGen, MtcSystem &rResGen)
State Minimization This function implements the (n*log n) set partitioning algorithm by John E.
std::string ToStringInteger(Int number)
integer to string
Definition: cfl_helper.cpp:43

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen