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 00063 // Filter class for SCC search: constructors 00064 SccFilter::SccFilter(const SccFilter& rSrc) : 00065 mMode(rSrc.mMode), 00066 pStatesAvoid(rSrc.pStatesAvoid), 00067 pStatesRequire(rSrc.pStatesRequire), 00068 pEventsAvoid(rSrc.pEventsAvoid), 00069 mpStatesAvoid(0), 00070 mpStatesRequire(0), 00071 mpEventsAvoid(0) 00072 {} 00073 00074 00075 // Filter class for SCC search: constructors 00076 SccFilter::SccFilter(int mode, const EventSet& rEventsAvoid) : 00077 mMode(mode), 00078 pStatesAvoid(&msEmptyStates), 00079 pStatesRequire(&msEmptyStates), 00080 pEventsAvoid(&msEmptyEvents), 00081 mpStatesAvoid(0), 00082 mpStatesRequire(0), 00083 mpEventsAvoid(0) 00084 { 00085 // no special states 00086 mMode &= ~(FmStatesRequire | FmStatesAvoid); 00087 // use events for avoid 00088 mMode |= FmEventsAvoid; 00089 // record 00090 pEventsAvoid=&rEventsAvoid; 00091 } 00092 00093 00094 // Filter class for SCC search: constructors 00095 SccFilter::SccFilter(int mode, const StateSet& rStatesAvoidRequire) : 00096 mMode(mode), 00097 pStatesAvoid(&msEmptyStates), 00098 pStatesRequire(&msEmptyStates), 00099 pEventsAvoid(&msEmptyEvents), 00100 mpStatesAvoid(0), 00101 mpStatesRequire(0), 00102 mpEventsAvoid(0) 00103 { 00104 // no special events 00105 mMode &= ~FmEventsAvoid; 00106 // use states for require 00107 if(mMode & FmStatesRequire) 00108 pStatesRequire=&rStatesAvoidRequire; 00109 // use states for avoid 00110 if(mMode & FmStatesAvoid) 00111 pStatesAvoid=&rStatesAvoidRequire; 00112 } 00113 00114 // Filter class for SCC search: constructors 00115 SccFilter::SccFilter(int mode, const StateSet& rStatesAvoid, const StateSet& rStatesRequire): 00116 mMode(mode), 00117 pStatesAvoid(&msEmptyStates), 00118 pStatesRequire(&msEmptyStates), 00119 pEventsAvoid(&msEmptyEvents), 00120 mpStatesAvoid(0), 00121 mpStatesRequire(0), 00122 mpEventsAvoid(0) 00123 { 00124 // no special events 00125 mMode &= ~FmEventsAvoid; 00126 // but special states 00127 mMode |= FmStatesRequire; 00128 mMode |= FmStatesAvoid; 00129 // set internal pointers 00130 pStatesAvoid=&rStatesAvoid; 00131 pStatesRequire=&rStatesRequire; 00132 } 00133 00134 00135 // Filter class for SCC search: constructors 00136 SccFilter::SccFilter(int mode, const Generator& rGen) : 00137 mMode(mode), 00138 pStatesAvoid(&msEmptyStates), 00139 pStatesRequire(&msEmptyStates), 00140 pEventsAvoid(&msEmptyEvents), 00141 mpStatesAvoid(0), 00142 mpStatesRequire(0), 00143 mpEventsAvoid(0) 00144 { 00145 // sets all empty by default 00146 mMode &= ~(FmStatesAvoid | FmStatesRequire | FmEventsAvoid ); 00147 // ignore livelocks ==> require at least one marked state 00148 if(mode & FmIgnoreLiveLocks) { 00149 pStatesRequire=&rGen.MarkedStates(); 00150 mMode |= FmStatesRequire; 00151 } 00152 // livelocks only ==> avoid marked states 00153 if(mode & FmLiveLocksOnly) { 00154 pStatesAvoid=&rGen.MarkedStates(); 00155 mMode |= FmStatesAvoid; 00156 } 00157 // accessible only ==> deal with this in api wrappers 00158 if(mode & FmIgnoreUnaccessible) { 00159 (void) mode; 00160 } 00161 } 00162 00163 00164 // Filter class for SCC search: clear 00165 void SccFilter::Clear(void) { 00166 if(mpStatesAvoid) delete mpStatesAvoid; 00167 if(mpStatesRequire) delete mpStatesRequire; 00168 if(mpEventsAvoid) delete mpEventsAvoid; 00169 mpStatesAvoid=0; 00170 mpStatesRequire=0; 00171 mpEventsAvoid=0; 00172 mMode=0x00; 00173 pStatesAvoid=&msEmptyStates; 00174 pStatesRequire=&msEmptyStates; 00175 pEventsAvoid=&msEmptyEvents; 00176 } 00177 00178 // Filter class for SCC search: edit 00179 void SccFilter::StatesAvoid(const StateSet& rStatesAvoid) { 00180 if(mpStatesAvoid) delete mpStatesAvoid; 00181 mpStatesAvoid=0; 00182 mMode |= FmStatesAvoid; 00183 pStatesAvoid=&rStatesAvoid; 00184 } 00185 00186 // Filter class for SCC search: edit 00187 void SccFilter::StatesRequire(const StateSet& rStatesRequire) { 00188 if(mpStatesRequire) delete mpStatesRequire; 00189 mpStatesRequire=0; 00190 mMode |= FmStatesRequire; 00191 pStatesRequire=&rStatesRequire; 00192 } 00193 00194 // Filter class for SCC search: edit 00195 void SccFilter::MergeStatesAvoid(const StateSet& rStatesAvoid) { 00196 if(mpStatesAvoid==0) mpStatesAvoid= new IndexSet(*pStatesAvoid); 00197 mpStatesAvoid->InsertSet(rStatesAvoid); 00198 mpStatesAvoid->Name("StatesAvoid"); 00199 pStatesAvoid=mpStatesAvoid; 00200 } 00201 00202 // Filter class for SCC search: edit 00203 void SccFilter::EventsAvoid(const EventSet& rEventsAvoid) { 00204 if(mpEventsAvoid) delete mpEventsAvoid; 00205 mpEventsAvoid=0; 00206 mMode |= FmEventsAvoid; 00207 pEventsAvoid=&rEventsAvoid; 00208 } 00209 00210 // Filter class for SCC search: edit 00211 void SccFilter::IgnoreTrivial(bool flag) { 00212 mMode &= ~FmIgnoreTrivial; 00213 if(flag) mMode |= FmIgnoreTrivial; 00214 } 00215 00216 // Filter class for SCC search: edit 00217 void SccFilter::FindFirst(bool flag) { 00218 mMode &= ~FmFindFirst; 00219 if(flag) mMode |= FmFindFirst; 00220 } 00221 00222 00223 00224 00225 // Recursive function to search for SCCs. 00226 // The algorithm is a variation of the one prsented in 00227 // -- Aho, Hopcroft, Ullman: The Design and Analysis of Computer Algorithms 00228 void SearchScc( 00229 const Idx vState, // Current state under investigation 00230 int& vRcount, // Depth count of recursion 00231 const Generator& rGen, // Graph to inspect 00232 const SccFilter& rFilter, // Filter to ignore transitions with specified events 00233 StateSet& rTodo, // States not dealt with so far 00234 std::stack<Idx>& rStack, // Stack of currently considered states 00235 StateSet& rStackStates, // Stack contents as set 00236 std::map<const Idx, int>& rDfn, // Map assigning to each state its depth-first count 00237 std::map<const Idx, int>& rLowLnk, // Map assigning to each state its LOWLINK Number 00238 std::list<StateSet>& rSccList, // Record result: list of SCCs 00239 StateSet& rRoots) // Record result: one state per SCC 00240 { 00241 FD_DF("SerchScc: -- recursive search from state "<< vState << " at level " << vRcount << " --"); 00242 // local variables (expensive for recursion) 00243 TransSet::Iterator tit; 00244 Idx ls; 00245 bool fl; 00246 // Take current state from todo list 00247 rTodo.Erase(vState); 00248 // Ignore filter: avoid states 00249 if(rFilter.mMode & SccFilter::FmStatesAvoid) 00250 if(rFilter.pStatesAvoid->Exists(vState)) return; 00251 // Ignore filter: break recursion on find first 00252 if(rFilter.mMode & SccFilter::FmFindFirst) 00253 if(!rSccList.empty()) return; 00254 // Record depth-first level for current state and initialise low-link level 00255 rDfn[vState]=vRcount; 00256 rLowLnk[vState]=vRcount; 00257 // Increment depth-first level 00258 vRcount++; 00259 // Push state on stack; 00260 rStack.push(vState); 00261 rStackStates.Insert(vState); 00262 /* 00263 std::list<Idx>::iterator vsit = --rStack.end(); 00264 */ 00265 // Investigate successor states "L[state]" 00266 tit=rGen.TransRelBegin(vState); 00267 for(; tit != rGen.TransRelEnd(); ++tit) { 00268 if(tit->X1!=vState) break; 00269 // Sucessor to investigate 00270 ls=tit->X2; 00271 // Ignore avoid: avoid states 00272 if(rFilter.mMode & SccFilter::FmStatesAvoid) 00273 if(rFilter.pStatesAvoid->Exists(ls)) continue; 00274 // Ignore filter: avoid events 00275 if(rFilter.mMode & SccFilter::FmEventsAvoid) 00276 if(rFilter.pEventsAvoid->Exists(tit->Ev)) continue; 00277 // Successors that are on the todo list get ... 00278 if(rTodo.Exists(ls)) { 00279 // ... searched recursively, and ... 00280 SearchScc(ls, vRcount, rGen, rFilter, rTodo, rStack, rStackStates, rDfn, rLowLnk, rSccList, rRoots); 00281 // ... the current low-link gets updated to the new minimum. 00282 if(rLowLnk[ls]<rLowLnk[vState]) rLowLnk[vState]=rLowLnk[ls]; 00283 } 00284 // Successors that are not on the todo list ... 00285 else { 00286 // ... if they have a lower deph-first level ... 00287 if(rDfn[ls]<rDfn[vState]) 00288 // ... and if they are on the stack at all ... 00289 if(rStackStates.Exists(ls)) 00290 // ... set the current low-link to the new minimum 00291 if(rDfn[ls]<rLowLnk[vState]) rLowLnk[vState]=rDfn[ls]; 00292 } 00293 }//end for: iterate successors 00294 00295 // If the current state is the root of a SCC, record the result 00296 if((rLowLnk[vState]==rDfn[vState])) { 00297 // Retrieve SCC from stack 00298 FD_DF("SearchScc: retrieving SCC from stack, root " << vState); 00299 rSccList.push_back(StateSet()); 00300 rRoots.Insert(vState); 00301 do { 00302 // Pop top of stack 00303 ls=rStack.top(); 00304 rStackStates.Erase(ls); 00305 rStack.pop(); 00306 // Record 00307 rSccList.back().Insert(ls); 00308 } while(ls!=vState); 00309 // Invalidate for missed requirements 00310 fl=false; 00311 // .. required states. 00312 if(rFilter.mMode & SccFilter::FmStatesRequire) 00313 if(((*rFilter.pStatesRequire) * rSccList.back()).Empty()) 00314 fl=true; 00315 // .. ignore trivial (singleton without relevant selfloop) 00316 if(rFilter.mMode & SccFilter::FmIgnoreTrivial) { 00317 if((!fl) && (rSccList.back().Size()==1)) { 00318 fl=true; 00319 tit = rGen.TransRelBegin(vState); 00320 for(; tit != rGen.TransRelEnd(); ++tit) { 00321 if(tit->X1!=vState) break; 00322 // no self loop 00323 if(tit->X2!=vState) continue; 00324 // avoid event self loop does not qualify 00325 if(rFilter.mMode & SccFilter::FmEventsAvoid) 00326 if(rFilter.pEventsAvoid->Exists(tit->Ev)) 00327 continue; 00328 // found relevant selfloop 00329 fl=false; 00330 break; 00331 } 00332 } 00333 } 00334 // Invalidate result 00335 if(fl) { 00336 #ifdef FAUDES_DEBUG_FUNCTION 00337 FD_DF("SearchScc: invalidate scc for filter condition"); 00338 #endif 00339 rSccList.pop_back(); 00340 rRoots.Erase(vState); 00341 } 00342 } 00343 } 00344 00345 00346 // ComputeScc(Generator, SccList, Roots) 00347 bool ComputeScc( 00348 const Generator& rGen, 00349 const SccFilter& rFilter, 00350 std::list<StateSet>& rSccList, 00351 StateSet& rRoots) 00352 { 00353 FD_DF("CompteScc(" << rGen.Name() << ")"); 00354 00355 // inititalize results: 00356 rRoots.Clear(); 00357 rSccList.clear(); 00358 00359 // initialize counter for depthfirstnumbers(DFN): 00360 int count=1; 00361 00362 // provide local variables 00363 std::stack<Idx> stack; 00364 StateSet stackstates; 00365 StateSet todostates; 00366 std::map<const Idx, int> dfn; 00367 std::map<const Idx, int> lowlnk; 00368 00369 // initialise todo list 00370 if(rFilter.Mode() & SccFilter::FmIgnoreUnaccessible) 00371 todostates=rGen.AccessibleSet(); 00372 else 00373 todostates=rGen.States(); 00374 if(rFilter.Mode() & SccFilter::FmStatesAvoid) 00375 todostates = todostates - rFilter.StatesAvoid(); 00376 00377 // each recursion level keeps transition iterators 00378 rGen.TransRel().Lock(); 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,rSccList, rRoots); 00384 } 00385 00386 // done 00387 return !rSccList.empty(); 00388 } 00389 00390 // ComputeScc(Generator, SccList, Roots) 00391 bool ComputeScc( 00392 const Generator& rGen, 00393 std::list<StateSet>& rSccList, 00394 StateSet& rRoots) 00395 { 00396 FD_DF("CompteScc(" << rGen.Name() << ") [std]"); 00397 00398 // dummy 00399 const static SccFilter msFilter = SccFilter(); 00400 00401 // doit 00402 return ComputeScc(rGen,msFilter,rSccList,rRoots); 00403 } 00404 00405 00406 // ComputeScc(Generator, Filter, q0, Scc) 00407 bool ComputeScc( 00408 const Generator& rGen, 00409 const SccFilter& rFilter, 00410 Idx q0, 00411 StateSet& rScc) 00412 { 00413 FD_DF("ComputeScc(" << rGen.Name() << ")"); 00414 00415 // inititalize result 00416 rScc.Clear(); 00417 00418 // initialize counter for depthfirstnumbers: 00419 int count=1; 00420 00421 // provide local variables 00422 std::stack<Idx> stack; 00423 StateSet stackstates; 00424 StateSet todostates; 00425 std::map<const Idx, int> dfn; 00426 std::map<const Idx, int> lowlnk; 00427 std::list<StateSet> scclist; 00428 StateSet roots; 00429 00430 // initialise todo list 00431 if(rFilter.Mode() & SccFilter::FmIgnoreUnaccessible) 00432 todostates=rGen.AccessibleSet(); 00433 else 00434 todostates=rGen.States(); 00435 if(rFilter.Mode() & SccFilter::FmStatesAvoid) 00436 todostates = todostates - rFilter.StatesAvoid(); 00437 00438 // copy and edit the filter 00439 SccFilter filter(rFilter); 00440 filter.FindFirst(true); 00441 StateSet reqstate; 00442 reqstate.Insert(q0); 00443 filter.StatesRequire(reqstate); 00444 00445 // each recursion level keeps transition iterators 00446 rGen.TransRel().Lock(); 00447 00448 // start recursive depth-first search for Scc's: 00449 while(!todostates.Empty()) { 00450 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates, 00451 dfn, lowlnk, scclist, roots); 00452 } 00453 00454 // copy (!) result 00455 if(!scclist.empty()) rScc=*scclist.begin(); 00456 00457 // done 00458 return !rScc.Empty(); 00459 } 00460 00461 00462 // ComputeScc(Generator, Filter, Scc) 00463 bool ComputeScc( 00464 const Generator& rGen, 00465 const SccFilter& rFilter, 00466 StateSet& rScc) 00467 { 00468 FD_DF("ComputeScc(" << rGen.Name() << ")"); 00469 00470 // inititalize result 00471 rScc.Clear(); 00472 00473 // initialize counter for depthfirstnumbers: 00474 int count=1; 00475 00476 // provide local variables 00477 std::stack<Idx> stack; 00478 StateSet stackstates; 00479 StateSet todostates; 00480 std::map<const Idx, int> dfn; 00481 std::map<const Idx, int> lowlnk; 00482 std::list<StateSet> scclist; 00483 StateSet roots; 00484 00485 // initialise todo list 00486 if(rFilter.Mode() & SccFilter::FmIgnoreUnaccessible) 00487 todostates=rGen.AccessibleSet(); 00488 else 00489 todostates=rGen.States(); 00490 if(rFilter.Mode() & SccFilter::FmStatesAvoid) 00491 todostates = todostates - rFilter.StatesAvoid(); 00492 00493 // copy and edit the filter 00494 SccFilter filter(rFilter); 00495 filter.FindFirst(true); 00496 00497 // each recursion level keeps transition iterators 00498 rGen.TransRel().Lock(); 00499 00500 // start recursive depth-first search for Scc's: 00501 while(!todostates.Empty()) { 00502 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates, 00503 dfn, lowlnk, scclist, roots); 00504 } 00505 00506 // copy (!) result 00507 if(!scclist.empty()) rScc=*scclist.begin(); 00508 00509 // done 00510 return !rScc.Empty(); 00511 } 00512 00513 // HasScc(Generator, Filter) 00514 bool HasScc( 00515 const Generator& rGen, 00516 const SccFilter& rFilter) 00517 { 00518 FD_DF("HasScc(" << rGen.Name() << ") [boolean only]"); 00519 00520 // initialize counter for depthfirstnumbers: 00521 int count=1; 00522 00523 // provide local variables 00524 std::stack<Idx> stack; 00525 StateSet stackstates; 00526 StateSet todostates; 00527 std::map<const Idx, int> dfn; 00528 std::map<const Idx, int> lowlnk; 00529 std::list<StateSet> scclist; 00530 StateSet roots; 00531 00532 // initialise todo list 00533 if(rFilter.Mode() & SccFilter::FmIgnoreUnaccessible) 00534 todostates=rGen.AccessibleSet(); 00535 else 00536 todostates=rGen.States(); 00537 if(rFilter.Mode() & SccFilter::FmStatesAvoid) 00538 todostates = todostates - rFilter.StatesAvoid(); 00539 00540 // copy and edit the filter 00541 SccFilter filter(rFilter); 00542 filter.FindFirst(true); 00543 00544 // each recursion level keeps transition iterators 00545 rGen.TransRel().Lock(); 00546 00547 // start recursive depth-first search for Scc's: 00548 while(!todostates.Empty()) { 00549 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates, 00550 dfn, lowlnk, scclist, roots); 00551 } 00552 00553 // done 00554 return !scclist.empty(); 00555 00556 } 00557 00558 00559 // RTI wrapper 00560 bool ComputeNextScc( 00561 const Generator& rGen, 00562 SccFilter& rFilter, 00563 StateSet& rScc 00564 ) { 00565 // find first 00566 rFilter.FindFirst(true); 00567 bool res = ComputeScc(rGen,rFilter,rScc); 00568 // fix filter 00569 if(res) rFilter.MergeStatesAvoid(rScc); 00570 rFilter.FindFirst(false); 00571 // done 00572 return res; 00573 } 00574 00575 00576 00577 /* 00578 00579 // WriteStateSets(rStateSets) 00580 // Write set of StateSet's to console. 00581 void WriteStateSets( 00582 const std::set<StateSet>& rStateSets) 00583 { 00584 FD_DF("WriteStateSets()"); 00585 std::cout<<std::endl; 00586 if(rStateSets.empty()) { 00587 std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl; 00588 FD_DF("WriteStateSets: Set of state sets is empty."); 00589 return; 00590 } 00591 std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl; 00592 std::set<StateSet>::iterator StateSetit = rStateSets.begin(); 00593 std::set<StateSet>::iterator StateSetit_end = rStateSets.end(); 00594 for (; StateSetit != StateSetit_end; ++StateSetit) { 00595 std::cout<<std::endl<<" >> State set begin:"<< std::endl; 00596 StateSet::Iterator sit = StateSetit->Begin(); 00597 StateSet::Iterator sit_end = StateSetit->End(); 00598 for (; sit != sit_end; ++sit) { 00599 std::cout<<" >> "<<*sit<<std::endl; 00600 } 00601 std::cout<<" >> State set end."<< std::endl; 00602 } 00603 std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl; 00604 } 00605 00606 // WriteStateSets(rGen,rStateSets) 00607 // Write set of StateSet's to console. 00608 // Use rGen for symbolic state names 00609 void WriteStateSets( 00610 const Generator& rGen, 00611 const std::set<StateSet>& rStateSets) 00612 { 00613 FD_DF("WriteStateSets()"); 00614 std::cout<<std::endl; 00615 if(rStateSets.empty()) { 00616 std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl; 00617 FD_DF("WriteStateSets: Set of state sets is empty."); 00618 return; 00619 } 00620 std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl; 00621 std::set<StateSet>::iterator StateSetit = rStateSets.begin(); 00622 std::set<StateSet>::iterator StateSetit_end = rStateSets.end(); 00623 for (; StateSetit != StateSetit_end; ++StateSetit) { 00624 std::cout<<std::endl<<" >> State set begin:"<< std::endl; 00625 std::cout<<" "<<rGen.StateSetToString(*StateSetit)<<std::endl; 00626 std::cout<<" >> State set end."<< std::endl; 00627 } 00628 std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl; 00629 } 00630 00631 */ 00632 00633 }//namespace faudes 00634 libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |