|
libFAUDES
Sections
Index
|
cfl_graphfncts.cppGo 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.18b --- 2010-12-17 --- c++ source docu by doxygen 1.6.3