| |
libFAUDES
Sections
Index
|
graphfncts.cppGo 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