libFAUDES

Sections

Index

cfl_statemin.cpp

Go to the documentation of this file.
00001 /** @file cfl_statemin.cpp state space minimization */
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_statemin.h"
00024 #include "cfl_exception.h"
00025 #include "cfl_project.h"
00026 
00027 namespace faudes {
00028 
00029 // StateMin(rGen, rResGen)
00030 void StateMin(const vGenerator& rGen, vGenerator& rResGen) {
00031   // how to avoid the copy?? see core procedure
00032   vGenerator* accgen=rGen.Copy();
00033   StateMin(*accgen, rResGen);
00034 }
00035 
00036 // StateMin(rGen, rResGen)
00037 void aStateMin(const vGenerator& rGen, vGenerator& rResGen) {
00038   vGenerator* accgen=rGen.Copy();
00039   StateMin(*accgen, rResGen);
00040   // restore attributes
00041   rResGen.EventAttributes(accgen->Alphabet());
00042 }
00043 
00044 // StateMin(rGen)
00045 void aStateMin(vGenerator& rGen) {
00046   vGenerator* accgen=rGen.Copy();
00047   StateMin(*accgen, rGen);
00048   // restore attributes
00049   rGen.EventAttributes(accgen->Alphabet());
00050 }
00051 
00052 // StateMin(rGen, rResGen)
00053 void StateMin(vGenerator& rGen, vGenerator& rResGen) {
00054   std::vector<StateSet> subsets;
00055   std::vector<Idx> newindices;
00056   StateMin(rGen, rResGen, subsets, newindices);
00057 }
00058 
00059 // StateMin(rGen, rResGen, rSubSets, rNewIndices)
00060 // todo: make argument const, circumvent accessible
00061 void StateMin(vGenerator& rGen, vGenerator& rResGen, 
00062         std::vector<StateSet>& rSubsets, std::vector<Idx>& rNewIndices) {
00063   FD_DF("StateMin: *** computing state space minimization of generator " 
00064   << &rGen << " ***");
00065 
00066   FD_DF("StateMin: making generator accessible");
00067   rGen.Accessible();
00068   if (rGen.Size() == 0) {
00069     FD_DF("StateMin: generator size 0. returning given generator");
00070     rResGen = rGen;
00071     return;
00072   }
00073   if (rGen.Size() == 1) {
00074     FD_DF("StateMin: generator size 1. returning given generator");
00075     rResGen = rGen;
00076     rSubsets.push_back(rGen.States() );
00077     rNewIndices.push_back(*( rResGen.States().Begin() ) );
00078     return;
00079   }
00080 
00081   // ensure generator is deterministic
00082   if (! rGen.IsDeterministic()) {
00083     throw Exception("StateMin", "input automaton nondeterministic", 101);
00084   }
00085     
00086   // use pointer pResGen to result rResGen; if rResGen is identical to
00087   // one of the parameters, allocate temporary object and copy back later
00088   vGenerator* pResGen = &rResGen;
00089   if(&rResGen==&rGen) {
00090     pResGen= pResGen->New();
00091   }
00092 
00093   // prepare result
00094   pResGen->Clear();
00095   pResGen->Name(rGen.Name()+" [minstate]");
00096   pResGen->InjectAlphabet(rGen.Alphabet());
00097   bool stateNames= pResGen->StateNamesEnabled() && rGen.StateNamesEnabled();
00098   // blocks B[i]
00099   std::vector<StateSet>& b = rSubsets; // convenience notation "b"
00100   Idx i, j;
00101   // set of active b (iterators)
00102   std::set<Idx> active;
00103   std::set<Idx>::iterator ait;
00104   // reverse transrel
00105   TransSetEvX2X1 rtransrel;
00106   rGen.TransRel(rtransrel);
00107   TransSetEvX2X1::Iterator rtit, rtit_end;
00108   // other stuff
00109   StateSet::Iterator lit; 
00110   TransSet::Iterator tit;
00111 
00112   // set up b "B[i]"
00113   i = 0;
00114   if (rGen.Size() - rGen.MarkedStatesSize() > 0) {
00115     StateSet notmarked=rGen.States() - rGen.MarkedStates();
00116     notmarked.Name("B[i]"); 
00117     FD_DF("StateMin: new block B[" << i << "] = {" << notmarked.ToString() << "}");
00118     b.push_back(notmarked);  //X -Xm
00119     active.insert(i++);
00120   }
00121   if (rGen.MarkedStatesSize() > 0) { // tmoor 20090915: conditional to prevent emty block 
00122     FD_DF("StateMin: new block B[" << i << "] = {" << rGen.MarkedStates().ToString() << "}");
00123     b.push_back(rGen.MarkedStates()); // Xm
00124     active.insert(i++);
00125   }
00126 
00127   // while there is a active block B
00128   while (! active.empty()) {
00129     FD_WPC(b.size()-active.size(), b.size(), "StateMin: blocks/active:   " << b.size() << " / " << active.size());
00130 #ifdef FAUDES_DEBUG_FUNCTION
00131     FD_DF("StateMin: while there is an active block B...");
00132     std::set<Idx>::iterator _it1;
00133     std::stringstream str;
00134     for (_it1 = active.begin(); _it1 != active.end(); ++_it1) {
00135       str << *_it1 << " ";
00136     }
00137     FD_DF("StateMin: active: "+str.str());
00138     std::vector<StateSet>::iterator _it2;
00139     str.clear();
00140     str.str("");
00141     for (_it2 = b.begin(); _it2 != b.end(); ++_it2) {
00142       str << "{" << _it2->ToString() << "} "<<std::endl;
00143     }
00144     str << std::endl;
00145     FD_DF("B: "+str.str());
00146 #endif
00147     // current block B[i]
00148     i = *(active.begin());
00149     // inactivate B[i]
00150     active.erase(active.begin());
00151     FD_DF("StateMin: getting active block B[" << i << "] = {" <<
00152     b.at(i).ToString() << "}");
00153     // b_current <- B[i]
00154     StateSet b_current = b.at(i);
00155 
00156     // compute C = f^-1(B[i]) for every event in B[i] (as b_current)
00157     StateSet c;
00158     EventSet::Iterator eit;
00159     // iteration over alphabet
00160     for (eit = rGen.AlphabetBegin(); eit != rGen.AlphabetEnd(); ++eit) {
00161       c.Clear();
00162       // iteration over states in current block
00163       for (lit = b_current.Begin(); lit != b_current.End(); ++lit) {
00164   // find predecessor states by current ev + x2
00165   rtit = rtransrel.BeginByEvX2(*eit, *lit);
00166   rtit_end = rtransrel.EndByEvX2(*eit, *lit);
00167   for (; rtit != rtit_end; ++rtit) {
00168     c.Insert(rtit->X1);
00169   }
00170       }
00171       // if predecessor states where found
00172       if (! c.Empty()) {
00173   // search for new block on next event or coming end of rtransrel with
00174   // x1 as *lit
00175   FD_DF("StateMin: computed predecessor states C = {" << c.ToString() 
00176         << "} for event " << rGen.EventName(*eit));
00177   // foreach block D 
00178   for (j=0; j < b.size(); ++j) {
00179     FD_DF("StateMin: examining block B[" << j << "] = {" << 
00180     b.at(j).ToString() << "}");
00181     // compute D' = D intersection C
00182     StateSet d_ = b.at(j) * c;
00183     d_.Name("D'");
00184     // compute D'' = D - D'; remove D, add D''
00185     StateSet d__ = b.at(j) - d_;
00186     d__.Name("D''");
00187     // check D split by B
00188     if (d_.Empty() || d__.Empty()) {
00189       FD_DF("StateMin: -> no split");  
00190       continue;
00191     }
00192     FD_DF("StateMin: -> split:");  
00193     b[j] = d_;
00194     FD_DF("StateMin: new block B[" << j << "] = {" 
00195     << d_.ToString() << "}");
00196     b.push_back(d__);
00197     FD_DF("StateMin: new block B[" << b.size()-1 << "] = {"
00198     << d__.ToString() << "}");
00199     // if D was active
00200     if (active.count(j) > 0) {
00201       // then mark both D', D'' active
00202       active.insert((Idx)b.size()- 1);
00203       FD_DF("StateMin: mark active: " << b.size()-1);
00204     }
00205     // else mark smaller of D', D'' active
00206     else {
00207       if (d_.Size() < d__.Size()) {
00208         active.insert(j);
00209         FD_DF("StateMin: mark active: " << j);
00210       }
00211       else {
00212         active.insert((Idx)b.size()-1);
00213         FD_DF("StateMin: mark active: " << b.size()-1);
00214       }
00215     }
00216   } // foreach block D
00217   c.Clear();
00218       }
00219     }
00220   }
00221 
00222   FD_DF("StateMin: *** building minimized generator ***");
00223   // build minimized generator
00224   std::map<Idx,Idx> minstatemap;
00225   Idx newstate;
00226   // loop over all blocks B
00227   for (i = 0; i < b.size(); ++i) {
00228     // create state in new generator for every block
00229     newstate = pResGen->InsState();
00230     rNewIndices.push_back(newstate);
00231     FD_DF("StateMin: block {" << b.at(i).ToString() 
00232     << "} -> new state " << newstate);
00233     std::ostringstream ostr; 
00234     for (lit = b.at(i).Begin(); lit != b.at(i).End(); ++lit) {
00235       // set minstatemap entry for every state in gen
00236       minstatemap[*lit] = newstate;
00237       if(stateNames) {
00238   if (rGen.StateName(*lit) == "") {
00239     ostr << ToStringInteger(*lit) << ",";
00240   }
00241   else {
00242     ostr << rGen.StateName(*lit) << ",";
00243   }
00244       }
00245       // set istates
00246       if (rGen.ExistsInitState(*lit)) {
00247   pResGen->SetInitState(newstate);
00248   FD_DF("StateMin: -> initial state");
00249       }
00250       // set mstates
00251       if (rGen.ExistsMarkedState(*lit)) {
00252   pResGen->SetMarkedState(newstate);
00253   FD_DF("StatMmin: -> marked state");
00254       }
00255     }
00256     if(stateNames) {
00257       std::string statename = ostr.str();
00258       if(statename!="") statename.erase(statename.length()-1);
00259       statename = "{" + statename + "}";
00260       pResGen->StateName(newstate, statename);
00261     }
00262   }
00263   // create transition relation
00264   for (tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) {
00265     pResGen->SetTransition(minstatemap[tit->X1], tit->Ev, minstatemap[tit->X2]);
00266     FD_DF("statemin: adding transition: " 
00267     << minstatemap[tit->X1] << "-" << tit->Ev << "-" 
00268     << minstatemap[tit->X2]);
00269   }
00270     
00271   // if necessary, move pResGen to rResGen
00272   if(pResGen != &rResGen) {
00273     pResGen->Move(rResGen);
00274     delete pResGen;
00275   }
00276 }
00277   
00278 } // namespace faudes

libFAUDES 2.18b --- 2010-12-17 --- c++ source docu by doxygen 1.6.3