mtc_project.cpp

Go 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