cfl_statemin.cpp
Go to the documentation of this file.
1 /** @file cfl_statemin.cpp state space minimization */
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 "cfl_statemin.h"
24 #include "cfl_exception.h"
25 #include "cfl_project.h"
26 
27 namespace faudes {
28 
29 // StateMin(rGen, rResGen)
30 void StateMin(const Generator& rGen, Generator& rResGen) {
31  // how to avoid the copy?? see core procedure
32  Generator* accgen=rGen.Copy();
33  StateMin(*accgen, rResGen);
34 }
35 
36 // StateMin(rGen, rResGen)
37 void aStateMin(const Generator& rGen, Generator& rResGen) {
38  Generator* accgen=rGen.Copy();
39  StateMin(*accgen, rResGen);
40  // restore attributes
41  rResGen.EventAttributes(accgen->Alphabet());
42 }
43 
44 // StateMin(rGen)
45 void aStateMin(Generator& rGen) {
46  Generator* accgen=rGen.Copy();
47  StateMin(*accgen, rGen);
48  // restore attributes
49  rGen.EventAttributes(accgen->Alphabet());
50 }
51 
52 // StateMin(rGen, rResGen)
53 void StateMin(Generator& rGen, Generator& rResGen) {
54  std::vector<StateSet> subsets;
55  std::vector<Idx> newindices;
56  StateMin(rGen, rResGen, subsets, newindices);
57 }
58 
59 // StateMin(rGen, rResGen, rSubSets, rNewIndices)
60 // todo: make argument const, circumvent accessible
61 void StateMin(Generator& rGen, Generator& rResGen,
62  std::vector<StateSet>& rSubsets, std::vector<Idx>& rNewIndices) {
63  FD_DF("StateMin: *** computing state space minimization of generator "
64  << &rGen << " ***");
65 
66  FD_DF("StateMin: making generator accessible");
67  rGen.Accessible();
68  if (rGen.Size() == 0) {
69  FD_DF("StateMin: generator size 0. returning given generator");
70  rResGen = rGen;
71  return;
72  }
73  if(rGen.Size() == 1) {
74  FD_DF("StateMin: generator size 1. returning given generator");
75  rResGen = rGen;
76  rSubsets.push_back(rGen.States() );
77  rNewIndices.push_back(*( rResGen.States().Begin() ) );
78  return;
79  }
80 
81  // ensure generator is deterministic
82 #ifdef FAUDES_CHECKED
83  if(!rGen.IsDeterministic()) {
84  throw Exception("StateMin", "input automaton nondeterministic", 101);
85  }
86 #endif
87 
88  // use pointer pResGen to result rResGen; if rResGen is identical to
89  // one of the parameters, allocate temporary object and copy back later
90  Generator* pResGen = &rResGen;
91  if(&rResGen==&rGen) {
92  pResGen= pResGen->New();
93  }
94 
95  // prepare result
96  pResGen->Clear();
97  pResGen->Name(rGen.Name()+" [minstate]");
98  pResGen->InjectAlphabet(rGen.Alphabet());
99  bool stateNames= pResGen->StateNamesEnabled() && rGen.StateNamesEnabled();
100  // blocks B[i]
101  std::vector<StateSet>& b = rSubsets; // convenience notation "b"
102  Idx i, j;
103  // set of active b (iterators)
104  std::set<Idx> active;
105  std::set<Idx>::iterator ait;
106  // reverse gen transrel
107  TransSetEvX2X1 rtransrel;
108  rGen.TransRel(rtransrel);
109  TransSetEvX2X1::Iterator rtit, rtit_end;
110  // other stuff
111  StateSet::Iterator sit;
112  TransSet::Iterator tit, tit_end;
113 
114  // set up b "B[i]"
115  b.clear();
116  i = 0;
117  if (rGen.Size() - rGen.MarkedStatesSize() > 0) {
118  StateSet notmarked=rGen.States() - rGen.MarkedStates();
119  notmarked.Name("B[i]");
120  FD_DF("StateMin: new block B[" << i << "] = {" << notmarked.ToString() << "}");
121  b.push_back(notmarked); //X -Xm
122  active.insert(i++);
123  }
124  if (rGen.MarkedStatesSize() > 0) { // tmoor 200909: conditional to prevent emty block
125  FD_DF("StateMin: new block B[" << i << "] = {" << rGen.MarkedStates().ToString() << "}");
126  b.push_back(rGen.MarkedStates()); // Xm
127  active.insert(i++);
128  }
129 
130  // while there is a active block B
131  while (! active.empty()) {
132  FD_WPC(b.size()-active.size(), b.size(), "StateMin: blocks/active: " << b.size() << " / " << active.size());
133 #ifdef FAUDES_DEBUG_FUNCTION
134  FD_DF("StateMin: while there is an active block B...");
135  std::set<Idx>::iterator _it1;
136  std::stringstream str;
137  for (_it1 = active.begin(); _it1 != active.end(); ++_it1) {
138  str << *_it1 << " ";
139  }
140  FD_DF("StateMin: active: "+str.str());
141  std::vector<StateSet>::iterator _it2;
142  str.clear();
143  str.str("");
144  for (_it2 = b.begin(); _it2 != b.end(); ++_it2) {
145  str << "{" << _it2->ToString() << "} "<<std::endl;
146  }
147  str << std::endl;
148  FD_DF("B: "+str.str());
149 #endif
150  // current block B[i]
151  i = *(active.begin());
152  // inactivate B[i]
153  active.erase(active.begin());
154  FD_DF("StateMin: getting active block B[" << i << "] = {" <<
155  b.at(i).ToString() << "}");
156  // b_current <- B[i]
157  StateSet b_current = b.at(i);
158 
159  // compute C = f^-1(B[i]) for every event in B[i] (as b_current)
160  StateSet c;
161  EventSet::Iterator eit;
162  // iteration over alphabet
163  for (eit = rGen.AlphabetBegin(); eit != rGen.AlphabetEnd(); ++eit) {
164  c.Clear();
165  // iteration over states in current block
166  for (sit = b_current.Begin(); sit != b_current.End(); ++sit) {
167  // find predecessor states by current ev + x2
168  rtit = rtransrel.BeginByEvX2(*eit, *sit);
169  rtit_end = rtransrel.EndByEvX2(*eit, *sit);
170  for (; rtit != rtit_end; ++rtit) {
171  c.Insert(rtit->X1);
172  }
173  }
174  // if no predecessor states where found, try next event
175  if(c.Empty()) continue;
176  // search for block to be split
177  FD_DF("StateMin: computed predecessor states C = {" << c.ToString()
178  << "} for event " << rGen.EventName(*eit));
179  // foreach block D
180  for (j=0; j < b.size(); ++j) {
181  // d_current <- B[j]
182  const StateSet& d_current = b.at(j);
183  FD_DF("StateMin: examining block B[" << j << "] = {" <<
184  d_current.ToString() << "}");
185  // compute D' = D intersection C
186  StateSet d_ = d_current * c;
187  d_.Name("D'");
188  // check D split by B
189  if(d_.Empty() || (d_.Size()==d_current.Size())) {
190  FD_DF("StateMin: -> no split");
191  continue;
192  }
193  FD_DF("StateMin: -> split:");
194  // compute D'' = D intersected not C;
195  StateSet d__ = d_current - d_;
196  d__.Name("D''");
197  // record split block
198  b[j] = d_;
199  b.push_back(d__);
200  FD_DF("StateMin: new block B[" << j << "] = {" << d_.ToString() << "}");
201  FD_DF("StateMin: new block B[" << b.size()-1 << "] = {" << d__.ToString() << "}");
202  // if B[j] was active then mark both D', D'' active
203  if(active.find(j) != active.end()) {
204  active.insert((Idx)b.size()- 1);
205  FD_DF("StateMin: mark active: " << b.size()-1);
206  }
207  // else mark smaller of D', D'' active
208  else {
209  if (d_.Size() < d__.Size()) {
210  active.insert(j);
211  FD_DF("StateMin: mark active: " << j);
212  } else {
213  active.insert((Idx)b.size()-1);
214  FD_DF("StateMin: mark active: " << b.size()-1);
215  }
216  }
217  } // foreach block D
218  } // foreach event
219  } // while active blocks exist
220 
221  FD_DF("StateMin: *** building minimized generator ***");
222  // build minimized generator
223  std::map<Idx,Idx> minstatemap;
224  Idx newstate;
225  // loop over all blocks B
226  for (i = 0; i < b.size(); ++i) {
227  // create state in new generator for every block
228  newstate = pResGen->InsState();
229  rNewIndices.push_back(newstate);
230  FD_DF("StateMin: block {" << b.at(i).ToString()
231  << "} -> new state " << newstate);
232  std::ostringstream ostr;
233  for (sit = b.at(i).Begin(); sit != b.at(i).End(); ++sit) {
234  // set minstatemap entry for every state in gen
235  minstatemap[*sit] = newstate;
236  if(stateNames) {
237  if (rGen.StateName(*sit) == "") {
238  ostr << ToStringInteger(*sit) << ",";
239  }
240  else {
241  ostr << rGen.StateName(*sit) << ",";
242  }
243  }
244  // set istates
245  if (rGen.ExistsInitState(*sit)) {
246  pResGen->SetInitState(newstate);
247  FD_DF("StateMin: -> initial state");
248  }
249  // set mstates
250  if (rGen.ExistsMarkedState(*sit)) {
251  pResGen->SetMarkedState(newstate);
252  FD_DF("StatMmin: -> marked state");
253  }
254  }
255  if(stateNames) {
256  std::string statename = ostr.str();
257  if(statename!="") statename.erase(statename.length()-1);
258  statename = "{" + statename + "}";
259  pResGen->StateName(newstate, statename);
260  }
261  }
262  // create transition relation
263  for (tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
264  pResGen->SetTransition(minstatemap[tit->X1], tit->Ev, minstatemap[tit->X2]);
265  FD_DF("statemin: adding transition: "
266  << minstatemap[tit->X1] << "-" << tit->Ev << "-"
267  << minstatemap[tit->X2]);
268  }
269 
270  // if necessary, move pResGen to rResGen
271  if(pResGen != &rResGen) {
272  pResGen->Move(rResGen);
273  delete pResGen;
274  }
275 }
276 
277 } // namespace faudes

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