cfl_statemin.cppGo to the documentation of this file.00001 /** @file cfl_statemin.cpp state space minimization */ 00002 00003 /* FAU Discrete Event Systems Library (libfaudes) 00004 00005 Copyright (C) 2006 Bernd Opitz 00006 Exclusive copyright is granted to Klaus Schmidt 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Lesser General Public 00010 License as published by the Free Software Foundation; either 00011 version 2.1 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Lesser General Public License for more details. 00017 00018 You should have received a copy of the GNU Lesser General Public 00019 License along with this library; if not, write to the Free Software 00020 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00021 00022 00023 #include "cfl_statemin.h" 00024 #include "cfl_exception.h" 00025 #include "cfl_project.h" 00026 00027 namespace faudes { 00028 00029 // StateMin(rGen, rResGen) 00030 void StateMin(const Generator& rGen, Generator& rResGen) { 00031 // how to avoid the copy?? see core procedure 00032 Generator* accgen=rGen.Copy(); 00033 StateMin(*accgen, rResGen); 00034 } 00035 00036 // StateMin(rGen, rResGen) 00037 void aStateMin(const Generator& rGen, Generator& rResGen) { 00038 Generator* accgen=rGen.Copy(); 00039 StateMin(*accgen, rResGen); 00040 // restore attributes 00041 rResGen.EventAttributes(accgen->Alphabet()); 00042 } 00043 00044 // StateMin(rGen) 00045 void aStateMin(Generator& rGen) { 00046 Generator* accgen=rGen.Copy(); 00047 StateMin(*accgen, rGen); 00048 // restore attributes 00049 rGen.EventAttributes(accgen->Alphabet()); 00050 } 00051 00052 // StateMin(rGen, rResGen) 00053 void StateMin(Generator& rGen, Generator& rResGen) { 00054 std::vector<StateSet> subsets; 00055 std::vector<Idx> newindices; 00056 StateMin(rGen, rResGen, subsets, newindices); 00057 } 00058 00059 // StateMin(rGen, rResGen, rSubSets, rNewIndices) 00060 // todo: make argument const, circumvent accessible 00061 void StateMin(Generator& rGen, Generator& rResGen, 00062 std::vector<StateSet>& rSubsets, std::vector<Idx>& rNewIndices) { 00063 FD_DF("StateMin: *** computing state space minimization of generator " 00064 << &rGen << " ***"); 00065 00066 FD_DF("StateMin: making generator accessible"); 00067 rGen.Accessible(); 00068 if (rGen.Size() == 0) { 00069 FD_DF("StateMin: generator size 0. returning given generator"); 00070 rResGen = rGen; 00071 return; 00072 } 00073 if(rGen.Size() == 1) { 00074 FD_DF("StateMin: generator size 1. returning given generator"); 00075 rResGen = rGen; 00076 rSubsets.push_back(rGen.States() ); 00077 rNewIndices.push_back(*( rResGen.States().Begin() ) ); 00078 return; 00079 } 00080 00081 // ensure generator is deterministic 00082 #ifdef FAUDES_CHECKED 00083 if(!rGen.IsDeterministic()) { 00084 throw Exception("StateMin", "input automaton nondeterministic", 101); 00085 } 00086 #endif 00087 00088 // use pointer pResGen to result rResGen; if rResGen is identical to 00089 // one of the parameters, allocate temporary object and copy back later 00090 Generator* pResGen = &rResGen; 00091 if(&rResGen==&rGen) { 00092 pResGen= pResGen->New(); 00093 } 00094 00095 // prepare result 00096 pResGen->Clear(); 00097 pResGen->Name(rGen.Name()+" [minstate]"); 00098 pResGen->InjectAlphabet(rGen.Alphabet()); 00099 bool stateNames= pResGen->StateNamesEnabled() && rGen.StateNamesEnabled(); 00100 // blocks B[i] 00101 std::vector<StateSet>& b = rSubsets; // convenience notation "b" 00102 Idx i, j; 00103 // set of active b (iterators) 00104 std::set<Idx> active; 00105 std::set<Idx>::iterator ait; 00106 // reverse gen transrel 00107 TransSetEvX2X1 rtransrel; 00108 rGen.TransRel(rtransrel); 00109 TransSetEvX2X1::Iterator rtit, rtit_end; 00110 // other stuff 00111 StateSet::Iterator sit; 00112 TransSet::Iterator tit, tit_end; 00113 00114 // set up b "B[i]" 00115 b.clear(); 00116 i = 0; 00117 if (rGen.Size() - rGen.MarkedStatesSize() > 0) { 00118 StateSet notmarked=rGen.States() - rGen.MarkedStates(); 00119 notmarked.Name("B[i]"); 00120 FD_DF("StateMin: new block B[" << i << "] = {" << notmarked.ToString() << "}"); 00121 b.push_back(notmarked); //X -Xm 00122 active.insert(i++); 00123 } 00124 if (rGen.MarkedStatesSize() > 0) { // tmoor 200909: conditional to prevent emty block 00125 FD_DF("StateMin: new block B[" << i << "] = {" << rGen.MarkedStates().ToString() << "}"); 00126 b.push_back(rGen.MarkedStates()); // Xm 00127 active.insert(i++); 00128 } 00129 00130 // while there is a active block B 00131 while (! active.empty()) { 00132 FD_WPC(b.size()-active.size(), b.size(), "StateMin: blocks/active: " << b.size() << " / " << active.size()); 00133 #ifdef FAUDES_DEBUG_FUNCTION 00134 FD_DF("StateMin: while there is an active block B..."); 00135 std::set<Idx>::iterator _it1; 00136 std::stringstream str; 00137 for (_it1 = active.begin(); _it1 != active.end(); ++_it1) { 00138 str << *_it1 << " "; 00139 } 00140 FD_DF("StateMin: active: "+str.str()); 00141 std::vector<StateSet>::iterator _it2; 00142 str.clear(); 00143 str.str(""); 00144 for (_it2 = b.begin(); _it2 != b.end(); ++_it2) { 00145 str << "{" << _it2->ToString() << "} "<<std::endl; 00146 } 00147 str << std::endl; 00148 FD_DF("B: "+str.str()); 00149 #endif 00150 // current block B[i] 00151 i = *(active.begin()); 00152 // inactivate B[i] 00153 active.erase(active.begin()); 00154 FD_DF("StateMin: getting active block B[" << i << "] = {" << 00155 b.at(i).ToString() << "}"); 00156 // b_current <- B[i] 00157 StateSet b_current = b.at(i); 00158 00159 // compute C = f^-1(B[i]) for every event in B[i] (as b_current) 00160 StateSet c; 00161 EventSet::Iterator eit; 00162 // iteration over alphabet 00163 for (eit = rGen.AlphabetBegin(); eit != rGen.AlphabetEnd(); ++eit) { 00164 c.Clear(); 00165 // iteration over states in current block 00166 for (sit = b_current.Begin(); sit != b_current.End(); ++sit) { 00167 // find predecessor states by current ev + x2 00168 rtit = rtransrel.BeginByEvX2(*eit, *sit); 00169 rtit_end = rtransrel.EndByEvX2(*eit, *sit); 00170 for (; rtit != rtit_end; ++rtit) { 00171 c.Insert(rtit->X1); 00172 } 00173 } 00174 // if no predecessor states where found, try next event 00175 if(c.Empty()) continue; 00176 // search for block to be split 00177 FD_DF("StateMin: computed predecessor states C = {" << c.ToString() 00178 << "} for event " << rGen.EventName(*eit)); 00179 // foreach block D 00180 for (j=0; j < b.size(); ++j) { 00181 // d_current <- B[j] 00182 const StateSet& d_current = b.at(j); 00183 FD_DF("StateMin: examining block B[" << j << "] = {" << 00184 d_current.ToString() << "}"); 00185 // compute D' = D intersection C 00186 StateSet d_ = d_current * c; 00187 d_.Name("D'"); 00188 // check D split by B 00189 if(d_.Empty() || (d_.Size()==d_current.Size())) { 00190 FD_DF("StateMin: -> no split"); 00191 continue; 00192 } 00193 FD_DF("StateMin: -> split:"); 00194 // compute D'' = D intersected not C; 00195 StateSet d__ = d_current - d_; 00196 d__.Name("D''"); 00197 // record split block 00198 b[j] = d_; 00199 b.push_back(d__); 00200 FD_DF("StateMin: new block B[" << j << "] = {" << d_.ToString() << "}"); 00201 FD_DF("StateMin: new block B[" << b.size()-1 << "] = {" << d__.ToString() << "}"); 00202 // if B[j] was active then mark both D', D'' active 00203 if(active.find(j) != active.end()) { 00204 active.insert((Idx)b.size()- 1); 00205 FD_DF("StateMin: mark active: " << b.size()-1); 00206 } 00207 // else mark smaller of D', D'' active 00208 else { 00209 if (d_.Size() < d__.Size()) { 00210 active.insert(j); 00211 FD_DF("StateMin: mark active: " << j); 00212 } else { 00213 active.insert((Idx)b.size()-1); 00214 FD_DF("StateMin: mark active: " << b.size()-1); 00215 } 00216 } 00217 } // foreach block D 00218 } // foreach event 00219 } // while active blocks exist 00220 00221 FD_DF("StateMin: *** building minimized generator ***"); 00222 // build minimized generator 00223 std::map<Idx,Idx> minstatemap; 00224 Idx newstate; 00225 // loop over all blocks B 00226 for (i = 0; i < b.size(); ++i) { 00227 // create state in new generator for every block 00228 newstate = pResGen->InsState(); 00229 rNewIndices.push_back(newstate); 00230 FD_DF("StateMin: block {" << b.at(i).ToString() 00231 << "} -> new state " << newstate); 00232 std::ostringstream ostr; 00233 for (sit = b.at(i).Begin(); sit != b.at(i).End(); ++sit) { 00234 // set minstatemap entry for every state in gen 00235 minstatemap[*sit] = newstate; 00236 if(stateNames) { 00237 if (rGen.StateName(*sit) == "") { 00238 ostr << ToStringInteger(*sit) << ","; 00239 } 00240 else { 00241 ostr << rGen.StateName(*sit) << ","; 00242 } 00243 } 00244 // set istates 00245 if (rGen.ExistsInitState(*sit)) { 00246 pResGen->SetInitState(newstate); 00247 FD_DF("StateMin: -> initial state"); 00248 } 00249 // set mstates 00250 if (rGen.ExistsMarkedState(*sit)) { 00251 pResGen->SetMarkedState(newstate); 00252 FD_DF("StatMmin: -> marked state"); 00253 } 00254 } 00255 if(stateNames) { 00256 std::string statename = ostr.str(); 00257 if(statename!="") statename.erase(statename.length()-1); 00258 statename = "{" + statename + "}"; 00259 pResGen->StateName(newstate, statename); 00260 } 00261 } 00262 // create transition relation 00263 for (tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) { 00264 pResGen->SetTransition(minstatemap[tit->X1], tit->Ev, minstatemap[tit->X2]); 00265 FD_DF("statemin: adding transition: " 00266 << minstatemap[tit->X1] << "-" << tit->Ev << "-" 00267 << minstatemap[tit->X2]); 00268 } 00269 00270 // if necessary, move pResGen to rResGen 00271 if(pResGen != &rResGen) { 00272 pResGen->Move(rResGen); 00273 delete pResGen; 00274 } 00275 } 00276 00277 } // namespace faudes libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |