cfl_graphfncts.cpp
Go to the documentation of this file.
1/** @file cfl_graphfncts.cpp Operations on (directed) graphs. */
2
3/* FAU Discrete Event Systems Library (libfaudes)
4
5 Copyright (C) 2009 Thomas Moor, Klaus Schmidt, Sebastian Perk
6 Exclusive copyright is granted to Klaus Schmidt
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21
22
23#include "cfl_graphfncts.h"
24
25
26namespace faudes {
27
28/*
29**********************************************************************
30**********************************************************************
31**********************************************************************
32
33Search for strongly connected ycless components (SCC)
34
35**********************************************************************
36**********************************************************************
37**********************************************************************
38*/
39
40// Filter class for SCC search: statics
43
44// Filter class for SCC search: destructor
50
51// Filter class for SCC search: constructors
53 mMode(0x00),
54 pStatesAvoid(&msEmptyStates),
55 pStatesRequire(&msEmptyStates),
56 pEventsAvoid(&msEmptyEvents),
57 mpStatesAvoid(0),
58 mpStatesRequire(0),
59 mpEventsAvoid(0)
60{}
61
62
63// Filter class for SCC search: constructors
65 mMode(rSrc.mMode),
66 pStatesAvoid(rSrc.pStatesAvoid),
67 pStatesRequire(rSrc.pStatesRequire),
68 pEventsAvoid(rSrc.pEventsAvoid),
69 mpStatesAvoid(0),
70 mpStatesRequire(0),
71 mpEventsAvoid(0)
72{}
73
74
75// Filter class for SCC search: constructors
76SccFilter::SccFilter(int mode, const EventSet& rEventsAvoid) :
77 mMode(mode),
78 pStatesAvoid(&msEmptyStates),
79 pStatesRequire(&msEmptyStates),
80 pEventsAvoid(&msEmptyEvents),
81 mpStatesAvoid(0),
82 mpStatesRequire(0),
83 mpEventsAvoid(0)
84{
85 // no special states
87 // use events for avoid
89 // record
90 pEventsAvoid=&rEventsAvoid;
91}
92
93
94// Filter class for SCC search: constructors
95SccFilter::SccFilter(int mode, const StateSet& rStatesAvoidRequire) :
96 mMode(mode),
97 pStatesAvoid(&msEmptyStates),
98 pStatesRequire(&msEmptyStates),
99 pEventsAvoid(&msEmptyEvents),
100 mpStatesAvoid(0),
101 mpStatesRequire(0),
102 mpEventsAvoid(0)
103{
104 // no special events
105 mMode &= ~FmEventsAvoid;
106 // use states for require
108 pStatesRequire=&rStatesAvoidRequire;
109 // use states for avoid
110 if(mMode & FmStatesAvoid)
111 pStatesAvoid=&rStatesAvoidRequire;
112}
113
114// Filter class for SCC search: constructors
115SccFilter::SccFilter(int mode, const StateSet& rStatesAvoid, const StateSet& rStatesRequire):
116 mMode(mode),
117 pStatesAvoid(&msEmptyStates),
118 pStatesRequire(&msEmptyStates),
119 pEventsAvoid(&msEmptyEvents),
120 mpStatesAvoid(0),
121 mpStatesRequire(0),
122 mpEventsAvoid(0)
123{
124 // no special events
125 mMode &= ~FmEventsAvoid;
126 // but special states
129 // set internal pointers
130 pStatesAvoid=&rStatesAvoid;
131 pStatesRequire=&rStatesRequire;
132}
133
134
135// Filter class for SCC search: constructors
136SccFilter::SccFilter(int mode, const Generator& rGen) :
137 mMode(mode),
138 pStatesAvoid(&msEmptyStates),
139 pStatesRequire(&msEmptyStates),
140 pEventsAvoid(&msEmptyEvents),
141 mpStatesAvoid(0),
142 mpStatesRequire(0),
143 mpEventsAvoid(0)
144{
145 // sets all empty by default
147 // ignore livelocks ==> require at least one marked state
148 if(mode & FmIgnoreLiveLocks) {
151 }
152 // livelocks only ==> avoid marked states
153 if(mode & FmLiveLocksOnly) {
156 }
157 // accessible only ==> deal with this in api wrappers
158 if(mode & FmIgnoreUnaccessible) {
159 (void) mode;
160 }
161}
162
163
164// Filter class for SCC search: clear
177
178// Filter class for SCC search: edit
179void SccFilter::StatesAvoid(const StateSet& rStatesAvoid) {
180 if(mpStatesAvoid) delete mpStatesAvoid;
183 pStatesAvoid=&rStatesAvoid;
184}
185
186// Filter class for SCC search: edit
187void SccFilter::StatesRequire(const StateSet& rStatesRequire) {
191 pStatesRequire=&rStatesRequire;
192}
193
194// Filter class for SCC search: edit
195void SccFilter::MergeStatesAvoid(const StateSet& rStatesAvoid) {
197 mpStatesAvoid->InsertSet(rStatesAvoid);
198 mpStatesAvoid->Name("StatesAvoid");
200}
201
202// Filter class for SCC search: edit
203void SccFilter::EventsAvoid(const EventSet& rEventsAvoid) {
204 if(mpEventsAvoid) delete mpEventsAvoid;
207 pEventsAvoid=&rEventsAvoid;
208}
209
210// Filter class for SCC search: edit
212 mMode &= ~FmIgnoreTrivial;
213 if(flag) mMode |= FmIgnoreTrivial;
214}
215
216// Filter class for SCC search: edit
217void SccFilter::FindFirst(bool flag) {
218 mMode &= ~FmFindFirst;
219 if(flag) mMode |= FmFindFirst;
220}
221
222
223
224
225// Recursive function to search for SCCs.
226// The algorithm is a variation of the one prsented in
227// -- Aho, Hopcroft, Ullman: The Design and Analysis of Computer Algorithms
229 const Idx vState, // Current state under investigation
230 int& vRcount, // Depth count of recursion
231 const Generator& rGen, // Graph to inspect
232 const SccFilter& rFilter, // Filter to ignore transitions with specified events
233 StateSet& rTodo, // States not dealt with so far
234 std::stack<Idx>& rStack, // Stack of currently considered states
235 StateSet& rStackStates, // Stack contents as set
236 std::map<const Idx, int>& rDfn, // Map assigning to each state its depth-first count
237 std::map<const Idx, int>& rLowLnk, // Map assigning to each state its LOWLINK Number
238 std::list<StateSet>& rSccList, // Record result: list of SCCs
239 StateSet& rRoots) // Record result: one state per SCC
240{
241 FD_DF("SerchScc: -- recursive search from state "<< vState << " at level " << vRcount << " --");
242 // local variables (expensive for recursion)
244 Idx ls;
245 bool fl;
246 // Take current state from todo list
247 rTodo.Erase(vState);
248 // Ignore filter: avoid states
249 if(rFilter.mMode & SccFilter::FmStatesAvoid)
250 if(rFilter.pStatesAvoid->Exists(vState)) return;
251 // Ignore filter: break recursion on find first
252 if(rFilter.mMode & SccFilter::FmFindFirst)
253 if(!rSccList.empty()) return;
254 // Record depth-first level for current state and initialise low-link level
255 rDfn[vState]=vRcount;
256 rLowLnk[vState]=vRcount;
257 // Increment depth-first level
258 vRcount++;
259 // Push state on stack;
260 rStack.push(vState);
261 rStackStates.Insert(vState);
262 /*
263 std::list<Idx>::iterator vsit = --rStack.end();
264 */
265 // Investigate successor states "L[state]"
266 tit=rGen.TransRelBegin(vState);
267 for(; tit != rGen.TransRelEnd(); ++tit) {
268 if(tit->X1!=vState) break;
269 // Sucessor to investigate
270 ls=tit->X2;
271 // Ignore avoid: avoid states
272 if(rFilter.mMode & SccFilter::FmStatesAvoid)
273 if(rFilter.pStatesAvoid->Exists(ls)) continue;
274 // Ignore filter: avoid events
275 if(rFilter.mMode & SccFilter::FmEventsAvoid)
276 if(rFilter.pEventsAvoid->Exists(tit->Ev)) continue;
277 // Successors that are on the todo list get ...
278 if(rTodo.Exists(ls)) {
279 // ... searched recursively, and ...
280 SearchScc(ls, vRcount, rGen, rFilter, rTodo, rStack, rStackStates, rDfn, rLowLnk, rSccList, rRoots);
281 // ... the current low-link gets updated to the new minimum.
282 if(rLowLnk[ls]<rLowLnk[vState]) rLowLnk[vState]=rLowLnk[ls];
283 }
284 // Successors that are not on the todo list ...
285 else {
286 // ... if they have a lower deph-first level ...
287 if(rDfn[ls]<rDfn[vState])
288 // ... and if they are on the stack at all ...
289 if(rStackStates.Exists(ls))
290 // ... set the current low-link to the new minimum
291 if(rDfn[ls]<rLowLnk[vState]) rLowLnk[vState]=rDfn[ls];
292 }
293 }//end for: iterate successors
294
295 // If the current state is the root of a SCC, record the result
296 if(rLowLnk[vState]==rDfn[vState]) {
297 // Retrieve SCC from stack
298 FD_DF("SearchScc: retrieving SCC from stack, root " << vState);
299 rSccList.push_back(StateSet());
300 rRoots.Insert(vState);
301 do {
302 // Pop top of stack
303 ls=rStack.top();
304 rStackStates.Erase(ls);
305 rStack.pop();
306 // Record
307 rSccList.back().Insert(ls);
308 } while(ls!=vState);
309 // Invalidate for missed requirements
310 fl=false;
311 // .. required states.
313 if(((*rFilter.pStatesRequire) * rSccList.back()).Empty())
314 fl=true;
315 // .. ignore trivial (singleton without relevant selfloop)
316 if(rFilter.mMode & SccFilter::FmIgnoreTrivial) {
317 if((!fl) && (rSccList.back().Size()==1)) {
318 fl=true;
319 tit = rGen.TransRelBegin(vState);
320 for(; tit != rGen.TransRelEnd(); ++tit) {
321 if(tit->X1!=vState) break;
322 // no self loop
323 if(tit->X2!=vState) continue;
324 // avoid event self loop does not qualify
325 if(rFilter.mMode & SccFilter::FmEventsAvoid)
326 if(rFilter.pEventsAvoid->Exists(tit->Ev))
327 continue;
328 // found relevant selfloop
329 fl=false;
330 break;
331 }
332 }
333 }
334 // Invalidate result
335 if(fl) {
336#ifdef FAUDES_DEBUG_FUNCTION
337 FD_DF("SearchScc: invalidate scc for filter condition");
338#endif
339 rSccList.pop_back();
340 rRoots.Erase(vState);
341 }
342 }
343}
344
345
346// ComputeScc(Generator, SccList, Roots)
348 const Generator& rGen,
349 const SccFilter& rFilter,
350 std::list<StateSet>& rSccList,
351 StateSet& rRoots)
352{
353 FD_DF("CompteScc(" << rGen.Name() << ")");
354
355 // inititalize results:
356 rRoots.Clear();
357 rSccList.clear();
358
359 // initialize counter for depthfirstnumbers(DFN):
360 int count=1;
361
362 // provide local variables
363 std::stack<Idx> stack;
364 StateSet stackstates;
365 StateSet todostates;
366 std::map<const Idx, int> dfn;
367 std::map<const Idx, int> lowlnk;
368
369 // initialise todo list
371 todostates=rGen.AccessibleSet();
372 else
373 todostates=rGen.States();
374 if(rFilter.Mode() & SccFilter::FmStatesAvoid)
375 todostates = todostates - rFilter.StatesAvoid();
376
377 // each recursion level keeps transition iterators
378 rGen.TransRel().Lock();
379
380 // start recursive depth-first search for Scc's:
381 while(!todostates.Empty()) {
382 SearchScc(*todostates.Begin(), count, rGen, rFilter, todostates, stack, stackstates,
383 dfn, lowlnk,rSccList, rRoots);
384 }
385
386 // done
387 return !rSccList.empty();
388}
389
390// ComputeScc(Generator, SccList, Roots)
392 const Generator& rGen,
393 std::list<StateSet>& rSccList,
394 StateSet& rRoots)
395{
396 FD_DF("CompteScc(" << rGen.Name() << ") [std]");
397
398 // dummy
399 const static SccFilter msFilter = SccFilter();
400
401 // doit
402 return ComputeScc(rGen,msFilter,rSccList,rRoots);
403}
404
405
406// ComputeScc(Generator, Filter, q0, Scc)
408 const Generator& rGen,
409 const SccFilter& rFilter,
410 Idx q0,
411 StateSet& rScc)
412{
413 FD_DF("ComputeScc(" << rGen.Name() << ")");
414
415 // inititalize result
416 rScc.Clear();
417
418 // initialize counter for depthfirstnumbers:
419 int count=1;
420
421 // provide local variables
422 std::stack<Idx> stack;
423 StateSet stackstates;
424 StateSet todostates;
425 std::map<const Idx, int> dfn;
426 std::map<const Idx, int> lowlnk;
427 std::list<StateSet> scclist;
428 StateSet roots;
429
430 // initialise todo list
432 todostates=rGen.AccessibleSet();
433 else
434 todostates=rGen.States();
435 if(rFilter.Mode() & SccFilter::FmStatesAvoid)
436 todostates = todostates - rFilter.StatesAvoid();
437
438 // copy and edit the filter
439 SccFilter filter(rFilter);
440 filter.FindFirst(true);
441 StateSet reqstate;
442 reqstate.Insert(q0);
443 filter.StatesRequire(reqstate);
444
445 // each recursion level keeps transition iterators
446 rGen.TransRel().Lock();
447
448 // start recursive depth-first search for Scc's:
449 while(!todostates.Empty()) {
450 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates,
451 dfn, lowlnk, scclist, roots);
452 }
453
454 // copy (!) result
455 if(!scclist.empty()) rScc=*scclist.begin();
456
457 // done
458 return !rScc.Empty();
459}
460
461
462// ComputeScc(Generator, Filter, Scc)
464 const Generator& rGen,
465 const SccFilter& rFilter,
466 StateSet& rScc)
467{
468 FD_DF("ComputeScc(" << rGen.Name() << ")");
469
470 // inititalize result
471 rScc.Clear();
472
473 // initialize counter for depthfirstnumbers:
474 int count=1;
475
476 // provide local variables
477 std::stack<Idx> stack;
478 StateSet stackstates;
479 StateSet todostates;
480 std::map<const Idx, int> dfn;
481 std::map<const Idx, int> lowlnk;
482 std::list<StateSet> scclist;
483 StateSet roots;
484
485 // initialise todo list
487 todostates=rGen.AccessibleSet();
488 else
489 todostates=rGen.States();
490 if(rFilter.Mode() & SccFilter::FmStatesAvoid)
491 todostates = todostates - rFilter.StatesAvoid();
492
493 // copy and edit the filter
494 SccFilter filter(rFilter);
495 filter.FindFirst(true);
496
497 // each recursion level keeps transition iterators
498 rGen.TransRel().Lock();
499
500 // start recursive depth-first search for Scc's:
501 while(!todostates.Empty()) {
502 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates,
503 dfn, lowlnk, scclist, roots);
504 }
505
506 // copy (!) result
507 if(!scclist.empty()) rScc=*scclist.begin();
508
509 // done
510 return !rScc.Empty();
511}
512
513// HasScc(Generator, Filter)
515 const Generator& rGen,
516 const SccFilter& rFilter)
517{
518 FD_DF("HasScc(" << rGen.Name() << ") [boolean only]");
519
520 // initialize counter for depthfirstnumbers:
521 int count=1;
522
523 // provide local variables
524 std::stack<Idx> stack;
525 StateSet stackstates;
526 StateSet todostates;
527 std::map<const Idx, int> dfn;
528 std::map<const Idx, int> lowlnk;
529 std::list<StateSet> scclist;
530 StateSet roots;
531
532 // initialise todo list
534 todostates=rGen.AccessibleSet();
535 else
536 todostates=rGen.States();
537 if(rFilter.Mode() & SccFilter::FmStatesAvoid)
538 todostates = todostates - rFilter.StatesAvoid();
539
540 // copy and edit the filter
541 SccFilter filter(rFilter);
542 filter.FindFirst(true);
543
544 // each recursion level keeps transition iterators
545 rGen.TransRel().Lock();
546
547 // start recursive depth-first search for Scc's:
548 while(!todostates.Empty()) {
549 SearchScc(*todostates.Begin(), count, rGen, filter, todostates, stack, stackstates,
550 dfn, lowlnk, scclist, roots);
551 }
552
553 // done
554 return !scclist.empty();
555
556}
557
558
559// RTI wrapper
561 const Generator& rGen,
562 SccFilter& rFilter,
563 StateSet& rScc
564) {
565 // find first
566 rFilter.FindFirst(true);
567 bool res = ComputeScc(rGen,rFilter,rScc);
568 // fix filter
569 if(res) rFilter.MergeStatesAvoid(rScc);
570 rFilter.FindFirst(false);
571 // done
572 return res;
573}
574
575
576
577/*
578
579// WriteStateSets(rStateSets)
580// Write set of StateSet's to console.
581void WriteStateSets(
582 const std::set<StateSet>& rStateSets)
583{
584 FD_DF("WriteStateSets()");
585 std::cout<<std::endl;
586 if(rStateSets.empty()) {
587 std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl;
588 FD_DF("WriteStateSets: Set of state sets is empty.");
589 return;
590 }
591 std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl;
592 std::set<StateSet>::iterator StateSetit = rStateSets.begin();
593 std::set<StateSet>::iterator StateSetit_end = rStateSets.end();
594 for (; StateSetit != StateSetit_end; ++StateSetit) {
595 std::cout<<std::endl<<" >> State set begin:"<< std::endl;
596 StateSet::Iterator sit = StateSetit->Begin();
597 StateSet::Iterator sit_end = StateSetit->End();
598 for (; sit != sit_end; ++sit) {
599 std::cout<<" >> "<<*sit<<std::endl;
600 }
601 std::cout<<" >> State set end."<< std::endl;
602 }
603 std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl;
604}
605
606// WriteStateSets(rGen,rStateSets)
607// Write set of StateSet's to console.
608// Use rGen for symbolic state names
609void WriteStateSets(
610 const Generator& rGen,
611 const std::set<StateSet>& rStateSets)
612{
613 FD_DF("WriteStateSets()");
614 std::cout<<std::endl;
615 if(rStateSets.empty()) {
616 std::cout<<"WriteStateSets: Set of state sets is empty."<<std::endl;
617 FD_DF("WriteStateSets: Set of state sets is empty.");
618 return;
619 }
620 std::cout<<">WriteStateSets: Set of state sets begin:"<< std::endl;
621 std::set<StateSet>::iterator StateSetit = rStateSets.begin();
622 std::set<StateSet>::iterator StateSetit_end = rStateSets.end();
623 for (; StateSetit != StateSetit_end; ++StateSetit) {
624 std::cout<<std::endl<<" >> State set begin:"<< std::endl;
625 std::cout<<" "<<rGen.StateSetToString(*StateSetit)<<std::endl;
626 std::cout<<" >> State set end."<< std::endl;
627 }
628 std::cout<<std::endl<<">WriteStateSets: Set of state sets end."<<std::endl;
629}
630
631*/
632
633}//namespace faudes
634
#define FD_DF(message)
const std::string & Name(void) const
bool Exists(const Idx &rIndex) const
void EventsAvoid(const EventSet &rEventsAvoid)
static const StateSet msEmptyStates
EventSet * mpEventsAvoid
void MergeStatesAvoid(const StateSet &rStatesAvoid)
int Mode(void) const
static const EventSet msEmptyEvents
const StateSet & StatesRequire(void) const
const StateSet & StatesAvoid(void) const
StateSet * mpStatesAvoid
const EventSet * pEventsAvoid
const StateSet * pStatesAvoid
const StateSet * pStatesRequire
StateSet * mpStatesRequire
void IgnoreTrivial(bool flag)
void FindFirst(bool flag)
const TransSet & TransRel(void) const
const StateSet & MarkedStates(void) const
TransSet::Iterator TransRelBegin(void) const
StateSet AccessibleSet(void) const
TransSet::Iterator TransRelEnd(void) const
const StateSet & States(void) const
void Lock(void) const
bool Empty(void) const
bool Exists(const T &rElem) const
IndexSet StateSet
virtual void Clear(void)
virtual void InsertSet(const TBaseSet &rOtherSet)
Iterator Begin(void) const
NameSet EventSet
virtual bool Erase(const T &rElem)
bool ComputeNextScc(const Generator &rGen, SccFilter &rFilter, StateSet &rScc)
bool ComputeScc(const Generator &rGen, const SccFilter &rFilter, std::list< StateSet > &rSccList, StateSet &rRoots)
bool HasScc(const Generator &rGen, const SccFilter &rFilter)
uint32_t Idx
void SearchScc(const Idx vState, int &vRcount, const Generator &rGen, const SccFilter &rFilter, StateSet &rTodo, std::stack< Idx > &rStack, StateSet &rStackStates, std::map< const Idx, int > &rDfn, std::map< const Idx, int > &rLowLnk, std::list< StateSet > &rSccList, StateSet &rRoots)

libFAUDES 2.33k --- 2025.09.16 --- c++ api documentaion by doxygen