About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
libFAUDES

Sections

Index

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

libFAUDES 2.20d --- 2011.04.26 --- c++ source docu by doxygen