cfl_determin.cpp

Go to the documentation of this file.
00001 /** @file cfl_determin.cpp powerset construction */
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_determin.h"
00024 
00025 namespace faudes {
00026 
00027 // UniqueInit(rGen&)
00028 void UniqueInit(Generator& 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   } else {
00039     inituni = rGen.InsState();
00040   }
00041   FD_DF("UniqueInit: introducing new initial state: " << inituni);
00042   // introduce outgoing transitions from initial state
00043   FD_DF("UniqueInit: introduce outgoing transitions: ");
00044   for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) {
00045     for (tit = rGen.TransRelBegin(*lit); tit != rGen.TransRelEnd(*lit); ++tit) {
00046       rGen.SetTransition(inituni, tit->Ev, tit->X2);
00047       FD_DF("UniqueInit:   " << inituni << "-" << tit->Ev << "-" << tit->X2);
00048     }
00049   }
00050   // mark the new init state if there exists an originally marked init state (tm 20101206)
00051   if(!(rGen.InitStates() *  rGen.MarkedStates()).Empty()){
00052     rGen.SetMarkedState(inituni);
00053     FD_DF("UniqueInit: set marked state: " << inituni);
00054   }
00055   // delete old istates
00056   rGen.ClearInitStates();
00057   // set inituni as new initial state 
00058   rGen.SetInitState(inituni);
00059 }
00060 
00061 // UniqueInit(rGen&,rResGen&)
00062 void UniqueInit(const Generator& rGen, Generator& rResGen) {
00063   rResGen.Assign(rGen);
00064   UniqueInit(rResGen);
00065 }
00066 
00067 // Deterministic(rGen&, rResGen&)
00068 void Deterministic(const Generator& rGen, Generator& rResGen) {
00069   // temporary vectors
00070   std::vector<StateSet> power_states;
00071   std::vector<Idx> det_states;
00072   Deterministic(rGen, power_states, det_states, rResGen);
00073 }
00074 
00075 
00076 // aDeterministic(rGen&, rResGen&)
00077 void aDeterministic(const Generator& rGen, Generator& rResGen) {
00078   // prepare result to keep original alphabet
00079   Generator* pResGen = &rResGen;
00080   if(&rResGen==&rGen) {
00081     pResGen= rResGen.New();
00082   }
00083   // perform op
00084   Deterministic(rGen,*pResGen);
00085   // set old attributes
00086   pResGen->EventAttributes(rGen.Alphabet());
00087   // copy result
00088   if(pResGen != &rResGen) {
00089     pResGen->Move(rResGen);
00090     delete pResGen;
00091   }
00092 }
00093 
00094 
00095 // Deterministic(rGen&, rEntryStatesMap&, rResGen&)
00096 void Deterministic(const Generator& rGen, std::map<Idx,StateSet>& rEntryStatesMap,
00097        Generator& rResGen) {
00098   // prepare result:
00099   rEntryStatesMap.clear();
00100   // helpers:
00101   std::vector<StateSet> power_states;
00102   std::vector<Idx> det_states;
00103   // call Deterministic function
00104   Deterministic(rGen, power_states, det_states, rResGen);
00105   // build entry states map
00106   std::vector<StateSet>::size_type i;
00107   for (i = 0; i < power_states.size(); ++i) {
00108     rEntryStatesMap.insert(std::pair<Idx,StateSet>(det_states[i], power_states[i]));
00109   }
00110 }
00111 
00112 
00113 void Deterministic(const Generator& rGen, std::vector<StateSet>& rPowerStates,
00114        std::vector<Idx>& rDetStates, Generator& rResGen) {
00115 
00116   // note: there is a demonstrative description of the multiway merge
00117   // algorithm in the master thesis. (Bernd Opitz)
00118 
00119   FD_DF("Deterministic(): core function #" << rGen.Size());
00120 
00121   // use pointer pResGen to result rResGen
00122   Generator* pResGen = &rResGen;
00123   if(&rResGen== &rGen) {
00124     pResGen= rResGen.New();
00125   }
00126 
00127   // prepare result
00128   pResGen->Clear();  
00129   rPowerStates.clear();
00130   rDetStates.clear();
00131   // set the name
00132   pResGen->Name(CollapsString("Det(" + rGen.Name() + ")"));
00133   // copy alphabet
00134   FD_DF("Deterministic A " << rGen.Alphabet().ToString());
00135   pResGen->InjectAlphabet(rGen.Alphabet());
00136   FD_DF("Deterministic B");
00137 
00138   // bail out on empty input 
00139   if(rGen.InitStatesEmpty()) {
00140     if(pResGen != &rResGen) {
00141       pResGen->Move(rResGen);
00142       delete pResGen;
00143     }
00144     FD_DF("Deterministic(): done (empty)"); 
00145     return;
00146   }
00147 
00148   // helpers
00149   typedef std::multimap< Idx,std::vector<StateSet>::size_type > T_HASHMAP;
00150   T_HASHMAP hashmap;
00151   std::vector<StateSet>::size_type current_vecindex;
00152   std::pair< std::map<StateSet,Idx>::iterator,bool > result;
00153   TransSet::Iterator transrel_end = rGen.TransRelEnd();
00154   StateSet newset;
00155   StateSet::Iterator lit;
00156   const Idx max_idx = std::numeric_limits<Idx>::max();
00157 
00158   // lock transrel to prevent iterator tracking (tmoor 201403)
00159   rGen.TransRel().Lock();
00160   
00161   // initialize rPowerStates with subset of initial states
00162   Idx newstate = pResGen->InsInitState();
00163   for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) {
00164     // clear set and insert single state
00165     newset.Insert(*lit);
00166     // if marked state set in res generator
00167     if (rGen.ExistsMarkedState(*lit)) {
00168       pResGen->SetMarkedState(newstate);
00169       FD_DF("Deterministic: setting as mstate: " << rGen.SStr(newstate));
00170     }
00171   }
00172   FD_DF("Deterministic: created subset of initial states {"
00173   << newset.ToString() << "} with deterministic state index "
00174   << rGen.SStr(newstate));
00175   // internally record newset 
00176   rPowerStates.push_back(newset);
00177   rDetStates.push_back(newstate);
00178   hashmap.insert(std::make_pair(newset.Signature(), (Idx)rPowerStates.size() - 1));
00179 
00180   // iteration over all states
00181   for (current_vecindex = 0; current_vecindex < rPowerStates.size(); 
00182        ++current_vecindex) {
00183     FD_WPC(current_vecindex,rPowerStates.size(), "Deterministic(): current/size: "<<  current_vecindex << " / " << rPowerStates.size());
00184     FD_DF("Deterministic: current power set: {" 
00185     << rPowerStates[current_vecindex].ToString() << "} -> " 
00186     << rDetStates[current_vecindex]);
00187 
00188     std::vector<StateSet> newset_vec;
00189     std::vector<Idx> event_vec;
00190 
00191     // multiway merge begin
00192     FD_DF("Deterministic: starting multiway merge...");
00193     std::list<TransSet::Iterator> merge_iterators;
00194     std::vector<Transition> trans_vec;
00195 
00196     // add transset iterator at begin of each state's transitions
00197     TransSet::Iterator tit;
00198     for (lit = rPowerStates[current_vecindex].Begin(); 
00199    lit != rPowerStates[current_vecindex].End(); ++lit) {
00200       tit = rGen.TransRelBegin(*lit);
00201       if (tit != rGen.TransRelEnd(*lit)) {
00202   merge_iterators.push_back(tit);
00203   FD_DF("Deterministic: added merge iterator: " << rGen.SStr(tit->X1) 
00204         << "-" << rGen.EStr(tit->Ev) << "-" << rGen.SStr(tit->X2));
00205       }
00206     }
00207 
00208     // find first iterator with lowest event
00209     while (! merge_iterators.empty()) {
00210       Idx currentevent = max_idx;
00211       std::list<TransSet::Iterator>::iterator i; 
00212       std::list<TransSet::Iterator>::iterator currentit = merge_iterators.end();
00213       for (i = merge_iterators.begin(); i != merge_iterators.end(); ++i) {
00214   if ((*i)->Ev < currentevent) {
00215     currentevent = (*i)->Ev;
00216     currentit = i;
00217   }
00218       }
00219       // currentit now holds the iterator
00220       // currentevent holds the lowest event (lowest Idx)
00221 
00222       // merge all transitions with currentevent at each iterator in a row;
00223       // this is a modification of multiway merge as after projection the
00224       // automaton most likely holds states with many transitions that share 
00225       // the same event; only merging the lowest transition and continue with
00226       // search for the lowest event again would be to slow here (because
00227       // of too much iterator dereferencing).
00228       Idx currentstate;
00229       while (currentit != merge_iterators.end()) {
00230   currentstate = (*currentit)->X1;
00231   TransSet::Iterator& j = *currentit;
00232   while (1) {
00233     // remove iterator if it reaches the end of the transition set
00234     if (j == transrel_end) {
00235       merge_iterators.erase(currentit++);
00236       break;
00237     }
00238     // if current iterator is in its original state
00239     else if (j->X1 == currentstate) {
00240       // if the event is still the same add the transition
00241       if (j->Ev == currentevent) {
00242         trans_vec.push_back(*j); 
00243         FD_DF("Deterine: adding transition to list: " 
00244         << rGen.SStr(j->X1) << "-" << rGen.EStr(j->Ev) << "-"
00245         << rGen.SStr(j->X2));
00246       }
00247       // else go to next iterator
00248       else {
00249         ++currentit;
00250         break;
00251       }
00252     }
00253     // if the iterator is beyond its original state remove it
00254     else {
00255       merge_iterators.erase(currentit++);
00256       break;
00257     }
00258     ++j;
00259   }
00260       }
00261     }
00262 
00263     // partition transition vector by events. optimizable? 
00264     FD_DF("Deterministic: partitioning the transition vector...");
00265     std::vector<Transition>::iterator tv_it;
00266     StateSet newset;
00267     Idx lastevent = 0;
00268     for (tv_it = trans_vec.begin(); tv_it != trans_vec.end(); ++tv_it) {
00269       if ((tv_it->Ev == lastevent) || (lastevent == 0)) {
00270   newset.Insert(tv_it->X2);
00271   lastevent = tv_it->Ev;
00272       }
00273       else {
00274   FD_DF("Deterministic: partition: {" << newset.ToString() 
00275         << "} with event " << rGen.EStr(lastevent));
00276   newset_vec.push_back(newset);
00277   event_vec.push_back(lastevent);
00278   newset.Clear();
00279   newset.Insert(tv_it->X2);
00280   lastevent = tv_it->Ev;
00281       }
00282     }
00283     if (! newset.Empty()) {
00284       FD_DF("Deterministic: partition: {" << newset.ToString() 
00285       << "} with event " << rGen.EStr(lastevent));
00286       newset_vec.push_back(newset);
00287       event_vec.push_back(lastevent);
00288     }
00289     FD_DF("Deterministic: partitioning the transition vector finished");
00290     FD_DF("Deterministic: multiway merge finished");
00291     // multiway merge end
00292 
00293 
00294     std::vector<StateSet>::size_type nsv_index;
00295     for (nsv_index = 0; nsv_index < newset_vec.size(); ++nsv_index) {
00296       StateSet& currentset = newset_vec[nsv_index];
00297       Idx currentevent = event_vec[nsv_index];
00298       Idx tmp_x2 = 0;
00299       Idx sig = currentset.Signature();
00300       // test if newset signature is already known
00301       std::pair<T_HASHMAP::iterator,T_HASHMAP::iterator> phit
00302   = hashmap.equal_range(sig);
00303       T_HASHMAP::iterator hit = phit.first;
00304       for (hit = phit.first; hit != phit.second; ++hit) {
00305   // test set of every matching signature for equality
00306   if (currentset == rPowerStates[hit->second]) {
00307     tmp_x2 = rDetStates[hit->second];
00308     break;
00309   }
00310       }
00311 
00312       // if new set is unique within the existing power sets
00313       if (tmp_x2 == 0) {
00314   // create new state in res generator
00315   tmp_x2 = pResGen->InsState();
00316   // insert newset in rPowerStates and get iterator,bool pair
00317   rPowerStates.push_back(currentset);
00318   rDetStates.push_back(tmp_x2);
00319   hashmap.insert(std::make_pair(sig, (Idx)rPowerStates.size() - 1));
00320   FD_DF("Deterministic: added new state " 
00321         << rGen.SStr(tmp_x2) 
00322         << " for new subset {" << currentset.ToString() << "}");
00323   // set marked if one of the states in current set is marked
00324   for (lit = currentset.Begin(); lit != currentset.End(); ++lit) {
00325     if (rGen.ExistsMarkedState(*lit)) {
00326       pResGen->SetMarkedState(tmp_x2);
00327       break;
00328     }
00329   }
00330       }
00331       // introduce transition
00332       pResGen->SetTransition(rDetStates[current_vecindex], currentevent, tmp_x2);
00333     }
00334   }
00335 
00336 
00337   // fix names
00338   if (rGen.StateNamesEnabled() && pResGen->StateNamesEnabled()) {
00339     FD_DF("Deterministic: fixing names...");
00340     // rPowerStates / rDetStates index "iterator"
00341     std::vector<StateSet>::size_type i;
00342     // deterministic states iterator
00343     std::vector<Idx>::const_iterator dit;
00344     for (i = 0; i < rPowerStates.size(); ++i) {
00345       // temporary state name
00346       std::string name = "{";
00347       for (lit = rPowerStates[i].Begin();  lit != rPowerStates[i].End(); ++lit) {
00348   if (rGen.StateName(*lit) != "") name = name + rGen.StateName(*lit) + ",";
00349   else name = name + ToStringInteger(*lit) + ",";
00350       }
00351       name.erase(name.length() - 1);
00352       name = name + "}";
00353       FD_DF("Deterministic: setting state name \"" << name << "\" for index "
00354       << rDetStates[i]);
00355       pResGen->StateName(rDetStates[i], name);
00356     }
00357   }
00358   
00359   // move pResGen to rResGen
00360   if(pResGen != &rResGen) {
00361     pResGen->Move(rResGen);
00362     delete pResGen;
00363   }
00364 
00365   FD_DF("Deterministic(): core function: done");
00366     
00367 }
00368 
00369 
00370 
00371 } // namespace faudes

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen