cfl_bisimulation.cpp
Go to the documentation of this file.
1/** @file cfl_bisimulation.cpp Bisimulation relations
2
3 Functions to compute bisimulation relations on dynamic systems (represented
4 by non-deterministic finite automata).
5
6 The relevant algorithms are described in J.-C. Fernandez, "An implementation
7 of an efficient algorithm for bisimulation equivalence", Science of Computer
8 Programming, vol. 13, pp. 219-236, 1990.
9
10 This code was originally part of the observer plug-in (op_bisimulation.* and
11 op_partition.*). It moved in revised form to corefaudes as of libFAUDES 2.26.
12
13**/
14
15/* FAU Discrete Event Systems Library (libfaudes)
16
17 Copyright (C) 2009, Christian Breindl
18 Copyright (C) 2015, Thomas Moor
19 Exclusive copyright is granted to Klaus Schmidt
20
21 This library is free software; you can redistribute it and/or
22 modify it under the terms of the GNU Lesser General Public
23 License as published by the Free Software Foundation; either
24 version 2.1 of the License, or (at your option) any later version.
25
26 This library is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 Lesser General Public License for more details.
30
31 You should have received a copy of the GNU Lesser General Public
32 License along with this library; if not, write to the Free Software
33 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
34
35#include <cfl_bisimulation.h>
36
37#include <string>
38#include <sstream>
39#include <stack>
40
41using namespace std;
42
43//#undef FD_DF
44//#define FD_DF(a) FD_WARN(a)
45
46namespace faudes {
47
48/*
49*********************************************
50*********************************************
51
52PART 1: Partition
53
54Objects of class faudes::Pnode represent a set of states with various administration
55features for the interpretation as a node in a binary tree. Each node state set amounts
56to the disjoint union of the two child state sets, with the root of the tree holding the
57full state set of the generator under consideration. The leaves of the tree the form
58the current partition in the bisimulation algorithm.
59
60The code used to reside in the observer plug-in as a public class up to version 2.25.
61
62*********************************************
63*********************************************
64*/
65
66
67struct Pnode {
68
69 /** unique partition index */
71
72 /** Associated set of states */
73 // Revision 20150714 tmoor
74 // --- replaced faudes sets by plain STL sets for inner-loop variables
75 // [test case performance 4min-->1min]
76 // --- avoid copying STL sets by using pointers instead
77 // [test case performance 1min-->30sec]
78 // --- avoid sets altogether, use sorted STL vectors and swap rather than copy
79 // [test case performance 30min-->20sec]
80 std::vector<Idx> states;
81
82 /** number of states in this coset */
84
85 /** ref or relatives */
89
90 /** indicates whether the current partition ro is stable with respect to this block */
92
93 /** Info-map. First Idx: ev, second Idx: state q, third Idx: number q-ev-successors in this node */
94 std::vector<std::map<Idx,Idx> > infoMap;
95
96 /** flag to inicate non-empty infoMap per event (for use with alternative info-map constructs) */
97 std::vector<bool> activeEv; // <> infomap nonempty
98
99 /**
100 * write info-map to console
101 *
102 * @param event
103 * event for which the info-map shall be plotted
104 */
105 void writeInfoMap(Idx event) const {
106 cout << "Writing info-map for event " << event << endl;
107 const std::map<Idx,Idx> & pMap = infoMap[event];
108 std::map<Idx,Idx>::const_iterator mIt;
109 std::map<Idx,Idx>::const_iterator mItBegin = pMap.begin();
110 std::map<Idx,Idx>::const_iterator mItEnd = pMap.end();
111 if(mItBegin == mItEnd)
112 cout << "no entries for this event" << endl;
113 for(mIt=mItBegin; mIt != mItEnd; ++mIt)
114 cout << "state: " << (*mIt).first << " : occurrences: " << (*mIt).second << endl;
115 cout << endl;
116 };
117};
118
119
120/*
121*********************************************
122PART 2: Bisimulation
123
124The class faudes::Bisimulation is used to compute the coarsest bisimulation relation
125and to maintain relevant data structures required for the particular implementation.
126The code used to reside in the observer plug-in as a public class up to libFAUDES 2.25.
127
128*********************************************
129*/
130
131
133
134public:
135
136 /**
137 * Contructor:
138 * keep a reference to the generator and initialize the partition and the W-Tree
139 * to represent the universal equivalence relation, i.e. every two states are equivalent.
140 *
141 * @param g
142 * Original generator
143 */
144 Bisimulation(const Generator& g);
145
146 /**
147 * Destructor
148 */
149 ~Bisimulation(void);
150
151 /**
152 * Write W-tree to console
153 */
154 void writeW(void);
155
156 /**
157 * Write the set of equivalence classes to console
158 */
159 void writeRo(void);
160
161 /**
162 * Perform fixpoint iteration to obtain the coarset bisimulation relation
163 */
164 void refine(void);
165
166 /**
167 * Extract output generator that represents the resulting quotient automaton.
168 * (need to invoke refine() befor)
169 *
170 * @param rMapStateToPartition
171 * Maps each state to its equivalence class
172 * @param rGenPart
173 * Generator representing the result of the computation. Each state corresponds to an
174 * euivalence class
175 */
176 void partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart);
177
178
179 /**
180 * Extract the coarsest quasi-congruence as an STL map
181 * (need to invoke refine() befor)
182 *
183 * @param rMapStateToPartition
184 * Maps each state to its equivalence class
185 */
186 void partition(std::map<Idx,Idx>& rMapStateToPartition);
187
188 /**
189 * Extract the coarsest quasi-congruence as a list of equivalence classes.
190 * (need to invoke refine() befor)
191 *
192 * @param rPartition
193 * List of equivcalent sets ogf states
194 */
195 void partition(std::list< StateSet >& rPartition);
196
197
198private:
199
200 /**
201 * internal representation of transition relation with consecutive indexed states and events
202 // Revision 20150724 tmoor
203 // --- technically, re-indexing is equivalent to "pointers on source indicees" and
204 // buffers log-n searches [30sec -> 10sec for our testcases]
205 */
206 struct State {
207 Idx idx; // source state idx
208 vector< vector<Idx> > suc; // successors by event
209 vector< vector<Idx> > pre; // predecessors by event
210 size_t iscnt; // alternative infomap for current BSmaller [not used]
211 size_t ilcnt; // alternative infomap for current BLarger [not used]
212 };
213 vector<State> states; // vector of all states [starting with 1 -- use min-index for debugging]
214 vector<Idx> events; // vector of all events [starting with 1]
215
216
217 /**
218 * Keep reference to Automaton
219 */
221
222 /**
223 * Counter to assign a unique index to each node [debugging/cosmetic only]
224 */
226
227 /**
228 * W-tree. Contains all blocks ever created [required for destruction]
229 */
230 std::vector<Pnode*> W;
231
232 /**
233 * insert new node to W-tree (empty stateset)
234 * note: this method only cares about indexing, and initialisation of node members
235 * note: cross references are left to the caller
236 */
237 Pnode* newnode();
238
239 /**
240 * set of nodes that form current partition ro (i.e. leaves of W)
241 */
242 // Revision 20150714 tmoor
243 // --- this used to be a vector with suboptimal performance for search/delete
244 // --- todo: this could be represented by pointers per node
245 std::set<Pnode*> ro;
246
247 /**
248 * set of nodes that can possibly split classes in ro
249 */
250 std::set<Pnode*> roDividers;
251
252
253 /**
254 * compute info-maps for two cosets pSmallerPart and pLargerpart.
255 * - the current partition must be stable wrt the common parent the both parts
256 * - the smaller part and larger part info maps must be initialized empty and by parent, resp.
257 *
258 * @param node
259 * Node to provide states of pSmallerPart (call with pSmallerPart)
260 * @param pSmallerPart
261 * Child coset P1 of P with smaller number of states
262 * @param pLargerPart
263 * Child coset P2 of P with larger number of states
264 * @param ev
265 * Event
266 */
267 void computeInfoMaps(Pnode& node, Pnode* pSmallerPart, Pnode* pLargerPart, Idx ev);
268
269 /**
270 * Compute info-map for coset B
271 *
272 * @param B
273 * Coset for which the info-map is computed
274 * @param Bstates
275 * Node to provide states of B
276 * @param ev
277 * Event to use
278 * @param tb
279 * sorted vector containing all the states that have an ev-transition into coset B
280 */
281 void computeInfoMap(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb);
282
283
284 /**
285 * Alternative: compute and set info-map to state data
286 * --- this is for testing/debugging only, it did neither buy nor cost relevant performance
287 */
288 void setInfoMap(Pnode& BSmaller, Pnode& BLarger, Idx ev);
289 void invImage(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb);
290
291 /**
292 * Test wehther a state has an ev-transitions into the specified coset
293 *
294 * @param state
295 * State to be examined
296 * @param node
297 * Coset
298 * @param ev
299 * Event
300 */
301 bool stateLeadsToPartition(Idx state, Pnode& node, Idx ev);
302
303
304 /**
305 * Refine current partition with respect to coset B
306 *
307 * @param B
308 * Coset
309 */
310 void partitionClass(Pnode& B);
311
312 /**
313 * Refine current partition with respect to partition B and make use of the fact that
314 * the current partition is stable with respect to the parent coset of B (compound splitter).
315 *
316 * @param B
317 * Coset
318 */
319 void partitionSplitter(Pnode& B);
320
321
322 /**
323 * Function for recursively plotting the W-tree to console [debugging]
324 *
325 * @param node
326 * Coset
327 */
328 void writeNode(Pnode& node);
329
330};
331
332
333
334// Constructor Bisimulation(g)
336{
337 FD_DF("Bisimulation::Bisimulation(" << g.Name() << ")");
338 gen = &g;
339 nxidx=1;
340
341 // encode transition relation [effectively buffer log-n search]
342 map<Idx,Idx> smap;
343 map<Idx,Idx> emap;
344 Idx max=0;
345 events.resize(gen->Alphabet().Size()+1);
346 EventSet::Iterator eit=gen->AlphabetBegin();
347 for(; eit != gen->AlphabetEnd(); ++eit) {
348 emap[*eit]=++max;
349 events[max]=*eit;
350 }
351 max=0;
352 states.resize(gen->States().Size()+1);
353 StateSet::Iterator sit=gen->StatesBegin();
354 for(; sit != gen->StatesEnd(); ++sit) {
355 smap[*sit]=++max;
356 states[max].idx=*sit;
357 states[max].suc.resize(events.size());
358 states[max].pre.resize(events.size());
359 }
361 for(; tit != gen->TransRelEnd(); ++tit) {
362 states[smap[tit->X1]].suc[emap[tit->Ev]].push_back(smap[tit->X2]);
363 states[smap[tit->X2]].pre[emap[tit->Ev]].push_back(smap[tit->X1]);
364 }
365
366 // create universal partition holding the complete state set
367 Pnode* universe = newnode();
368 universe->pParent=NULL;
369
370 Idx st=1;
371 for(;st<states.size();++st) universe->states.push_back(st);
372 universe->nsize = universe->states.size();
373
374 // add universal Partition to ro and roDividers (all equivalence classes are potential dividers)
375 ro.insert(universe);
376 roDividers.insert(universe);
377
378 // this partition is too coarse ... it needs refinement
379 FD_DF("Bisimulation::Bisimulation: leaving function");
380}
381
382// destruct
384{
385 vector<Pnode*>::iterator wit=W.begin();
386 vector<Pnode*>::iterator wit_end=W.end();
387 for(;wit!=wit_end;++wit) delete *wit;
388
389}
390
391// maintain W-tree: new node
393 Pnode* nn= new Pnode();
394 nn->rostable=false;
395 nn->nsize=0;
396 nn->pFirstChild=NULL;
397 nn->pSecondChild=NULL;
398 nn->index=nxidx;
399 nn->infoMap.resize(events.size());
400 nn->activeEv.resize(events.size());
401 nxidx++;
402 W.push_back(nn);
403 return nn;
404}
405
406
407// Bisimulation::partitionSplitter(B)
408// Revision tmoor 20150714
409// -- gprof indicated that most time is spend in this function; not quite sure whether this is acurate
410// -- circumvented excessive set-look up "W[index]"
411// -- using stl set for current partition "ro" to improve performance when deleting a cell
413
414 FD_DF("Bisimulation::partitionSplitter(B)");
415 FD_DF("Bisimulation::partitionSplitter: index of current coset is " << B.index);
416
417 // it is ensured by the calling function that the passed coset B has a parent coset B' and
418 // that ro is stable with respect to B'. Therefore, the info-maps for the parent coset B' already exist.
419
420 // pointer to parent coset
421 Pnode* BParent = B.pParent;
422
423 // Choose the coset with fewer states among B and its brother coset and let pSmallerPart point to it
424 Pnode* BSmallerPart=BParent->pFirstChild;
425 Pnode* BLargerPart=BParent->pSecondChild;
426 if(BSmallerPart->nsize > BLargerPart->nsize) {
427 BSmallerPart=BParent->pSecondChild;
428 BLargerPart=BParent->pFirstChild;
429 }
430
431 FD_DF("Bisimulation::partitionSplitter: the smaller coset (chosen) has index: " << BSmallerPart->index);
432 FD_DF("Bisimulation::partitionSplitter: the larger coset has index: " << BLargerPart->index);
433
434 // Iterators for loop over states
435 vector<Idx>::iterator sit;
436 vector<Idx>::iterator sit_end;
437
438 // stack of cells to process
439 stack<Pnode*> toDo;
440
441 //loop over all events
442 size_t ev=1;
443 for(; ev < events.size(); ++ev){
444
445 // the current event only has to be processed if there are transitions with ev to states in the
446 // parent coset, i.e., there is an entry for ev in the infoMap of BParent
447 if(!BParent->activeEv[ev]) continue;
448 FD_DF("Bisimulation::partitionSplitter: partitioning for event " << gen->EventName(events[ev]));
449
450 // initialize info-map for current event of larger child coset with
451 // a copy of the info-map of the current event of the parent coset
452 BLargerPart->infoMap[ev]= BParent->infoMap[ev];
453 // initialize info-map for current event of smaller child coset with an empty info-map
454 BSmallerPart->infoMap[ev].clear();
455 // compute the info maps for current event for smaller child cosets
456 computeInfoMaps(*(BSmallerPart), BSmallerPart, BLargerPart, ev);
457
458
459
460 //debugging / performance: alternative --- almost no difference in performance
461 /*
462 set<Idx> tb;
463 computeInfoMap(*BSmallerPart,*BSmallerPart,ev,tb);
464 computeInfoMap(*BLargerPart,*BLargerPart,ev,tb);
465 */
466
467
468 // alternative current info map
469 // setInfoMap(*BSmallerPart, *BLargerPart, ev);
470
471 // figure cosets in ro that are completely contained in T_{ev}^{-1}{B}
472 // note: since ro is stable w.r.t BParent, either all or no states of a ro-class have a successor in BParent
473 FD_DF("Bisimulation::partitionSplitter: computing predecessor cosets of parent coset with index " << BParent->index);
474 set<Pnode*>::iterator rit;
475 for(rit=ro.begin(); rit!=ro.end(); ++rit) {
476 // skip singletons
477 if((*rit)->nsize==1) continue;
478 // choose an arbitrary state from the current coset
479 Idx testState = *((*rit)->states.begin());
480 FD_DF("Bisimulation::partitionSplitter: candidate coset index " << (*rit)->index << " and test state " << gen->SStr(testState));
481 if(stateLeadsToPartition(testState, *BParent, ev)) {
482 toDo.push(*rit);
483 FD_DF("Bisimulation::partitionSplitter: coset index " << (*rit)->index << " is predecessor for parent coset with index " << (*BParent).index << " and event = " << gen->EStr(events[ev]) << " and was pushed on toDo-stack");
484 }
485 }
486
487 // iterator to info map for parent and smaller coset with event (and opt x1) resolved
488 map<Idx, Idx> & imapParentEv = BParent->infoMap[ev];
489 map<Idx, Idx> & imapSmallerEv = BSmallerPart->infoMap[ev];
490 map<Idx, Idx>::const_iterator imapParentEvX1;
491 map<Idx, Idx>::const_iterator imapSmallerEvX1;
492
493
494 // split all cosets on the toDo-stack using the info-maps. This process is described in Equation (2) of
495 // J.-C. Fernandez, “An implementation of an efficient algorithm for bisimulation equivalence,”
496 // Science of Computer Programming, vol. 13, pp. 219-236, 1990.
497
498 // iteration over all cosets on todo-stack
499 while(!toDo.empty()){
500 // take top of the stack
501 Pnode* rop=toDo.top();
502 toDo.pop();
503 FD_DF("Bisimulation::partitionSplitter: current coset taken from todo-stack has index " << rop->index);
504
505 // prepare three empty state state sets for later insertion to W-Tree
506 vector<Idx> sX1;
507 vector<Idx> sX2;
508 vector<Idx> sX3;
509
510 // iteration over all states of current candidate coset
511 // apply rules for splitting cosets into subsets using info-maps
512 sit_end = rop->states.end();
513 for(sit=rop->states.begin(); sit!=sit_end; ++sit) {
514 if(imapSmallerEv.empty()){
515 sX2.push_back(*sit); // all sucessors in larger part
516 } else {
517 imapSmallerEvX1=imapSmallerEv.find(*sit);
518 if(imapSmallerEvX1==imapSmallerEv.end()) {
519 sX2.push_back(*sit); // all sucessors in larger part
520 } else {
521 imapParentEvX1=imapParentEv.find(*sit);
522 if(imapParentEvX1->second==imapSmallerEvX1->second)
523 sX1.push_back(*sit); // all sucessors in smaller part
524 else {
525 sX3.push_back(*sit); // sucessors in both parts
526 }
527 }
528 }
529 }
530
531 // use alternative info-map
532 /*
533 sit_end = rop->states.end();
534 for(sit=rop->states.begin(); sit!=sit_end; ++sit) {
535 State& st=states[*sit];
536 if(st.iscnt==0) { sX2->insert(*sit); continue;}
537 if(st.ilcnt==0) { sX1->insert(*sit); continue;}
538 sX3->insert(*sIt);
539 }
540 */
541
542 // sort states
543 sort(sX1.begin(), sX1.end());
544 sort(sX2.begin(), sX2.end());
545 sort(sX3.begin(), sX3.end());
546
547 // insert non empty sets to the W-Tree; W-Tree takes ownership
548 Pnode* nX1 = NULL;
549 Pnode* nX2 = NULL;
550 Pnode* nX3 = NULL;
551 if(!sX1.empty()) { nX1=newnode(); nX1->nsize=sX1.size(); nX1->states.swap(sX1); };
552 if(!sX2.empty()) { nX2=newnode(); nX2->nsize=sX2.size(); nX2->states.swap(sX2); };
553 if(!sX3.empty()) { nX3=newnode(); nX3->nsize=sX3.size(); nX3->states.swap(sX3); };
554
555 // if not more than one set is empty, no split happens
556 if((nX1!=NULL ? 1 : 0) + (nX2!=NULL ? 1 : 0) + (nX3!=NULL ? 1 : 0) <2) continue;
557
558 // any non-empty set becomes a ro-class and a roDivider
559 if(nX1!=NULL) {ro.insert(nX1); roDividers.insert(nX1);};
560 if(nX2!=NULL) {ro.insert(nX2); roDividers.insert(nX2);};
561 if(nX3!=NULL) {ro.insert(nX3); roDividers.insert(nX3);};
562
563 // current split ro-class does not belong to ro anymore
564 ro.erase(rop);
565 roDividers.erase(rop);
566
567 // states of split ro-class coset are no longer needed as they will be represented by childs
568 // rop->states=vector<Idx>()
569
570 // info-map of the split coset's parent coset can be deleted if it is no longer needed
571 if(rop->pParent!=NULL && rop->pParent != BParent)
572 if(rop->pParent->pFirstChild->pFirstChild!=NULL && rop->pParent->pSecondChild->pSecondChild!=NULL) {
573 rop->pParent->infoMap.clear();
574 rop->pParent->states=vector<Idx>();
575 }
576
577 // update W-tree structure (set cross references)
578 switch( (nX1!=NULL ? 1 : 0) + (nX2!=NULL ? 2 : 0) + (nX3!=NULL ? 4 : 0) ) {
579 case 0: // not possible
580 case 1: // not possible
581 case 2: // not possible
582 case 4: // not possible
583 break;
584
585 case 3: //X1 and X2 are not empty
586 FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1 and X2");
587 rop->pFirstChild=nX1;
588 rop->pSecondChild=nX2;
589 nX2->pParent=rop;
590 nX1->pParent=rop;
591 break;
592
593 case 5: //X1 and X3 are not empty
594 FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1 and X3");
595 rop->pFirstChild=nX1;
596 rop->pSecondChild=nX3;
597 nX3->pParent=rop;
598 nX1->pParent=rop;
599 break;
600
601 case 6: //X2 and X3 are not empty
602 FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X2 and X3");
603 rop->pFirstChild=nX2;
604 rop->pSecondChild=nX3;
605 nX3->pParent=rop;
606 nX2->pParent=rop;
607 break;
608
609 case 7: //X1 and X2 and X3 are not empty
610 FD_DF("Bisimulation::partitionSplitter: coset " << rop->index << " has been split into cosets X1, X2 and X3");
611 // have one extra node parent of 2 and 3
612 Pnode* nX23=newnode();
613 std::set_union(nX2->states.begin(), nX2->states.end(), nX3->states.begin(), nX3->states.end(),
614 std::inserter(nX23->states, nX23->states.begin()));
615 // set references
616 rop->pFirstChild=nX1;
617 rop->pSecondChild=nX23;
618 nX1->pParent=rop;
619 nX23->pParent=rop;
620 nX23->pFirstChild=nX2;
621 nX23->pSecondChild=nX3;
622 nX2->pParent=nX23;
623 nX3->pParent=nX23;
624 nX23->nsize=nX2->nsize + nX3->nsize;
625 break;
626
627 } //end switch-case
628
629 } // end iteration over todo-stack
630 }
631
632 // infoMap of parent coset is now lo longer needed and can be deleted (the information has been transferred to the children cosets)
633 BParent->infoMap.clear();
634 BParent->states=vector<Idx>();
635
636 // ro is now stable with respect to the larger and smaller child cosets
637 BSmallerPart->rostable=true;
638 BLargerPart->rostable=true;
639
640 // delete the stateSets of the smaller and larger child cosets since they are no ro-deviders anymore
641 if(BSmallerPart->pFirstChild != NULL) BSmallerPart->states=vector<Idx>();
642 if(BLargerPart->pFirstChild != NULL) BLargerPart->states=vector<Idx>();
643
644 // if smaller and larger partitions were in roDividers, then they now have to be deleted from this vector
645 roDividers.erase(BSmallerPart);
646 roDividers.erase(BLargerPart);
647
648 FD_DF("Bisimulation::partitionSplitter: leaving function");
649}
650
651// Bisimulation::computeInfoMaps(node, pSmallerPart, pLargerPart, ev)
652// compute info-maps for smaller and larger part with target states provided by node, first call with node=smaller
653// assume that smaller is inititialized with zero and larger is initialized with parent map
654void Bisimulation::computeInfoMaps(Pnode& node, Pnode* pSmallerPart, Pnode* pLargerPart, Idx ev) {
655
656 FD_DF("Bisimulation::computeInfoMaps(" << node.index << "," << pSmallerPart->index << "," << pLargerPart->index << "," << gen->EventName(ev) << ")");
657
658 // if the target node does not hold states, ask children
659 if(node.states.empty()){
660 if(node.pFirstChild!=NULL)
661 computeInfoMaps(*(node.pFirstChild), pSmallerPart, pLargerPart, ev);
662 if(node.pSecondChild!=NULL)
663 computeInfoMaps(*(node.pSecondChild),pSmallerPart, pLargerPart, ev);
664 return;
665 }
666
667 // iterators over transitions
668 vector<Idx>::iterator tit;
669 vector<Idx>::iterator tit_end;
670
671 // info maps with resolved ev (and opt x1)
672 map<Idx,Idx>& imapLEv = pLargerPart->infoMap[ev];
673 map<Idx,Idx>& imapSEv = pSmallerPart->infoMap[ev];
674 map<Idx,Idx>::iterator imapLEvX1;
675 map<Idx,Idx>::iterator imapSEvX1;
676
677 // loop over states of target node
678 vector<Idx>::iterator xit2=node.states.begin();
679 vector<Idx>::iterator xit2_end=node.states.end();
680 for(; xit2!=xit2_end; ++xit2) {
681 // loop over transitions of target state to find predecessors
682 // Note that all states investigated are states of the smaller coset.
683 tit = states[*xit2].pre[ev].begin();
684 tit_end = states[*xit2].pre[ev].end();
685 for(; tit!=tit_end; ++tit) {
686 // record predecessor
687 Idx x1=*tit;
688 // increment number of occurrences for found predecessor in smaller part map
689 imapSEvX1=imapSEv.find(x1);
690 if(imapSEvX1!=imapSEv.end())
691 ++imapSEvX1->second;
692 else
693 imapSEv[x1]=1;
694 //decrement number of occurrences for found predecessor in larger part map
695 imapLEvX1=imapLEv.find(x1);
696 --imapLEvX1->second;
697 if(imapLEvX1->second==0) imapLEv.erase(imapLEvX1);
698 }
699 }
700
701 // counts: larger = parent -smaller (should be outside the recursion)
702 /*
703 map<Idx,Idx> & imapFEv=pLargerPart->pParent->infoMap[ev];
704 map<Idx,Idx>::iterator mit=imapFEv.begin();
705 for(;mit!=imapFEv.end();++mit){
706 Idx cnt= mit->second;
707 imapSEvX1=imapLEv.find(mit->first);
708 if(imapSEvX1!=imapLEv.end()) cnt=cnt-imapSEvX1->second;
709 if(cnt>0) imapLEv[mit->first]=cnt;
710 }
711 */
712
713 // set active flag
714 pSmallerPart->activeEv[ev]= !pSmallerPart->infoMap[ev].empty();
715 pLargerPart->activeEv[ev]= !pLargerPart->infoMap[ev].empty();
716
717 FD_DF("Bisimulation::computeInfoMaps: leaving function");
718}
719
720
721// Bisimulation::stateLeadsToPartition(state, node, ev)
722// Revision tmoor 20150715
723// --- this was in error and of low performance
725 FD_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(ev) << ")");
726
727 // if node does not hold states, ask children
728 if(node.states.empty()) {
729 if(node.pFirstChild!=NULL)
730 if(stateLeadsToPartition(state,*node.pFirstChild,ev)) return true;
731 if(node.pSecondChild!=NULL)
732 if(stateLeadsToPartition(state,*node.pSecondChild,ev)) return true;
733 return false;
734 }
735
736 // look for transition to target node
737 vector<Idx>::iterator tit = states[state].suc[ev].begin();
738 vector<Idx>::iterator tit_end = states[state].suc[ev].end();
739 for(;tit!=tit_end; ++tit) {
740 if(binary_search(node.states.begin(),node.states.end(),*tit)) return true;
741 // break; --- todo: do we need to iterate here? original code did not ...
742 }
743 return false;
744}
745
746
747/*
748// Bisimulation::stateLeadsToPartition(state, node, ev)
749// libFAUDES Version 2.25 for reference
750bool Bisimulation::stateLeadsToPartition(Idx state, Pnode& node, Idx ev)
751{
752 FD_DF("Bisimulation::stateLeadsToPartition(" << state << "," << node.index << "," << gen->EventName(ev) << ")");
753
754 bool found=false;
755 // there is a direct transition from state to a state in the coset node
756 if( node.states->find(gen->TransRelBegin(state, ev)->X2)!= node.states->end() &&
757 gen->TransRelBegin(state, ev)->X1 == state &&
758 gen->TransRelBegin(state, ev)->Ev == ev)
759 {
760 found = true;
761 }
762 // the stateset of node is stored in its children. Then, try to find a transition to any of the children cosets of node
763 if(found == false && node.pFirstChild!=NULL)
764 {
765 found=stateLeadsToPartition(state,*node.pFirstChild,ev);
766 }
767
768 if(found == false && node.pSecondChild!=NULL)
769 {
770 found=stateLeadsToPartition(state,*node.pSecondChild,ev);
771 }
772
773 FD_DF("Bisimulation::stateLeadsToPartition: leaving function");
774 return found;
775}
776*/
777
778
779
780// Bisimulation::partitionClass(B)
781// Revision tmoor 20150714
782// -- gprof indicated that most time is spend in this function; not quite sure whether this is acurate
783// -- circumvented excessive set-look up "W[index]" (this should become a vector anyway)
784// -- using stl set for current partition ro to improve performance when deleting a cell
786
787 FD_DF("Bisimulation::partitionClass(" << B.index << ")");
788 FD_DF("Bisimulation::partitionClass: index of passed coset is " << B.index);
789
790 // helpers
791 vector<Pnode*> addSet;
792 vector<Pnode*>::iterator addIt;
793 vector<Pnode*> removeSet;
794 vector<Pnode*>::iterator remIt;
795
796 FD_DV("Bisimulation::partitionClass: loop over events");
797
798 // Loop over all events
799 size_t ev=1;
800 for(; ev<events.size(); ++ev) {
801
802 FD_DF("Bisimulation::partitionClass: partitioning for event " << gen->EventName(events[ev]));
803 // compute info map for current event ev and coset B and store predecessor states in T_{ev}^{-1}(B) in tb
804 vector<Idx> tb;
805 computeInfoMap(B, B, ev, tb);
806 //invImage(B, B, ev, tb);
807
808 // if there are no predecessors for this event there will be no split
809 // --- tmoor 20150723: this clause bought us 13sec --> 6sec for testcases
810 if(!B.activeEv[ev]) continue;
811
812 // compute the cosets in ro that are split into the subsets intersec and diff by evaluating the backward reachability from states in B
813 set<Pnode*>::iterator rit;
814 for(rit = ro.begin(); rit != ro.end(); ++rit) {
815 FD_DF("Bisimulation::partitionClass: candidate coset to be split has index " << (*rit)->index);
816
817 // skip singletons
818 if((*rit)->nsize==1) continue;
819
820 // compute intersection of tb with current candidate coset
821 vector<Idx> sXinter;
822 std::set_intersection((*rit)->states.begin(), (*rit)->states.end(), tb.begin(), tb.end(),
823 std::inserter(sXinter, sXinter.begin()));
824
825 // skip on trivial intersection
826 if(sXinter.empty() || sXinter.size()==(*rit)->states.size()) continue;
827 FD_DF("Bisimulation::partitionClass: current coset with index " << (*rit)->index << " will be split");
828
829 // delete from ro and roDividers
830 roDividers.erase(*rit);
831 removeSet.push_back(*rit);
832
833 // set up new node for intersection
834 Pnode* nXinter= newnode();
835 nXinter->nsize=sXinter.size();
836 nXinter->states.swap(sXinter);
837 (*rit)->pFirstChild=nXinter;
838 nXinter->pParent=*rit;
839
840 // set up new node for difference
841 Pnode* nXdiff = newnode();
842 std::set_difference((*rit)->states.begin(), (*rit)->states.end(), nXinter->states.begin(), nXinter->states.end(),
843 std::inserter(nXdiff->states,nXdiff->states.begin()));
844 (*rit)->pSecondChild=nXdiff;
845 nXdiff->pParent=*rit;
846 nXdiff->nsize=nXdiff->states.size();
847
848 // record that the new cosets have to be added to ro and roDividers
849 addSet.push_back(nXinter);
850 addSet.push_back(nXdiff);
851 roDividers.insert(nXinter);
852 roDividers.insert(nXdiff);
853
854 // report
855 FD_DF("Bisimulation::partitionClass: the coset with index " << nXinter->index << " has been added to addSet and to roDividers");
856 FD_DF("Bisimulation::partitionClass: the coset with index " << nXdiff->index << " has been added to addSet and to roDividers");
857 FD_DF("Bisimulation::partitionClass: the candidate coset has been split");
858
859 // delete info-map of parent coset of split coset if no longer needed
860 if((*rit)->pParent!=NULL) {
861 FD_DF("Bisimulation::partitionClass: split coset has parent coset with index " << (*rit)->pParent->index);
862 if((*rit)->pParent->pFirstChild->pFirstChild!=NULL && (*rit)->pParent->pSecondChild->pSecondChild!=NULL && (*rit)->pParent->rostable) {
863 (*rit)->pParent->infoMap.clear();
864 (*rit)->pParent->states=vector<Idx>();
865 FD_DF("Bisimulation::partitionClass: info map of parent coset deleted");
866 }
867 }
868
869 // delete stateSet of split coset as the states are now stored in the child cosets
870 //(*rit)->states=vector<Idx>();
871 FD_DF("Bisimulation::partitionClass: states of split coset " << (*rit)->index << " have been deleted");
872
873 } // loop all ro classes
874
875 // delete split partitions from ro
876 FD_DF("Bisimulation::partitionClass: deleting split cosets from ro");
877 for(remIt=removeSet.begin(); remIt!=removeSet.end();++remIt)
878 ro.erase(*remIt);
879 removeSet.clear();
880
881 // insert the new cosets into ro
882 FD_DF("Bisimulation::partitionClass: inserting #" << addSet.size() <<" new cosets into ro");
883 for(addIt=addSet.begin();addIt!=addSet.end();++addIt)
884 ro.insert(*addIt);
885 addSet.clear();
886
887 } //end loop over events
888
889
890 // ro is now stable with respect to coset B
891 B.rostable = true;
892
893 // delete coset B from roDividers
894 roDividers.erase(&B);
895
896 // delete stateSet of coset B if no longer needed
897 if(B.pFirstChild != NULL) B.states=vector<Idx>();
898
899 FD_DF("Bisimulation::partitionClass(): done");
900}
901
902// Bisimulation::computeInfoMap(B, Bstates, ev, tb)
903// compute info map for B using target states provided by Bstates, i.e., first call with Bstates=B
904void Bisimulation::computeInfoMap(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb) {
905
906 FD_DF("Bisimulation::computeInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(ev) << ", Stateset&)");
907 FD_DF("Bisimulation::computeInfoMap: consider stateSet of coset " << Bstates.index);
908
909 // if Bstates does not host states, ask children
910 if(Bstates.states.empty()) {
911 if(Bstates.pFirstChild!=NULL)
912 computeInfoMap(B, *(Bstates.pFirstChild), ev, tb);
913 if(Bstates.pSecondChild!=NULL)
914 computeInfoMap(B, *(Bstates.pSecondChild), ev, tb);
915 return;
916 }
917
918 // iterators over predecessors
919 vector< Idx >::iterator tit;
920 vector< Idx >::iterator tit_end;
921
922 // info map with ev (and opt x1) resolved
923 map<Idx, Idx>& imapBEv = B.infoMap[ev];
924 map<Idx, Idx>::iterator imapBEvX1;
925
926 // loop over all states of current partition B
927 vector<Idx>::iterator xit2 = Bstates.states.begin();
928 vector<Idx>::iterator xit2_end = Bstates.states.end();
929 for(; xit2 != xit2_end; ++ xit2){
930 // loop over all transitions to current target state
931 tit=states[*xit2].pre[ev].begin();
932 tit_end=states[*xit2].pre[ev].end();
933 for(; tit < tit_end; ++tit) {
934 // record precessor
935 Idx x1=*tit;
936 tb.push_back(x1);
937 // increase number of occurrences for found predecessor state in info-map
938 imapBEvX1=imapBEv.find(x1);
939 if(imapBEvX1!=imapBEv.end()) ++imapBEvX1->second;
940 else imapBEv[x1]=1;
941 }
942 }
943 // sort states
944 sort(tb.begin(),tb.end());
945
946 B.activeEv[ev]= !tb.empty();
947
948 FD_DF("Bisimulation::computeInfoMap: leaving function");
949}
950
951
952// Bisimulation::setInfoMap(...)
953// set up info map for smaller and larger part
954// -- Revision 20150725: use state data structure to store current info map
955// -- this did not help performance
956void Bisimulation::setInfoMap(Pnode& BSmaller, Pnode& BLarger, Idx ev) {
957
958 //FD_DF("Bisimulation::setInfoMap(" << B.index << "," << Bstates.index << "," << gen->EventName(ev) << ", Stateset&)");
959 //FD_DF("Bisimulation::setInfoMap: consider stateSet of coset " << Bstates.index);
960
961 // clear info
962 vector<State>::iterator sit=states.begin();
963 if(sit!=states.end()) ++sit;
964 for(;sit!=states.end();++sit) {
965 sit->iscnt=0;
966 sit->ilcnt=0;
967 }
968
969 // iterators over predecessors
970 vector< Idx >::iterator tit;
971 vector< Idx >::iterator tit_end;
972 vector<Idx>::iterator xit2;
973 bool found;
974
975 // loop over all states of current partition BSmaller
976 found=false;
977 xit2 = BSmaller.states.begin();
978 for(; xit2 != BSmaller.states.end(); ++xit2) {
979 // loop over all transitions to current target state
980 tit=states[*xit2].pre[ev].begin();
981 tit_end=states[*xit2].pre[ev].end();
982 for(; tit < tit_end; ++tit) {
983 // record predecessor
984 Idx x1=*tit;
985 ++(states[x1].iscnt);
986 found=true;
987 }
988 }
989 if(found) BSmaller.activeEv[ev]=true;
990
991
992 // loop over all states of current partition BLarger
993 found=false;
994 xit2 = BLarger.states.begin();
995 for(; xit2 != BLarger.states.end(); ++xit2) {
996 // loop over all transitions to current target state
997 tit=states[*xit2].pre[ev].begin();
998 tit_end=states[*xit2].pre[ev].end();
999 for(; tit < tit_end; ++tit) {
1000 // record predecessor
1001 Idx x1=*tit;
1002 ++(states[x1].ilcnt);
1003 found=true;
1004 }
1005 }
1006 if(found) BLarger.activeEv[ev]=true;
1007
1008 FD_DF("Bisimulation::setInfoMap: leaving function");
1009}
1010
1011
1012// inverse image
1013void Bisimulation::invImage(Pnode& B, Pnode& Bstates, Idx ev, vector<Idx>& tb) {
1014
1015 // if Bstates does not host states, ask children
1016 if(Bstates.states.empty()) {
1017 if(Bstates.pFirstChild!=NULL)
1018 invImage(B, *(Bstates.pFirstChild), ev, tb);
1019 if(Bstates.pSecondChild!=NULL)
1020 invImage(B, *(Bstates.pSecondChild), ev, tb);
1021 return;
1022 }
1023
1024 // iterators over predecessors
1025 vector< Idx >::iterator tit;
1026 vector< Idx >::iterator tit_end;
1027
1028 // loop over all states of current partition B
1029 vector<Idx>::iterator xit2 = Bstates.states.begin();
1030 for(; xit2 != Bstates.states.end(); ++xit2) {
1031 // loop over all transitions to current target state
1032 tit=states[*xit2].pre[ev].begin();
1033 tit_end=states[*xit2].pre[ev].end();
1034 for(; tit < tit_end; ++tit) {
1035 // record precessor
1036 Idx x1=*tit;
1037 tb.push_back(x1);
1038 }
1039 }
1040 // sort states
1041 sort(tb.begin(),tb.end());
1042
1043 B.activeEv[ev]= !tb.empty();
1044}
1045
1046
1047// Bisimulation::refine()
1049 FD_DF("Bisimulation::refine()");
1050 //helpers
1051 set<Pnode*>::iterator roDivIt;
1052 Pnode* pParent;
1053 // start with first entry of roDividers and repeat the refinement steps performed by the functions partitionClass
1054 // and partitionSplitter as long as there are any roDividers
1055 while(!roDividers.empty()) {
1056 // be interuptable
1057 FD_WPC(ro.size()-roDividers.size(), ro.size(), "Bisimulation: blocks/dividers: " << ro.size() << " / " << roDividers.size());
1058 // find a coset that has a parent coset B' such that ro is stable w.r.t. B'
1059 // (the order in which the dividers are chosen does not matter)
1060 roDivIt=roDividers.begin();
1061 while(roDivIt != roDividers.end()) {
1062 pParent=(*roDivIt)->pParent;
1063 if(pParent == NULL) { roDivIt++; continue; };
1064 if(pParent->rostable != true) { roDivIt++; continue; };
1065 break;
1066 }
1067 // if a splitter was found, do the split
1068 if(roDivIt != roDividers.end()) {
1069 partitionSplitter(**roDivIt);
1070 continue;
1071 }
1072 // else split by class
1073 roDivIt=roDividers.begin();
1074 partitionClass(**roDivIt);
1075 }
1076}
1077
1078
1079
1080// Bisimulation::partition(rMapStateToPartition, rGenPart)
1081void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart) {
1082
1083 FD_DF("Bisimulation::partition(rMapStateToPartition," << rGenPart.Name() << ")");
1084
1085 // prepare result
1086 rGenPart.Clear();
1087 rMapStateToPartition.clear();
1088
1089 // loop over all elements of ro and create a new state for every coset in ro (ro contains the set of equivalence classes)
1090 set<Pnode*>::const_iterator cRoIt = ro.begin();
1091 set<Pnode*>::const_iterator cRoItEnd = ro.end();
1092 vector<Idx>::iterator cSIt;
1093 vector<Idx>::iterator cSItEnd;
1094 for(; cRoIt != cRoItEnd; ++cRoIt) {
1095 // have a new state
1096 std::ostringstream ostr;
1097 Idx newstate = rGenPart.InsState();
1098 FD_DF("Bisimulation::partition: new state " << newstate << " for coset "
1099 << (*cRoIt)->index );
1100
1101 // loop over all original states in current coset
1102 cSIt=(*cRoIt)->states.begin();
1103 cSItEnd=(*cRoIt)->states.end();
1104 for(; cSIt != cSItEnd; ++cSIt) {
1105 // retrieve source state idx
1106 Idx st=states[*cSIt].idx;
1107 // map every state of the original generator to its equivalence class (= state in rGenPart)
1108 // by creating an entry in the map rMapStateToPartition
1109 rMapStateToPartition[st] = newstate;
1110 // set state names for resulting generator
1111 if(rGenPart.StateNamesEnabled()) {
1112 if(gen->StateName(st)!="") ostr << gen->StateName(st) << ",";
1113 else ostr << st << ",";
1114 }
1115 // set init states
1116 if(gen->ExistsInitState(st))
1117 rGenPart.SetInitState(newstate);
1118 // set marked states
1119 if(gen->ExistsMarkedState(st))
1120 rGenPart.SetMarkedState(newstate);
1121 }
1122
1123 // set state name
1124 if(rGenPart.StateNamesEnabled()) {
1125 std::string statename = ostr.str();
1126 if(statename.length()>=1) statename.erase(statename.length()-1);
1127 statename = "{" + statename + "}";
1128 rGenPart.StateName(newstate, statename);
1129 FD_DF("Bisimulation::partition: new state " << statename);
1130 }
1131
1132 }
1133
1134 // create transition relation
1135 // iterate over all transitions of the original generator
1138 for(; tIt != tItEnd; ++tIt) {
1139 rGenPart.InsEvent(tIt->Ev); // ??
1140 rGenPart.SetTransition(rMapStateToPartition[tIt->X1], tIt->Ev, rMapStateToPartition[tIt->X2]);
1141 FD_DF("Bisimulation::partition: adding transition: X1=" << rGenPart.TStr(*tIt) );
1142 }
1143 FD_DF("Bisimulation::partition: leaving function");
1144}
1145
1146
1147
1148// Bisimulation::partition(rMapStateToPartition)
1149void Bisimulation::partition(std::map<Idx,Idx>& rMapStateToPartition) {
1150 FD_DF("Bisimulation::partition(rMapStateToPartition)");
1151
1152
1153 // prepare result
1154 rMapStateToPartition.clear();
1155
1156 // loop over all elements of ro
1157 set<Pnode*>::const_iterator cRoIt = ro.begin();
1158 set<Pnode*>::const_iterator cRoItEnd = ro.end();
1159 vector<Idx>::iterator cSIt;
1160 vector<Idx>::iterator cSItEnd;
1161 for (; cRoIt != cRoItEnd; ++cRoIt) {
1162 cSIt=(*cRoIt)->states.begin();
1163 cSItEnd=(*cRoIt)->states.end();
1164 for(; cSIt!=cSItEnd; ++ cSIt) {
1165 // map every state in the current coset to the index of this coset by creating an entry in the map rMapStateToPartition
1166 Idx st=states[*cSIt].idx;
1167 rMapStateToPartition[st] = (*cRoIt)->index; // fix: tmoor 20150712
1168 }
1169 }
1170 FD_DF("Bisimulation::partition: leaving function");
1171}
1172
1173
1174// Bisimulation::partition(rPartition)
1175void Bisimulation::partition(std::list< StateSet >& rPartition) {
1176 FD_DF("Bisimulation::partition(rPartition)");
1177
1178 // prepare result
1179 rPartition.clear();
1180
1181 // loop over all elements of ro
1182 set<Pnode*>::const_iterator cRoIt = ro.begin();
1183 for(; cRoIt != ro.end(); ++cRoIt) {
1184 if((*cRoIt)->states.size()<=1) continue;
1185 StateSet tb;
1186 vector<Idx>::iterator cSIt=(*cRoIt)->states.begin();
1187 for(; cSIt!=(*cRoIt)->states.end(); ++ cSIt) tb.Insert(states[*cSIt].idx);
1188 rPartition.push_back(tb);
1189 }
1190 FD_DF("Bisimulation::partition: leaving function");
1191}
1192
1193
1194// Bisimulation::writeW()
1196{
1197 FD_DF("Bisimulation:writeW()");
1198 cout << "Plotting the W-tree:" << endl;
1199 writeNode(**W.begin());
1200}
1201
1202// Bisimulation::writeNode(node)
1204{
1205 FD_DF("Bisimulation::writeNode(" << node.index << ")");
1206 cout << "Coset with index " << node.index << " has the following states:" << endl;
1207 vector<Idx>::iterator cSIt;
1208 vector<Idx>::iterator cSItEnd;
1209 cSIt=node.states.begin();
1210 cSItEnd=node.states.end();
1211 for(; cSIt!=cSItEnd; ++ cSIt) cout << *cSIt << " ";
1212 cout << endl;
1213 if(node.pParent!=NULL)
1214 cout << "Parent coset has index: " << node.pParent->index << endl;
1215 else
1216 cout << "Coset is the root of the tree" << endl;
1217 if(node.pParent!=NULL)
1218 if(node.pParent->pFirstChild!=NULL)
1219 if(node.index!=node.pParent->pFirstChild->index)
1220 cout << "Coset has brother coset with index: " << node.pParent->pFirstChild->index << endl;
1221 if(node.pParent!=NULL)
1222 if(node.pParent->pSecondChild!=NULL)
1223 if(node.index!=node.pParent->pSecondChild->index)
1224 cout << "Coset has brother coset with index: " << node.pParent->pSecondChild->index << endl;
1225
1226
1227 if(node.pFirstChild!=NULL && node.pSecondChild!=NULL)
1228 cout << "Child cosets have indices : " << node.pFirstChild->index << " and " << node.pSecondChild->index << endl;
1229 else
1230 cout << "Coset has no children" << endl;
1231 cout << "ro is stable with respect to this coset (1=yes; 0=no): " << node.rostable << endl;
1232 /*
1233 cout << "Info-map of coset: " << endl;
1234 EventSet::Iterator eIt;
1235 for(eIt=gen->AlphabetBegin();eIt != gen->AlphabetEnd(); ++eIt)
1236 node.writeInfoMap(*eIt);
1237
1238 if(node.pFirstChild!=NULL)
1239 writeNode(*(node.pFirstChild));
1240 if(node.pSecondChild!=NULL)
1241 writeNode(*(node.pSecondChild));
1242 */
1243}
1244
1245// Bisimulation::writeRo()
1247{
1248 FD_DF("Bisimulation::writeRo()");
1249 cout << "The Cosets with the following indices are in ro: " << endl;
1250 set<Pnode*>::iterator roIt;
1251 set<Pnode*>::iterator roItBegin =ro.begin();
1252 set<Pnode*>::iterator roItEnd = ro.end();
1253 for(roIt=roItBegin; roIt!=roItEnd; roIt++)
1254 cout << (*roIt)->index << endl;
1255 cout << endl;
1256}
1257
1258
1259
1260
1261/*
1262*********************************************
1263*********************************************
1264PART 3: application interface
1265
1266Minimal application interface based on plain functions.
1267*********************************************
1268*********************************************
1269*/
1270
1271// ComputeBisimulation(rGenOrig, rMapStateToPartition)
1272void ComputeBisimulation(const Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition)
1273{
1274 FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition)");
1275 // Construct an instance of the Bisimulation class from rGenOrig
1276 Bisimulation bisim = Bisimulation(rGenOrig);
1277 // method to compute the bisimulation on rGenOrig
1278 bisim.refine();
1279 bisim.partition(rMapStateToPartition);
1280#ifdef FAUDES_DEBUG_FUNCTION
1281 cout << "The result of the partition refinement is:" << endl;
1282 bisim.writeW();
1283 bisim.writeRo();
1284#endif
1285 FD_DF("ComputeBisimulation: leaving function");
1286}
1287
1288// ComputeBisimulation(rGenOrig, rMapStateToPartition, rGenPart)
1289void ComputeBisimulation(const Generator& rGenOrig, map<Idx,Idx>& rMapStateToPartition, Generator& rGenPart)
1290{
1291 FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rMapStateToPartition, " << rGenPart.Name() << ")");
1292 // Construct an instance of the Bisimulation class from rGenOrig
1293 Bisimulation bisim = Bisimulation(rGenOrig);
1294 // method to compute the bisimulation on rGenOrig
1295 bisim.refine();
1296 bisim.partition(rMapStateToPartition, rGenPart);
1297#ifdef FD_DF_PLOT
1298 cout << "The result of the partition refinement is:" << endl;
1299 bisim.writeW();
1300 bisim.writeRo();
1301#endif
1302 FD_DF("ComputeBisimulation: leaving function");
1303}
1304
1305// ComputeBisimulation(rGenOrig, rPartition)
1306void ComputeBisimulation(const Generator& rGenOrig, std::list< StateSet >& rPartition)
1307{
1308 FD_DF("ComputeBisimulation(" << rGenOrig.Name() << ", rPartition)");
1309 // Construct an instance of the Bisimulation class from rGenOrig
1310 Bisimulation bisim = Bisimulation(rGenOrig);
1311 // method to compute the bisimulation on rGenOrig
1312 bisim.refine();
1313 bisim.partition(rPartition);
1314#ifdef FD_DF_PLOT
1315 cout << "The result of the partition refinement is:" << endl;
1316 bisim.writeW();
1317 bisim.writeRo();
1318#endif
1319 FD_DF("ComputeBisimulation: leaving function");
1320}
1321
1322
1323
1324}
#define FD_WPC(cntnow, contdone, message)
#define FD_DV(message)
#define FD_DF(message)
void partitionClass(Pnode &B)
void computeInfoMap(Pnode &B, Pnode &Bstates, Idx ev, vector< Idx > &tb)
std::set< Pnode * > roDividers
void partition(std::map< Idx, Idx > &rMapStateToPartition, Generator &rGenPart)
void invImage(Pnode &B, Pnode &Bstates, Idx ev, vector< Idx > &tb)
std::set< Pnode * > ro
bool stateLeadsToPartition(Idx state, Pnode &node, Idx ev)
void computeInfoMaps(Pnode &node, Pnode *pSmallerPart, Pnode *pLargerPart, Idx ev)
Bisimulation(const Generator &g)
void writeNode(Pnode &node)
std::vector< Pnode * > W
void partitionSplitter(Pnode &B)
void setInfoMap(Pnode &BSmaller, Pnode &BLarger, Idx ev)
const std::string & Name(void) const
StateSet::Iterator StatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const EventSet & Alphabet(void) const
TransSet::Iterator TransRelBegin(void) const
EventSet::Iterator AlphabetBegin(void) const
void SetInitState(Idx index)
std::string TStr(const Transition &rTrans) const
std::string StateName(Idx index) const
StateSet::Iterator StatesEnd(void) const
TransSet::Iterator TransRelEnd(void) const
std::string EStr(Idx index) const
void SetMarkedState(Idx index)
bool StateNamesEnabled(void) const
bool InsEvent(Idx index)
std::string EventName(Idx index) const
EventSet::Iterator AlphabetEnd(void) const
bool ExistsInitState(Idx index) const
std::string SStr(Idx index) const
virtual void Clear(void)
bool ExistsMarkedState(Idx index) const
const StateSet & States(void) const
Idx Size(void) const
void ComputeBisimulation(const Generator &rGenOrig, map< Idx, Idx > &rMapStateToPartition)
uint32_t Idx
vector< vector< Idx > > pre
vector< vector< Idx > > suc
void writeInfoMap(Idx event) const
std::vector< bool > activeEv
std::vector< std::map< Idx, Idx > > infoMap
std::vector< Idx > states

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