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

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