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

Sections

Index

cfl_graphfncts.cpp

Go to the documentation of this file.
00001 /** @file cfl_graphfncts.cpp Operations on (directed) graphs. */
00002 
00003 /* FAU Discrete Event Systems Library (libfaudes)
00004 
00005    Copyright (C) 2009  Thomas Moor, Klaus Schmidt, Sebastian Perk
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_graphfncts.h"
00024 
00025 
00026 namespace faudes {
00027 
00028 /*
00029 **********************************************************************
00030 **********************************************************************
00031 **********************************************************************
00032 
00033 Search for strongly connected ycless components (SCC)
00034 
00035 **********************************************************************
00036 **********************************************************************
00037 **********************************************************************
00038 */
00039 
00040 // Filter class for SCC search: statics
00041 const StateSet SccFilter::msEmptyStates=StateSet();
00042 const EventSet SccFilter::msEmptyEvents=EventSet();
00043 
00044 // Filter class for SCC search: destructor
00045 SccFilter::~SccFilter(void) {
00046   if(mpStatesAvoid) delete mpStatesAvoid;
00047   if(mpStatesRequire) delete mpStatesRequire;
00048   if(mpEventsAvoid) delete mpEventsAvoid;
00049 }
00050 
00051 // Filter class for SCC search: constructors
00052 SccFilter::SccFilter(void) :
00053   mMode(0x00),
00054   pStatesAvoid(&msEmptyStates),
00055   pStatesRequire(&msEmptyStates),
00056   pEventsAvoid(&msEmptyEvents),
00057   mpStatesAvoid(0),
00058   mpStatesRequire(0),
00059   mpEventsAvoid(0)
00060 {}
00061 
00062 // Filter class for SCC search: constructors
00063 SccFilter::SccFilter(int mode, const StateSet& rStatesAvoidRequire) :
00064   mMode(mode),
00065   pStatesAvoid(&msEmptyStates),
00066   pStatesRequire(&msEmptyStates),
00067   pEventsAvoid(&msEmptyEvents),
00068   mpStatesAvoid(0),
00069   mpStatesRequire(0),
00070   mpEventsAvoid(0)
00071 {
00072   // no special events
00073   mMode &= ~EventsAvoid;
00074   // use states for require
00075   if(mMode & StatesRequire)
00076     pStatesRequire=&rStatesAvoidRequire;
00077   // use states for avoid
00078   if(mMode & StatesAvoid)
00079     pStatesAvoid=&rStatesAvoidRequire;
00080 }
00081 
00082 // Filter class for SCC search: constructors
00083 SccFilter::SccFilter(int mode, const StateSet& rStatesAvoid, const StateSet& rStatesRequire): 
00084   mMode(mode),
00085   pStatesAvoid(&msEmptyStates),
00086   pStatesRequire(&msEmptyStates),
00087   pEventsAvoid(&msEmptyEvents),
00088   mpStatesAvoid(0),
00089   mpStatesRequire(0),
00090   mpEventsAvoid(0)
00091 {
00092   // no special events
00093   mMode &= ~EventsAvoid;
00094   // but special states
00095   mMode |= StatesRequire;
00096   mMode |= StatesAvoid;
00097   // set internal pointers
00098   pStatesAvoid=&rStatesAvoid;
00099   pStatesRequire=&rStatesRequire;
00100 }
00101 
00102 
00103 // Filter class for SCC search: constructors
00104 SccFilter::SccFilter(int mode, const Generator& rGen) :
00105   mMode(mode),
00106   pStatesAvoid(&msEmptyStates),
00107   pStatesRequire(&msEmptyStates),
00108   pEventsAvoid(&msEmptyEvents),
00109   mpStatesAvoid(0),
00110   mpStatesRequire(0),
00111   mpEventsAvoid(0)
00112 {
00113   // sets all empty by default
00114   mMode &= ~(StatesAvoid | StatesRequire | EventsAvoid );
00115   // ignore livelocks ==> require at least one marked state
00116   if(mode & IgnoreLiveLocks) {
00117     pStatesRequire=&rGen.MarkedStates();
00118     mMode |= StatesRequire;
00119   }
00120   // livelocks only ==> avoid marked states
00121   if(mode & LiveLocksOnly) {
00122     pStatesAvoid=&rGen.MarkedStates();
00123     mMode |= StatesAvoid;
00124   }
00125   // accessible only ==> deal with this in api wrappers
00126   if(mode & IgnoreUnaccessible) {
00127     (void) mode;
00128   }  
00129 }
00130 
00131 
00132 
00133 // Recursive function to search for SCCs.
00134 // The algorithm is a minor variation of the one prsented in
00135 //  -- Aho, Hopcroft, Ullman: The Design and Analysis of Computer Algorithms
00136 void SearchScc(
00137   const Idx vState,            // Current state under investigation
00138   int& vRcount,                // Depth count of recursion
00139   const Generator& rGen,       // Graph to inspect
00140   const SccFilter& rFilter,    // Filter to ignore transitions with specified events
00141   StateSet&  rTodo,            // States not dealt with so far
00142   std::stack<Idx>& rStack,      // Stack of currently considered states
00143   StateSet& rStackStates,      // Stack contents as set
00144   std::map<const Idx, int>& rDfn, // Map assigning to each state its depth-first count
00145   std::map<const Idx, int>& rLowLnk, // Map assigning to each state its LOWLINK Number
00146   std::list<StateSet>& rSccList,  // Record result: list of SCCs 
00147   StateSet& rRoots)             // Record result: one state per SCC
00148 {
00149   FD_DF("SerchScc: -- recursive search from state "<< vState << " at level " << vRcount << " --");
00150   // Take current state from todo list
00151   rTodo.Erase(vState);
00152   // Ignore filter: avoid states
00153   if(rFilter.mMode & SccFilter::StatesAvoid)
00154   if(rFilter.pStatesAvoid->Exists(vState)) return;
00155   // Ignore filter: break recursion on find first
00156   if(rFilter.mMode & SccFilter::FindFirst)
00157   if(!rSccList.empty()) return;
00158   // Record depth-first level for current state and initialise low-link level
00159   rDfn[vState]=vRcount;
00160   rLowLnk[vState]=vRcount;
00161   // Increment depth-first level
00162   vRcount++;
00163   // Push state on stack;
00164   rStack.push(vState);
00165   rStackStates.Insert(vState);
00166   /*
00167   std::list<Idx>::iterator vsit = --rStack.end();
00168   */
00169   // Create set of successor states "L[state]" 
00170   StateSet SuccStates = StateSet();
00171   TransSet::Iterator tit = rGen.TransRelBegin(vState);
00172   TransSet::Iterator tit_end = rGen.TransRelEnd(vState);
00173   for(; tit != tit_end; ++tit) {
00174     // Ignore avoid: avoid states
00175     if(rFilter.mMode & SccFilter::StatesAvoid)
00176     if(rFilter.pStatesAvoid->Exists(tit->X2)) continue;
00177     // Ignore filter: avoid events
00178     if(rFilter.mMode & SccFilter::EventsAvoid)
00179     if(rFilter.pEventsAvoid->Exists(tit->Ev)) continue;
00180     // Record
00181     SuccStates.Insert(tit->X2);
00182   }
00183   // Iterate over vertices *sit of L[state] 
00184   StateSet::Iterator sit = SuccStates.Begin();
00185   StateSet::Iterator sit_end = SuccStates.End();
00186   for(; sit != sit_end; ++sit) {
00187     // Successors that are on the todo list get ... 
00188     if(rTodo.Exists(*sit)) {        
00189        // ... searched recursively, and ...
00190        SearchScc(*sit, vRcount, rGen, rFilter, rTodo, rStack, rStackStates, rDfn, rLowLnk, rSccList, rRoots);
00191        // ... the current low-link gets updated to the new minimum.
00192        if(rLowLnk[*sit]<rLowLnk[vState]) rLowLnk[vState]=rLowLnk[*sit];
00193        // Break recursion on find first
00194        if(rFilter.mMode & SccFilter::FindFirst)
00195        if(!rSccList.empty()) return;
00196     }
00197     // Successors that are not on the todo list ...
00198     else {
00199       // ... if they have a lower deph-first level ...
00200       if(rDfn[*sit]<rDfn[vState])  
00201       // ... and if the are on the stack at all ...
00202       if(rStackStates.Exists(*sit)) 
00203       // ... set the current low-link to the new minimum 
00204       if(rDfn[*sit]<rLowLnk[vState]) rLowLnk[vState]=rDfn[*sit];
00205     }
00206   }//end for: iterate successors
00207 
00208   // If the current state is the root of a SCC, record the result
00209   if((rLowLnk[vState]==rDfn[vState])) {
00210     FD_DF("SearchScc: retrieving SCC from stack, root " << vState);        
00211     bool record=true;
00212     // Technically, each state that fails to be part of a cycle forms an
00213     // SCC. We optionally ignore those trivial SCCs. They are identified by consisting of
00214     // one state only and having no (relevant) selfloop.
00215     if(rFilter.mMode & SccFilter::IgnoreTrivial) {
00216       if(rStack.top()==vState) {
00217         TransSet::Iterator tit = rGen.TransRelBegin(vState);
00218         TransSet::Iterator tit_end = rGen.TransRelEnd(vState);
00219         for(; tit != tit_end; ++tit) {
00220           // no self loop
00221           if(tit->X2!=vState) continue;
00222           // fail for avoid event
00223           if(rFilter.mMode & SccFilter::EventsAvoid)
00224     if(rFilter.pEventsAvoid->Exists(tit->Ev)) 
00225             continue;
00226           /*
00227           // fail no required event
00228           if(rFilter.mMode & SccFilter::EventsRequire)
00229     if(!rFilter.pEventsRequire->Exists(tit->Ev)) 
00230             continue;
00231     */
00232           // found relevant selfloop
00233           break;
00234         }
00235         if(tit==tit_end) record=false;
00236       }
00237 #ifdef FAUDES_DEBUG_FUNCTION
00238      if(!record) FD_DF("SearchScc: trivial loop, ignored");
00239 #endif
00240     }
00241     /*
00242     // Inspect for required events (TODO: perhaps record path incl. events?)
00243     if(rFilter.mMode & SccFilter::EventsRequire) {
00244       bool reqevent=false;
00245       for(;vsit!=rStack.end();) {
00246         Idx x1, x2;
00247         x1=*vsit;
00248         if(++vsit==rStack.end()) x2=vState;
00249         else x2=*vsit;
00250         TransSet::Iterator tit = rGen.TransRelBegin(x1);
00251         TransSet::Iterator tit_end = rGen.TransRelEnd(x1);
00252         for(; tit != tit_end; ++tit) {
00253           // not on my path
00254           if(tit->X2!=x2) continue;
00255           // event not found
00256           if(!rFilter.pEventsRequire->Exists(tit->Ev)) continue;
00257           // found
00258           reqevent=true;
00259         }
00260       }
00261       if(reqevent==false) record=false;
00262     }
00263     */
00264     // Retrieve SCC from stack, inspect required states
00265     rSccList.push_back(StateSet());
00266     rRoots.Insert(vState);
00267     Idx top;
00268     bool reqstate=false;
00269     do {
00270       // Pop top of stack
00271       top=rStack.top();
00272       rStackStates.Erase(top);
00273       rStack.pop();
00274       // Record/track state requirements
00275       if(record) {
00276         rSccList.back().Insert(top);
00277         // Required state?
00278         if(rFilter.mMode & SccFilter::StatesRequire)
00279   if(rFilter.pStatesRequire->Exists(top)) 
00280           reqstate=true;
00281       }
00282     } while(top!=vState);
00283     // Invalidate missed requirements
00284     if(rFilter.mMode & SccFilter::StatesRequire)
00285     if(!reqstate)
00286       record=false;
00287     // Invalidate result
00288     if(!record) {
00289       rSccList.pop_back();
00290       rRoots.Erase(vState);
00291     }
00292   } // end if: record
00293 }
00294 
00295 
00296 // ComputeScc(Generator, SccList, Roots)
00297 bool ComputeScc(
00298   const Generator& rGen,
00299   const SccFilter& rFilter,
00300   std::list<StateSet>& rSccList,
00301   StateSet& rRoots)
00302 {
00303   FD_DF("CompteScc(" << rGen.Name() << ")");
00304 
00305   // inititalize results:
00306   rRoots.Clear();
00307   rSccList.clear();
00308 
00309   // initialize counter for depthfirstnumbers(DFN):
00310   int count=1;
00311 
00312   // provide local variables 
00313   std::stack<Idx> stack;
00314   StateSet stackstates;
00315   StateSet todostates;
00316   std::map<const Idx, int> dfn;
00317   std::map<const Idx, int> lowlnk;
00318 
00319   // initialise todo list
00320   if(rFilter.Mode() & SccFilter::IgnoreUnaccessible)
00321     todostates=rGen.AccessibleSet();
00322   else
00323     todostates=rGen.States();
00324 
00325   // start recursive depth-first search for Scc's:
00326   while(!todostates.Empty()) {
00327     SearchScc(*todostates.Begin(), count, rGen, rFilter, todostates, stack, stackstates, 
00328       dfn, lowlnk,rSccList, rRoots);
00329   }
00330 
00331   // done
00332   return !rSccList.empty();
00333 }
00334 
00335 // ComputeScc(Generator, SccList, Roots)
00336 bool ComputeScc(
00337   const Generator& rGen,
00338   std::list<StateSet>& rSccList,
00339   StateSet& rRoots)
00340 {
00341   FD_DF("CompteScc(" << rGen.Name() << ") [std]");
00342 
00343   // dummy
00344   const static SccFilter msFilter = SccFilter();
00345 
00346   // doit
00347   return ComputeScc(rGen,msFilter,rSccList,rRoots);
00348 }
00349 
00350 
00351 // HasScc(Generator, Scc)
00352 bool HasScc(
00353   const Generator& rGen,
00354   const SccFilter& rFilter,
00355   StateSet& rScc)
00356 {
00357   FD_DF("HasScc(" << rGen.Name() << ")");
00358 
00359   // inititalize result
00360   rScc.Clear();
00361 
00362   // initialize counter for depthfirstnumbers:
00363   int count=1;
00364 
00365   // provide local variables 
00366   std::stack<Idx> stack;
00367   StateSet stackstates;
00368   StateSet todostates;
00369   std::map<const Idx, int> dfn;
00370   std::map<const Idx, int> lowlnk;
00371   std::list<StateSet> scclist;
00372   StateSet roots;
00373 
00374   // initialise todo list
00375   if(rFilter.Mode() & SccFilter::IgnoreUnaccessible)
00376     todostates=rGen.AccessibleSet();
00377   else
00378     todostates=rGen.States();
00379 
00380   // start recursive depth-first search for Scc's:
00381   while(!todostates.Empty()) {
00382     SearchScc(*todostates.Begin(), count, rGen, rFilter, todostates, stack, stackstates, 
00383       dfn, lowlnk, scclist, roots);
00384   }
00385 
00386   // copy (!) result
00387   if(!scclist.empty()) rScc=*scclist.begin();
00388 
00389   // done
00390   return !rScc.Empty();
00391 }
00392 
00393 // HasScc(Generator, Scc)
00394 bool HasScc(
00395   const Generator& rGen,
00396   const SccFilter& rFilter)
00397 {
00398   FD_DF("HasScc(" << rGen.Name() << ") [boolean only]");
00399 
00400   // dummy
00401   StateSet scc;
00402 
00403   // doit
00404   return HasScc(rGen,rFilter,scc);
00405 }
00406 
00407 
00408 /*
00409 
00410 // WriteStateSets(rStateSets)
00411 // Write set of StateSet's to console.
00412 void WriteStateSets(
00413   const std::set<StateSet>& rStateSets)
00414 {
00415   FD_DF("WriteStateSets()");
00416   std::cout<<std::endl;
00417   if(rStateSets.empty()) {
00418     std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl;
00419     FD_DF("WriteStateSets: Set of state sets is empty.");
00420     return;
00421   }
00422   std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl;
00423   std::set<StateSet>::iterator StateSetit = rStateSets.begin();
00424   std::set<StateSet>::iterator StateSetit_end = rStateSets.end();
00425   for (; StateSetit != StateSetit_end; ++StateSetit) {
00426     std::cout<<std::endl<<"  >> State set begin:"<< std::endl;
00427     StateSet::Iterator sit = StateSetit->Begin();
00428     StateSet::Iterator sit_end = StateSetit->End();
00429     for (; sit != sit_end; ++sit) {
00430       std::cout<<"  >> "<<*sit<<std::endl;
00431     }
00432     std::cout<<"  >> State set end."<< std::endl;
00433   }  
00434   std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl;
00435 }
00436 
00437 // WriteStateSets(rGen,rStateSets)
00438 // Write set of StateSet's to console.
00439 // Use rGen for symbolic state names
00440 void WriteStateSets(
00441   const Generator& rGen,
00442   const std::set<StateSet>& rStateSets)
00443 {
00444   FD_DF("WriteStateSets()");
00445   std::cout<<std::endl;
00446   if(rStateSets.empty()) {
00447     std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl;
00448     FD_DF("WriteStateSets: Set of state sets is empty.");
00449     return;
00450   }
00451   std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl;
00452   std::set<StateSet>::iterator StateSetit = rStateSets.begin();
00453   std::set<StateSet>::iterator StateSetit_end = rStateSets.end();
00454   for (; StateSetit != StateSetit_end; ++StateSetit) {
00455     std::cout<<std::endl<<"  >> State set begin:"<< std::endl;
00456     std::cout<<"  "<<rGen.StateSetToString(*StateSetit)<<std::endl;
00457     std::cout<<"  >> State set end."<< std::endl;
00458   }  
00459   std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl;
00460 }
00461 
00462 */
00463 
00464 }//namespace faudes
00465 

libFAUDES 2.20s --- 2011.10.12 --- c++ source docu by doxygen