libFAUDES

Sections

Index

graphfncts.cpp

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

libFAUDES 2.14g --- 2009-12-3 --- c++ source docu by doxygen 1.5.6