project.cpp

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

Generated on Fri May 9 11:26:47 2008 for libFAUDES 2.09b by  doxygen 1.4.4