mtc_project.cppGo to the documentation of this file.00001 /** @file mtc_project.cpp 00002 00003 Methods for computing the natural projection of multitasking generators 00004 00005 */ 00006 00007 /* FAU Discrete Event Systems Library (libfaudes) 00008 00009 Copyright (C) 2008 Matthias Singer 00010 Copyright (C) 2006 Bernd Opitz 00011 Exclusive copyright is granted to Klaus Schmidt 00012 00013 This library is free software; you can redistribute it and/or 00014 modify it under the terms of the GNU Lesser General Public 00015 License as published by the Free Software Foundation; either 00016 version 2.1 of the License, or (at your option) any later version. 00017 00018 This library is distributed in the hope that it will be useful, 00019 but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00021 Lesser General Public License for more details. 00022 00023 You should have received a copy of the GNU Lesser General Public 00024 License along with this library; if not, write to the Free Software 00025 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00026 00027 00028 #include "mtc_project.h" 00029 #include "cfl_localgen.h" 00030 00031 namespace faudes { 00032 00033 // mtcUniqueInit(rGen&) 00034 void mtcUniqueInit(MtcSystem& rGen) { 00035 Idx inituni; 00036 StateSet::Iterator lit; 00037 TransSet::Iterator tit; 00038 // check number of initial states 00039 if (rGen.InitStatesSize() <= 1) return; 00040 // introduce new initial state 00041 if (rGen.StateNamesEnabled()) { 00042 std::string initname=rGen.UniqueStateName("InitUni"); 00043 inituni = rGen.InsState(initname); 00044 } 00045 else { 00046 inituni = rGen.InsState(); 00047 } 00048 FD_DF("mtcUniqueInit: introducing new initial state: " << inituni); 00049 // introduce outgoing transitions from initial state 00050 FD_DF("mtcUniqueInit: introduce outgoing transitions: "); 00051 for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) { 00052 for (tit = rGen.TransRelBegin(*lit); tit != rGen.TransRelEnd(*lit); ++tit) { 00053 rGen.SetTransition(inituni, tit->Ev, tit->X2); 00054 FD_DF("mtcUniqueInit: " << inituni << "-" << tit->Ev << "-" << tit->X2); 00055 } 00056 // colored states 00057 const ColorSet& colors = rGen.Colors(*lit); 00058 rGen.InsColors(inituni, colors); 00059 // marked states 00060 if (!rGen.MarkedStatesEmpty()) { 00061 rGen.SetMarkedState(inituni); 00062 FD_DF("mtcUniqueInit: set marked state: " << inituni); 00063 } 00064 } 00065 // delete old istates 00066 rGen.ClearInitStates(); 00067 // set inituni as new initial state 00068 rGen.SetInitState(inituni); 00069 } 00070 00071 00072 // mtcDeterministic(rGen&, rResGen&) 00073 void mtcDeterministic(const MtcSystem& rGen, MtcSystem& rResGen) { 00074 // temporary vectors 00075 std::vector<StateSet> power_states; 00076 std::vector<Idx> det_states; 00077 mtcDeterministic(rGen, power_states, det_states, rResGen); 00078 } 00079 00080 00081 // mtcDeterministic(rGen&, rEntryStatesMap&, rResGen&) 00082 void mtcDeterministic(const MtcSystem& rGen, std::map<Idx,StateSet>& rEntryStatesMap, 00083 MtcSystem& rResGen) { 00084 // prepare result: 00085 rEntryStatesMap.clear(); 00086 // helpers: 00087 std::vector<StateSet> power_states; 00088 std::vector<Idx> det_states; 00089 // call Deterministic function 00090 mtcDeterministic(rGen, power_states, det_states, rResGen); 00091 // build entry states map 00092 std::vector<StateSet>::size_type i; 00093 for (i = 0; i < power_states.size(); ++i) { 00094 rEntryStatesMap.insert(std::pair<Idx,StateSet>(det_states[i], power_states[i])); 00095 } 00096 } 00097 00098 00099 void mtcDeterministic(const MtcSystem& rGen, std::vector<StateSet>& rPowerStates, 00100 std::vector<Idx>& rDetStates, MtcSystem& rResGen) { 00101 // set the name 00102 rResGen.Name("Det(" + rGen.Name() + ")"); 00103 00104 // prepare result 00105 rPowerStates.clear(); 00106 rDetStates.clear(); 00107 rResGen.Clear(); 00108 00109 // copy alphabet 00110 rResGen.InjectAlphabet(rGen.Alphabet()); 00111 00112 // helpers 00113 TransSetEvX1X2 trel_evx1x2; 00114 rGen.TransRel(trel_evx1x2); 00115 typedef std::multimap< Idx,std::vector<StateSet>::size_type > T_HASHMAP; 00116 T_HASHMAP hashmap; 00117 std::vector<StateSet>::size_type current_vecindex; 00118 std::pair< std::map<StateSet,Idx>::iterator,bool > result; 00119 TransSet::Iterator transrel_end = rGen.TransRelEnd(); 00120 StateSet newset; 00121 StateSet::Iterator lit; 00122 const Idx max_idx = std::numeric_limits<Idx>::max(); 00123 if (rGen.InitStatesEmpty()) { 00124 return; 00125 } 00126 // std::map<Idx,ColorSet> CopyMap = rGen.StateColorMap(); 00127 Idx newstate = rResGen.InsInitState(); 00128 // initialize rPowerStates with subset of initial states 00129 for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) { 00130 // clear set and insert single state 00131 newset.Insert(*lit); 00132 const ColorSet& colors = rGen.Colors(*lit); 00133 // set colored state if a member state is colored 00134 rResGen.InsColors(newstate,colors); 00135 } 00136 FD_DF("mtcDeterministic: created subset of initial states {" 00137 << newset.ToString() << "} with deterministic state index " << rGen.SStr(newstate)); 00138 // insert newset in rPowerStates 00139 rPowerStates.push_back(newset); 00140 rDetStates.push_back(newstate); 00141 hashmap.insert(std::make_pair(newset.Signature(), (Idx)rPowerStates.size() - 1)); 00142 00143 // iteration over all states 00144 for (current_vecindex = 0; current_vecindex < rPowerStates.size(); ++current_vecindex) { 00145 FD_DF("mtcDeterministic: current power set: {" << rPowerStates[current_vecindex].ToString() << 00146 "} -> " << rDetStates[current_vecindex]); 00147 00148 std::vector<StateSet> newset_vec; 00149 std::vector<Idx> event_vec; 00150 00151 // multiway merge begin 00152 FD_DF("mtcDeterministic: starting multiway merge..."); 00153 std::list<TransSet::Iterator> merge_iterators; 00154 std::vector<Transition> trans_vec; 00155 00156 // add transset iterator at begin of each state's transitions 00157 TransSet::Iterator tit; 00158 for (lit = rPowerStates[current_vecindex].Begin(); 00159 lit != rPowerStates[current_vecindex].End(); ++lit) { 00160 tit = rGen.TransRelBegin(*lit); 00161 if (tit != rGen.TransRelEnd(*lit)) { 00162 merge_iterators.push_back(tit); 00163 FD_DF("mtcDeterministic: added merge iterator: " << rGen.SStr(tit->X1) 00164 << "-" << rGen.EStr(tit->Ev) << "-" << rGen.SStr(tit->X2)); 00165 } 00166 } 00167 00168 // find first iterator with lowest event 00169 while (! merge_iterators.empty()) { 00170 Idx currentevent = max_idx; 00171 std::list<TransSet::Iterator>::iterator i; 00172 std::list<TransSet::Iterator>::iterator currentit = merge_iterators.end(); 00173 for (i = merge_iterators.begin(); i != merge_iterators.end(); ++i) { 00174 if ((*i)->Ev < currentevent) { 00175 currentevent = (*i)->Ev; 00176 currentit = i; 00177 } 00178 } 00179 // currentit now holds the iterator 00180 // currentevent holds the lowest event (lowest Idx) 00181 00182 // merge all transitions with currentevent at each iterator in a row 00183 // this is a modification of multiway merge as after projection the 00184 // automaton most likely holds states with many transitions that share 00185 // the same event. only merging the lowest transition and continue with 00186 // search for the lowest event again would be to slow here (because 00187 // of too much iterator dereferencing). 00188 Idx currentstate; 00189 while (currentit != merge_iterators.end()) { 00190 currentstate = (*currentit)->X1; 00191 TransSet::Iterator& j = *currentit; 00192 while (1) { 00193 // remove iterator if it reaches the end of the transition set 00194 if (j == transrel_end) { 00195 std::list<TransSet::Iterator>::iterator tmpit = currentit; 00196 ++currentit; 00197 merge_iterators.erase(tmpit); 00198 break; 00199 } 00200 // if current iterator is in its original state 00201 else if (j->X1 == currentstate) { 00202 // if the event is still the same add the transition 00203 if (j->Ev == currentevent) { 00204 trans_vec.push_back(*j); 00205 FD_DF("Determine: adding transition to list: " << rGen.SStr(j->X1) 00206 << "-" << rGen.EStr(j->Ev) << "-" << rGen.SStr(j->X2)); 00207 } 00208 // else go to next iterator 00209 else { 00210 ++currentit; 00211 break; 00212 } 00213 } 00214 // if the iterator is beyond its original state remove it 00215 else { 00216 std::list<TransSet::Iterator>::iterator tmpit = currentit; 00217 ++currentit; 00218 merge_iterators.erase(tmpit); 00219 break; 00220 } 00221 ++j; 00222 } 00223 } 00224 } 00225 00226 // partition transition vector by events. optimizable? 00227 FD_DF("mtcDeterministic: partitioning the transition vector..."); 00228 std::vector<Transition>::iterator tv_it; 00229 StateSet newset; 00230 Idx lastevent = 0; 00231 for (tv_it = trans_vec.begin(); tv_it != trans_vec.end(); ++tv_it) { 00232 if ((tv_it->Ev == lastevent) || (lastevent == 0)) { 00233 newset.Insert(tv_it->X2); 00234 lastevent = tv_it->Ev; 00235 } 00236 else { 00237 FD_DF("mtcDeterministic: partition: {" << newset.ToString() 00238 << "} with event " << rGen.EStr(lastevent)); 00239 newset_vec.push_back(newset); 00240 event_vec.push_back(lastevent); 00241 newset.Clear(); 00242 newset.Insert(tv_it->X2); 00243 lastevent = tv_it->Ev; 00244 } 00245 } 00246 if (! newset.Empty()) { 00247 FD_DF("mtcDeterministic: partition: {" << newset.ToString() 00248 << "} with event " << rGen.EStr(lastevent)); 00249 newset_vec.push_back(newset); 00250 event_vec.push_back(lastevent); 00251 } 00252 FD_DF("mtcDeterministic: partitioning the transition vector finished"); 00253 FD_DF("mtcDeterministic: multiway merge finished"); 00254 // multiway merge end 00255 00256 std::vector<StateSet>::size_type nsv_index; 00257 for (nsv_index = 0; nsv_index < newset_vec.size(); ++nsv_index) { 00258 StateSet& currentset = newset_vec[nsv_index]; 00259 Idx currentevent = event_vec[nsv_index]; 00260 Idx tmp_x2 = 0; 00261 Idx sig = currentset.Signature(); 00262 // test if newset signature is already known 00263 std::pair<T_HASHMAP::iterator,T_HASHMAP::iterator> phit 00264 = hashmap.equal_range(sig); 00265 T_HASHMAP::iterator hit = phit.first; 00266 for (hit = phit.first; hit != phit.second; ++hit) { 00267 // test set of every matching signature for equality 00268 if (currentset == rPowerStates[hit->second]) { 00269 tmp_x2 = rDetStates[hit->second]; 00270 break; 00271 } 00272 } 00273 00274 // if new set is unique within the existing power sets 00275 if (tmp_x2 == 0) { 00276 // create new state in res generator 00277 tmp_x2 = rResGen.InsState(); 00278 // insert newset in rPowerStates and get iterator,bool pair 00279 rPowerStates.push_back(currentset); 00280 rDetStates.push_back(tmp_x2); 00281 hashmap.insert(std::make_pair(sig, (Idx)rPowerStates.size() - 1)); 00282 FD_DF("mtcDeterministic: added new state " << rGen.SStr(tmp_x2) 00283 << " for new subset {" << currentset.ToString() << "}"); 00284 // set colored if one of the states in current set is colored 00285 for (lit = currentset.Begin(); lit != currentset.End(); ++lit) { 00286 const ColorSet& colors = rGen.Colors(*lit); 00287 rResGen.InsColors(tmp_x2,colors); 00288 FD_DF("mtcDeterministic: setting as colored: " << rGen.SStr(tmp_x2)); 00289 } 00290 } 00291 // introduce transition 00292 rResGen.SetTransition(rDetStates[current_vecindex], currentevent, tmp_x2); 00293 } 00294 } 00295 // fix names 00296 if (rGen.StateNamesEnabled() && rResGen.StateNamesEnabled()) { 00297 FD_DF("mtcDeterministic: fixing names..."); 00298 // rPowerStates / rDetStates index "iterator" 00299 std::vector<StateSet>::size_type i; 00300 // deterministic states iterator 00301 std::vector<Idx>::const_iterator dit; 00302 for (i = 0; i < rPowerStates.size(); ++i) { 00303 // temporary state name 00304 std::string name = "{"; 00305 for (lit = rPowerStates[i].Begin(); lit != rPowerStates[i].End(); ++lit) { 00306 if (rResGen.StateName(*lit) != "") { 00307 name = name + rResGen.StateName(*lit) + ","; 00308 } 00309 else { 00310 name = name + ToStringInteger(*lit) + ","; 00311 } 00312 } 00313 name.erase(name.length() - 1); 00314 name = name + "}"; 00315 rResGen.StateName(rDetStates[i], name); 00316 FD_DF("mtcDeterministic: setting state name \"" << name << "\" for index " << rDetStates[i]); 00317 } 00318 } 00319 // Delete unnecessary events and set event attributes 00320 rResGen.DelEvents(rResGen.UnusedEvents()); 00321 EventSet usedEvents = rResGen.UsedEvents(); 00322 rResGen.SetControllable(rGen.ControllableEvents()*usedEvents); 00323 rResGen.SetForcible(rGen.ForcibleEvents()*usedEvents); 00324 rResGen.ClrObservable(rGen.UnobservableEvents()*usedEvents); 00325 } 00326 00327 // mtcProjectNonDet(rGen&, rProjectAlphabet&) 00328 void mtcProjectNonDet(MtcSystem& rGen, const EventSet& rProjectAlphabet) { 00329 00330 // HELPERS: 00331 StateSet reach; // StateSet for reachable states 00332 std::stack<Idx> todo; // todo stack 00333 StateSet done; // done set 00334 Idx currentstate; // the currently processed state 00335 StateSet::Iterator lit; 00336 TransSet::Iterator tit; 00337 TransSet::Iterator tit_end; 00338 00339 // ALGORITHM: 00340 // initialize algorithm by pushing init states on todo stack 00341 for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) { 00342 FD_DF("mtcProjectNonDet: todo add: " << rGen.SStr(*lit)); 00343 todo.push(*lit); 00344 } 00345 00346 // process todo stack 00347 while (! todo.empty()) { 00348 currentstate = todo.top(); 00349 todo.pop(); 00350 done.Insert(currentstate); // mark as done 00351 FD_DF("mtcProjectNonDet: current state: " << rGen.SStr(currentstate)); 00352 00353 // comp accessible reach 00354 reach.Clear(); 00355 LocalAccessibleReach(rGen, rProjectAlphabet, currentstate, reach); 00356 FD_DF("mtcProjectNonDet: local reach: " << reach.ToString()); 00357 00358 // remove all transitions that leave current state 00359 // with an invisible event 00360 tit = rGen.TransRelBegin(currentstate); 00361 tit_end = rGen.TransRelEnd(currentstate); 00362 while(tit != tit_end) { 00363 FD_DF("mtcProjectNonDet: current transition: " << rGen.SStr(tit->X1) 00364 << "-" << rGen.EStr(tit->Ev) << "-" << rGen.SStr(tit->X2)); 00365 if (! rProjectAlphabet.Exists(tit->Ev)) { 00366 FD_DF("mtcProjectNonDet: deleting current transition"); 00367 TransSet::Iterator tit_tmp = tit; 00368 ++tit; 00369 rGen.ClrTransition(tit_tmp); 00370 } 00371 else { 00372 ++tit; 00373 } 00374 } 00375 00376 // relink outgoing transitions 00377 FD_DF("mtcProjectNonDet: relinking outgoing transitions..."); 00378 for (lit = reach.Begin(); lit != reach.End(); ++lit) { 00379 tit = rGen.TransRelBegin(*lit); 00380 tit_end = rGen.TransRelEnd(*lit); 00381 for (; tit != tit_end; ++tit) { 00382 if (rProjectAlphabet.Exists(tit->Ev)) { 00383 FD_DF("mtcProjectNonDet: relinking transition: " << rGen.TStr(*tit) << " to " << rGen.SStr(currentstate) << "--(" << rGen.EStr(tit->Ev) << ")-->" << rGen.SStr(tit->X2)); 00384 rGen.SetTransition(currentstate, tit->Ev, tit->X2); 00385 if (! done.Exists(tit->X2)) { 00386 FD_DF("mtcProjectNonDet: todo push: " << rGen.SStr(tit->X2)); 00387 todo.push(tit->X2); 00388 } 00389 } 00390 } 00391 // colored status test 00392 const ColorSet& colors = rGen.Colors(*lit); 00393 if (!colors.Empty()) { 00394 FD_DF("mtcProjectNonDet: setting colored state " << rGen.SStr(currentstate)); 00395 rGen.InsColors(currentstate, colors); 00396 } 00397 } 00398 } 00399 00400 // inject projection alphabet 00401 rGen.InjectAlphabet(rProjectAlphabet); 00402 00403 EventSet unused = rGen.UnusedEvents(); 00404 EventSet::Iterator eit; 00405 for(eit = unused.Begin(); eit != unused.End(); ++eit){ 00406 rGen.ClrEventAttribute(*eit); 00407 rGen.EventSymbolTablep()->ClrEntry(*eit); 00408 rGen.DelEvent(*eit); 00409 } 00410 // set name 00411 rGen.Name("MtcPro(" + rGen.Name() + ")" ); 00412 } 00413 00414 // wrapper 00415 void mtcProjectNonDet(const MtcSystem& rGen, const EventSet& rProjectAlphabet, MtcSystem& rResGen) { 00416 rResGen=rGen; 00417 mtcProjectNonDet(rResGen,rProjectAlphabet); 00418 } 00419 00420 // mtcProject(rGen, rProjectAlphabet, rResGen&) 00421 void mtcProject(const MtcSystem& rGen, const EventSet& rProjectAlphabet, MtcSystem& rResGen) { 00422 // algorithm: 00423 // temporary copy of rGen 00424 MtcSystem tmp; 00425 // temporarily assign rGen to rResGen 00426 MtcSystem copyGen = MtcSystem(rGen); 00427 // project rResGen with respect to rProjectAlphabet 00428 mtcProjectNonDet(copyGen, rProjectAlphabet); 00429 #ifdef FAUDES_DEBUG_FUNCTION 00430 FD_WARN("mtcProject: debug out") 00431 copyGen.Write("tmp_project_nd.gen"); 00432 #endif 00433 // put deterministic result into tmp 00434 mtcDeterministic(copyGen, tmp); 00435 #ifdef FAUDES_DEBUG_FUNCTION 00436 FD_WARN("mtcProject: debug out") 00437 tmp.Write("tmp_project_d.gen"); 00438 #endif 00439 // minimize states and rewrite result to rResGen 00440 mtcStateMin(tmp, rResGen); 00441 #ifdef FAUDES_DEBUG_FUNCTION 00442 FD_WARN("mtcProject: debug out") 00443 rResGen.Write("tmp_project_m.gen"); 00444 #endif 00445 // set controllability status TODO: other event attributes 00446 rResGen.SetControllable(rGen.ControllableEvents()*rProjectAlphabet); 00447 // set name 00448 rResGen.Name(rResGen.Name()+": mtcProject"); 00449 } 00450 00451 00452 // mtcProject(rGen, rProjectAlphabet, rEntryStatesMap&, rResGen&) 00453 void mtcProject(const MtcSystem& rGen, const EventSet& rProjectAlphabet, 00454 std::map<Idx,StateSet>& rEntryStatesMap, MtcSystem& rResGen) { 00455 // temporary copy of rGen 00456 MtcSystem tmp; 00457 MtcSystem copyGen = MtcSystem(rGen); 00458 // temporary entry state map 00459 std::map<Idx,StateSet> tmp_entrystatemap; 00460 // temporarily assign rGen to rResGen 00461 // std::cout << " copied low-level generator " << std::endl; 00462 // copyGen.DWrite(); 00463 // project tmp with respect to palphabet 00464 mtcProjectNonDet(copyGen, rProjectAlphabet); 00465 00466 // put deterministic result into tmp 00467 mtcDeterministic(copyGen, tmp_entrystatemap, tmp); 00468 // write entry state map for minimized generator 00469 std::vector<StateSet> subsets; 00470 std::vector<Idx> newindices; 00471 // minimize states and rewrite result to rResGen 00472 mtcStateMin(tmp, rResGen, subsets, newindices); 00473 // rResGen.DWrite(); 00474 // build entry state map 00475 std::vector<StateSet>::size_type i; 00476 std::map<Idx,StateSet>::iterator esmit; 00477 StateSet::Iterator sit; 00478 for (i = 0; i < subsets.size(); ++i) { 00479 StateSet tmpstates; 00480 for (sit = subsets[i].Begin(); sit != subsets[i].End(); ++sit) { 00481 esmit = tmp_entrystatemap.find(*sit); 00482 #ifdef FD_CHECKED 00483 if (esmit == tmp_entrystatemap.end()) { 00484 FD_WARN("mtcproject internal error"); 00485 abort(); 00486 } 00487 #endif 00488 // insert entry states in temporary StateSet 00489 tmpstates.InsertSet(esmit->second); 00490 } 00491 00492 rEntryStatesMap.insert(std::make_pair(newindices[i], tmpstates)); 00493 } 00494 } 00495 00496 00497 // mtcInvProject(rGen&, rProjectAlphabet) 00498 void mtcInvProject(MtcSystem& rGen, const EventSet& rProjectAlphabet) { 00499 // test if the alphabet of the generator is included in the given alphabet 00500 if(! (rProjectAlphabet >= rGen.Alphabet() ) ){ 00501 std::stringstream errstr; 00502 errstr << "Input alphabet has to contain alphabet of generator \"" << rGen.Name() << "\""; 00503 throw Exception("InvProject(Generator,EventSet)", errstr.str(), 506); 00504 } 00505 EventSet newevents = rProjectAlphabet - rGen.Alphabet(); 00506 // insert events into generator 00507 rGen.InsEvents(newevents); 00508 FD_DF("mtcInvProject: adding events \"" << newevents.ToString() << "\" at every state"); 00509 StateSet::Iterator lit; 00510 EventSet::Iterator eit; 00511 for (lit = rGen.StatesBegin(); lit != rGen.StatesEnd(); ++lit) { 00512 for (eit = newevents.Begin(); eit != newevents.End(); ++eit) 00513 rGen.SetTransition(*lit, *eit, *lit); 00514 } 00515 } 00516 00517 // RTI wrapper 00518 void mtcInvProject(const MtcSystem& rGen, const EventSet& rProjectAlphabet, MtcSystem& rResGen) { 00519 rResGen=rGen; 00520 mtcInvProject(rResGen,rProjectAlphabet); 00521 } 00522 00523 } // namespace faudes libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |