1 | /**CFile*********************************************************************** |
---|
2 | |
---|
3 | FileName [mcSCC.c] |
---|
4 | |
---|
5 | PackageName [mc] |
---|
6 | |
---|
7 | Synopsis [Computation of Fair Strongly Connected Components.] |
---|
8 | |
---|
9 | Description [This file contains the functions to compute the fair |
---|
10 | Strongly Connected Components (SCCs) of the state transtion graph of |
---|
11 | an FSM. Knowledge of the fair SCCs can be used to decide language |
---|
12 | emptiness. Other applications are also possible.] |
---|
13 | |
---|
14 | SeeAlso [] |
---|
15 | |
---|
16 | Author [Fabio Somenzi, Chao Wang] |
---|
17 | |
---|
18 | Copyright [This file was created at the University of Colorado at |
---|
19 | Boulder. The University of Colorado at Boulder makes no warranty |
---|
20 | about the suitability of this software for any purpose. It is |
---|
21 | presented on an AS IS basis.] |
---|
22 | |
---|
23 | ******************************************************************************/ |
---|
24 | |
---|
25 | #include "mcInt.h" |
---|
26 | |
---|
27 | /*#define SCC_NO_TRIM */ |
---|
28 | |
---|
29 | /*---------------------------------------------------------------------------*/ |
---|
30 | /* Constant declarations */ |
---|
31 | /*---------------------------------------------------------------------------*/ |
---|
32 | |
---|
33 | /*---------------------------------------------------------------------------*/ |
---|
34 | /* Stucture declarations */ |
---|
35 | /*---------------------------------------------------------------------------*/ |
---|
36 | struct GraphNodeSpineSet { |
---|
37 | mdd_t *states; /* V */ |
---|
38 | mdd_t *spine; /* S */ |
---|
39 | mdd_t *node; /* Node */ |
---|
40 | }; |
---|
41 | |
---|
42 | /*---------------------------------------------------------------------------*/ |
---|
43 | /* Type declarations */ |
---|
44 | /*---------------------------------------------------------------------------*/ |
---|
45 | typedef struct GraphNodeSpineSet gns_t; |
---|
46 | |
---|
47 | /*---------------------------------------------------------------------------*/ |
---|
48 | /* Variable declarations */ |
---|
49 | /*---------------------------------------------------------------------------*/ |
---|
50 | |
---|
51 | #ifndef lint |
---|
52 | static char rcsid[] UNUSED = "$Id: mcSCC.c,v 1.11 2005/05/18 19:35:19 jinh Exp $"; |
---|
53 | #endif |
---|
54 | |
---|
55 | /*---------------------------------------------------------------------------*/ |
---|
56 | /* Macro declarations */ |
---|
57 | /*---------------------------------------------------------------------------*/ |
---|
58 | |
---|
59 | /**AutomaticStart*************************************************************/ |
---|
60 | |
---|
61 | /*---------------------------------------------------------------------------*/ |
---|
62 | /* Static function prototypes */ |
---|
63 | /*---------------------------------------------------------------------------*/ |
---|
64 | |
---|
65 | static mdd_t * LockstepPickSeed(Fsm_Fsm_t *fsm, mdd_t *V, array_t *buechiFairness, array_t *onionRings, int ringIndex); |
---|
66 | static void LockstepQueueEnqueue(Fsm_Fsm_t *fsm, Heap_t *queue, mdd_t *states, array_t *onionRings, McLockstepMode mode, array_t *buechiFairness, Mc_VerbosityLevel verbosity, Mc_DcLevel dcLevel); |
---|
67 | static void LinearstepQueueEnqueue(Fsm_Fsm_t *fsm, Heap_t *queue, mdd_t *states, mdd_t *spine, mdd_t *node, array_t *onionRings, McLockstepMode mode, array_t *buechiFairness, Mc_VerbosityLevel verbosity, Mc_DcLevel dcLevel); |
---|
68 | static int GetSccEnumerationMethod( void ); |
---|
69 | |
---|
70 | /**AutomaticEnd***************************************************************/ |
---|
71 | |
---|
72 | |
---|
73 | /*---------------------------------------------------------------------------*/ |
---|
74 | /* Definition of exported functions */ |
---|
75 | /*---------------------------------------------------------------------------*/ |
---|
76 | |
---|
77 | |
---|
78 | /**Function******************************************************************** |
---|
79 | |
---|
80 | Synopsis [Generates the first fair SCC of a FSM.] |
---|
81 | |
---|
82 | Description [Defines an iterator on the fair SCCs of a FSM and finds the |
---|
83 | first fair SCC. Returns a generator that contains the information |
---|
84 | necessary to continue the enumeration if successful; NULL |
---|
85 | otherwise.] |
---|
86 | |
---|
87 | SideEffects [The fair SCC is retuned as a side effect.] |
---|
88 | |
---|
89 | SeeAlso [Mc_FsmForEachScc Mc_FsmNextScc Mc_FsmIsSccGenEmpty |
---|
90 | Mc_FsmSccGenFree] |
---|
91 | |
---|
92 | ******************************************************************************/ |
---|
93 | Mc_SccGen_t * |
---|
94 | Mc_FsmFirstScc( |
---|
95 | Fsm_Fsm_t *fsm, |
---|
96 | mdd_t **scc, |
---|
97 | array_t *sccClosedSetArray, |
---|
98 | array_t *buechiFairness, |
---|
99 | array_t *onionRings, |
---|
100 | boolean earlyTermination, |
---|
101 | Mc_VerbosityLevel verbosity, |
---|
102 | Mc_DcLevel dcLevel) |
---|
103 | { |
---|
104 | Mc_SccGen_t *gen; |
---|
105 | Heap_t *heap; |
---|
106 | int i; |
---|
107 | mdd_t *closedSet; |
---|
108 | int linearStepMethod; |
---|
109 | |
---|
110 | if (fsm == NIL(Fsm_Fsm_t)) return NIL(Mc_SccGen_t); |
---|
111 | |
---|
112 | /* Allocate generator and initialize it. */ |
---|
113 | gen = ALLOC(Mc_SccGen_t, 1); |
---|
114 | if (gen == NIL(Mc_SccGen_t)) return NIL(Mc_SccGen_t); |
---|
115 | |
---|
116 | gen->fsm = fsm; |
---|
117 | gen->heap = heap = Heap_HeapInit(1); |
---|
118 | gen->rings = onionRings; |
---|
119 | gen->buechiFairness = buechiFairness; |
---|
120 | gen->earlyTermination = earlyTermination; |
---|
121 | gen->verbosity = verbosity; |
---|
122 | gen->dcLevel = dcLevel; |
---|
123 | gen->totalExamined = 0; |
---|
124 | gen->nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c); |
---|
125 | gen->nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c); |
---|
126 | |
---|
127 | linearStepMethod = GetSccEnumerationMethod(); |
---|
128 | /* Initialize the heap from the given sets of states. */ |
---|
129 | arrayForEachItem(mdd_t *, sccClosedSetArray, i, closedSet) { |
---|
130 | if (linearStepMethod == 1) { |
---|
131 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
132 | LinearstepQueueEnqueue(fsm, heap, mdd_dup(closedSet), |
---|
133 | mdd_zero(mddManager), |
---|
134 | mdd_zero(mddManager), onionRings, |
---|
135 | McLS_none_c, buechiFairness, verbosity, dcLevel); |
---|
136 | }else { |
---|
137 | LockstepQueueEnqueue(fsm, heap, mdd_dup(closedSet), onionRings, |
---|
138 | McLS_none_c, buechiFairness, verbosity, dcLevel); |
---|
139 | } |
---|
140 | } |
---|
141 | /* Find first SCC. */ |
---|
142 | if (Heap_HeapCount(heap) == 0) { |
---|
143 | *scc = NIL(mdd_t); |
---|
144 | } else { |
---|
145 | if (linearStepMethod == 1) |
---|
146 | *scc = McFsmComputeOneFairSccByLinearStep(fsm, heap, buechiFairness, |
---|
147 | onionRings, earlyTermination, |
---|
148 | verbosity, dcLevel, |
---|
149 | &(gen->totalExamined)); |
---|
150 | else |
---|
151 | *scc = McFsmComputeOneFairSccByLockStep(fsm, heap, buechiFairness, |
---|
152 | onionRings, earlyTermination, |
---|
153 | verbosity, dcLevel, |
---|
154 | &(gen->totalExamined)); |
---|
155 | } |
---|
156 | if (*scc == NIL(mdd_t)) { |
---|
157 | gen->status = McSccGenEmpty_c; |
---|
158 | gen->fairSccsFound = 0; |
---|
159 | } else { |
---|
160 | gen->status = McSccGenNonEmpty_c; |
---|
161 | gen->fairSccsFound = 1; |
---|
162 | } |
---|
163 | return gen; |
---|
164 | |
---|
165 | } /* Mc_FsmFirstScc */ |
---|
166 | |
---|
167 | |
---|
168 | /**Function******************************************************************** |
---|
169 | |
---|
170 | Synopsis [Generates the next fair SCC of a FSM.] |
---|
171 | |
---|
172 | Description [Generates the next fair SCC of a FSM, using generator |
---|
173 | gen. Returns FALSE if the enumeration is completed; TRUE otherwise.] |
---|
174 | |
---|
175 | SideEffects [The fair SCC is returned as side effect.] |
---|
176 | |
---|
177 | SeeAlso [Mc_FsmForEachScc Mc_FsmFirstScc Mc_FsmIsSccGenEmpty |
---|
178 | Mc_FsmSccGenFree] |
---|
179 | |
---|
180 | ******************************************************************************/ |
---|
181 | boolean |
---|
182 | Mc_FsmNextScc( |
---|
183 | Mc_SccGen_t *gen, |
---|
184 | mdd_t **scc) |
---|
185 | { |
---|
186 | int linearStepMethod; |
---|
187 | |
---|
188 | if (gen->earlyTermination == TRUE) { |
---|
189 | gen->status = McSccGenEmpty_c; |
---|
190 | return FALSE; |
---|
191 | } |
---|
192 | linearStepMethod = GetSccEnumerationMethod(); |
---|
193 | if (linearStepMethod == 1) |
---|
194 | *scc = McFsmComputeOneFairSccByLinearStep(gen->fsm, gen->heap, |
---|
195 | gen->buechiFairness, gen->rings, |
---|
196 | gen->earlyTermination, |
---|
197 | gen->verbosity, gen->dcLevel, |
---|
198 | &(gen->totalExamined)); |
---|
199 | else |
---|
200 | *scc = McFsmComputeOneFairSccByLockStep(gen->fsm, gen->heap, |
---|
201 | gen->buechiFairness, gen->rings, |
---|
202 | gen->earlyTermination, |
---|
203 | gen->verbosity, gen->dcLevel, |
---|
204 | &(gen->totalExamined)); |
---|
205 | if (*scc == NIL(mdd_t)) { |
---|
206 | gen->status = McSccGenEmpty_c; |
---|
207 | return FALSE; |
---|
208 | } else { |
---|
209 | gen->status = McSccGenNonEmpty_c; |
---|
210 | gen->fairSccsFound++; |
---|
211 | return TRUE; |
---|
212 | } |
---|
213 | |
---|
214 | } /* Mc_FsmNextScc */ |
---|
215 | |
---|
216 | |
---|
217 | /**Function******************************************************************** |
---|
218 | |
---|
219 | Synopsis [Returns TRUE if a generator is empty; FALSE otherwise.] |
---|
220 | |
---|
221 | Description [] |
---|
222 | |
---|
223 | SideEffects [none] |
---|
224 | |
---|
225 | SeeAlso [Mc_FsmForEachScc Mc_FsmFirstScc Mc_FsmNextScc Mc_FsmSccGenFree] |
---|
226 | |
---|
227 | ******************************************************************************/ |
---|
228 | boolean |
---|
229 | Mc_FsmIsSccGenEmpty( |
---|
230 | Mc_SccGen_t *gen) |
---|
231 | { |
---|
232 | if (gen == NIL(Mc_SccGen_t)) return TRUE; |
---|
233 | return gen->status == McSccGenEmpty_c; |
---|
234 | |
---|
235 | } /* Mc_FsmIsSccGenEmpty */ |
---|
236 | |
---|
237 | |
---|
238 | /**Function******************************************************************** |
---|
239 | |
---|
240 | Synopsis [Frees a SCC generator.] |
---|
241 | |
---|
242 | Description [Frees a SCC generator. Always returns FALSE, so that it |
---|
243 | can be used in iterators. |
---|
244 | |
---|
245 | leftover is an array_t of mdd_t *s.] |
---|
246 | |
---|
247 | SideEffects [The sets of states in the heap are returned in leftover |
---|
248 | if the array pointer is non-null.] |
---|
249 | |
---|
250 | SeeAlso [Mc_FsmForEachScc Mc_FsmFirstScc Mc_FsmNextScc |
---|
251 | Mc_FsmIsSccGenEmpty] |
---|
252 | |
---|
253 | ******************************************************************************/ |
---|
254 | boolean |
---|
255 | Mc_FsmSccGenFree( |
---|
256 | Mc_SccGen_t *gen, |
---|
257 | array_t *leftover) |
---|
258 | { |
---|
259 | int linearStepMethod; |
---|
260 | |
---|
261 | if (gen == NIL(Mc_SccGen_t)) return FALSE; |
---|
262 | /* Print some stats. */ |
---|
263 | if (gen->verbosity == McVerbositySome_c || gen->verbosity == McVerbosityMax_c) { |
---|
264 | fprintf(vis_stdout, |
---|
265 | "--SCC: found %d fair SCC(s) out of %d examined\n", |
---|
266 | gen->fairSccsFound, gen->totalExamined); |
---|
267 | fprintf(vis_stdout, |
---|
268 | "--SCC: %d image computations, %d preimage computations\n", |
---|
269 | Img_GetNumberOfImageComputation(Img_Forward_c) - gen->nImgComps, |
---|
270 | Img_GetNumberOfImageComputation(Img_Backward_c) - gen->nPreComps); |
---|
271 | } |
---|
272 | /* Create array from elements still on queue if so requested. */ |
---|
273 | linearStepMethod = GetSccEnumerationMethod(); |
---|
274 | if (linearStepMethod == 1) { |
---|
275 | while (Heap_HeapCount(gen->heap)) { |
---|
276 | gns_t *set; |
---|
277 | long index; |
---|
278 | int retval UNUSED = Heap_HeapExtractMin(gen->heap, &set, &index); |
---|
279 | assert(retval); |
---|
280 | if (leftover == NIL(array_t) || gen->earlyTermination == TRUE) { |
---|
281 | mdd_free(set->states); |
---|
282 | } else { |
---|
283 | array_insert_last(mdd_t *, leftover, set->states); |
---|
284 | } |
---|
285 | mdd_free(set->spine); mdd_free(set->node); |
---|
286 | FREE(set); |
---|
287 | } |
---|
288 | }else { |
---|
289 | while (Heap_HeapCount(gen->heap)) { |
---|
290 | mdd_t *set; |
---|
291 | long index; |
---|
292 | int retval UNUSED = Heap_HeapExtractMin(gen->heap, &set, &index); |
---|
293 | assert(retval); |
---|
294 | if (leftover == NIL(array_t) || gen->earlyTermination == TRUE) { |
---|
295 | mdd_free(set); |
---|
296 | } else { |
---|
297 | array_insert_last(mdd_t *, leftover, set); |
---|
298 | } |
---|
299 | } |
---|
300 | } |
---|
301 | |
---|
302 | Heap_HeapFree(gen->heap); |
---|
303 | FREE(gen); |
---|
304 | return FALSE; |
---|
305 | |
---|
306 | } /* Mc_FsmSccGenFree */ |
---|
307 | |
---|
308 | |
---|
309 | /**Function******************************************************************** |
---|
310 | |
---|
311 | Synopsis [Computes fair SCCs of an FSM.] |
---|
312 | |
---|
313 | Description [Returns some fair SCCs of an FSM and the states on the |
---|
314 | paths leading to them. Parameter <code>maxNumberOfSCCs</code> |
---|
315 | controls the enumeration. If its value is 0, all fair SCCs are |
---|
316 | enumerated; if it is negative, early termination is applied, and at |
---|
317 | most one fair SCC is computed. Finally, if |
---|
318 | <code>maxNumberOfSCCs</code> is a positive integer <code>n</code>, |
---|
319 | then exactly <code>n</code> fair SCCs are computed.] |
---|
320 | |
---|
321 | SideEffects [Returns an array with one SCC per entry as side |
---|
322 | effect. May update reachability information.] |
---|
323 | |
---|
324 | SeeAlso [] |
---|
325 | |
---|
326 | ******************************************************************************/ |
---|
327 | mdd_t * |
---|
328 | McFsmComputeFairSCCsByLockStep( |
---|
329 | Fsm_Fsm_t *fsm, |
---|
330 | int maxNumberOfSCCs, |
---|
331 | array_t *SCCs, |
---|
332 | array_t *onionRingsArrayForDbg, |
---|
333 | Mc_VerbosityLevel verbosity, |
---|
334 | Mc_DcLevel dcLevel) |
---|
335 | { |
---|
336 | Mc_SccGen_t *sccGen; |
---|
337 | mdd_t *mddOne, *reached, *hull, *scc, *fairStates; |
---|
338 | array_t *onionRings, *sccClosedSetArray, *careStatesArray; |
---|
339 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
340 | int nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c); |
---|
341 | int nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c); |
---|
342 | Fsm_Fairness_t *modelFairness = Fsm_FsmReadFairnessConstraint(fsm); |
---|
343 | array_t *buechiFairness = array_alloc(mdd_t *, 0); |
---|
344 | |
---|
345 | /* Initialization. */ |
---|
346 | mddOne = mdd_one(mddManager); |
---|
347 | |
---|
348 | sccClosedSetArray = array_alloc(mdd_t *, 0); |
---|
349 | reached = Fsm_FsmComputeReachableStates(fsm, 0, verbosity, 0, 0, 1, 0, 0, |
---|
350 | Fsm_Rch_Default_c, 0, 0, |
---|
351 | NIL(array_t), FALSE, NIL(array_t)); |
---|
352 | array_insert_last(mdd_t *, sccClosedSetArray, reached); |
---|
353 | onionRings = Fsm_FsmReadReachabilityOnionRings(fsm); |
---|
354 | |
---|
355 | careStatesArray = array_alloc(mdd_t *, 0); |
---|
356 | array_insert_last(mdd_t *, careStatesArray, reached); |
---|
357 | Img_MinimizeTransitionRelation(Fsm_FsmReadOrCreateImageInfo(fsm, 1, 1), |
---|
358 | careStatesArray, Img_DefaultMinimizeMethod_c, |
---|
359 | Img_Both_c, FALSE); |
---|
360 | |
---|
361 | /* Read fairness constraints. */ |
---|
362 | if (modelFairness != NIL(Fsm_Fairness_t)) { |
---|
363 | if (!Fsm_FairnessTestIsBuchi(modelFairness)) { |
---|
364 | (void) fprintf(vis_stdout, |
---|
365 | "** mc error: non-Buechi fairness constraints not supported\n"); |
---|
366 | array_free(buechiFairness); |
---|
367 | return NIL(mdd_t); |
---|
368 | } else { |
---|
369 | int j; |
---|
370 | int numBuchi = Fsm_FairnessReadNumConjunctsOfDisjunct(modelFairness, 0); |
---|
371 | for (j = 0; j < numBuchi; j++) { |
---|
372 | mdd_t *tmpMdd = Fsm_FairnessObtainFinallyInfMdd(modelFairness, 0, j, |
---|
373 | careStatesArray, |
---|
374 | dcLevel); |
---|
375 | array_insert_last(mdd_t *, buechiFairness, tmpMdd); |
---|
376 | } |
---|
377 | } |
---|
378 | } else { |
---|
379 | array_insert_last(mdd_t *, buechiFairness, mdd_one(mddManager)); |
---|
380 | } |
---|
381 | |
---|
382 | /* Enumerate the fair SCCs and accumulate their disjunction in hull. */ |
---|
383 | hull = mdd_zero(mddManager); |
---|
384 | Mc_FsmForEachFairScc(fsm, sccGen, scc, sccClosedSetArray, NIL(array_t), |
---|
385 | buechiFairness, onionRings, |
---|
386 | maxNumberOfSCCs == MC_LOCKSTEP_EARLY_TERMINATION, |
---|
387 | verbosity, dcLevel) { |
---|
388 | mdd_t *tmp = mdd_or(hull, scc, 1, 1); |
---|
389 | mdd_free(hull); |
---|
390 | hull = tmp; |
---|
391 | array_insert_last(mdd_t *, SCCs, scc); |
---|
392 | if (maxNumberOfSCCs > MC_LOCKSTEP_ALL_SCCS && |
---|
393 | array_n(SCCs) == maxNumberOfSCCs) { |
---|
394 | Mc_FsmSccGenFree(sccGen, NIL(array_t)); |
---|
395 | break; |
---|
396 | } |
---|
397 | } |
---|
398 | |
---|
399 | /* Compute (subset of) fair states and onion rings. */ |
---|
400 | if (onionRingsArrayForDbg != NIL(array_t)) { |
---|
401 | mdd_t *fairSet; |
---|
402 | int i; |
---|
403 | fairStates = Mc_FsmEvaluateEUFormula(fsm, reached, hull, |
---|
404 | NIL(mdd_t), mddOne, careStatesArray, |
---|
405 | MC_NO_EARLY_TERMINATION, |
---|
406 | NIL(array_t), Mc_None_c, NIL(array_t), |
---|
407 | verbosity, dcLevel, NIL(boolean)); |
---|
408 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
409 | mdd_t *restrictedFairSet = mdd_and(fairSet, hull, 1, 1); |
---|
410 | array_t *setOfRings = array_alloc(mdd_t *, 0); |
---|
411 | mdd_t *EU = Mc_FsmEvaluateEUFormula(fsm, fairStates, restrictedFairSet, |
---|
412 | NIL(mdd_t), mddOne, careStatesArray, |
---|
413 | MC_NO_EARLY_TERMINATION, |
---|
414 | NIL(array_t), Mc_None_c, setOfRings, |
---|
415 | verbosity, dcLevel, NIL(boolean)); |
---|
416 | array_insert_last(array_t *, onionRingsArrayForDbg, setOfRings); |
---|
417 | mdd_free(restrictedFairSet); |
---|
418 | mdd_free(EU); |
---|
419 | } |
---|
420 | } else { |
---|
421 | fairStates = mdd_dup(hull); |
---|
422 | } |
---|
423 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
424 | fprintf(vis_stdout, |
---|
425 | "--Fair States: %d image computations, %d preimage computations\n", |
---|
426 | Img_GetNumberOfImageComputation(Img_Forward_c) - nImgComps, |
---|
427 | Img_GetNumberOfImageComputation(Img_Backward_c) - nPreComps); |
---|
428 | } |
---|
429 | |
---|
430 | /* Clean up. */ |
---|
431 | array_free(sccClosedSetArray); |
---|
432 | mdd_free(reached); |
---|
433 | mdd_free(hull); |
---|
434 | mdd_free(mddOne); |
---|
435 | array_free(careStatesArray); |
---|
436 | mdd_array_free(buechiFairness); |
---|
437 | return fairStates; |
---|
438 | |
---|
439 | } /* McFsmComputeFairSCCsByLockStep */ |
---|
440 | |
---|
441 | /**Function******************************************************************** |
---|
442 | |
---|
443 | Synopsis [Computes fair SCCs of an FSM within SCC-closed sets.] |
---|
444 | |
---|
445 | Description [Same as McFsmComputeFairSCCsByLockStep, except that the |
---|
446 | fair SCCs returned are within the given array of SCC-closed sets.] |
---|
447 | |
---|
448 | |
---|
449 | SideEffects [Returns an array with one SCC per entry as side |
---|
450 | effect. May update reachability information.] |
---|
451 | |
---|
452 | SeeAlso [McFsmComputeFairSCCsByLockStep] |
---|
453 | |
---|
454 | ******************************************************************************/ |
---|
455 | mdd_t * |
---|
456 | McFsmRefineFairSCCsByLockStep( |
---|
457 | Fsm_Fsm_t *fsm, |
---|
458 | int maxNumberOfSCCs, |
---|
459 | array_t *SCCs, |
---|
460 | array_t *sccClosedSets, |
---|
461 | array_t *careStates, |
---|
462 | array_t *onionRingsArrayForDbg, |
---|
463 | Mc_VerbosityLevel verbosity, |
---|
464 | Mc_DcLevel dcLevel) |
---|
465 | { |
---|
466 | Mc_SccGen_t *sccGen; |
---|
467 | mdd_t *mddOne, *reached, *hull, *scc, *fairStates; |
---|
468 | array_t *onionRings, *careStatesArray, *sccClosedSetArray; |
---|
469 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
470 | int nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c); |
---|
471 | int nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c); |
---|
472 | Fsm_Fairness_t *modelFairness = Fsm_FsmReadFairnessConstraint(fsm); |
---|
473 | array_t *buechiFairness = array_alloc(mdd_t *, 0); |
---|
474 | |
---|
475 | /* Initialization. */ |
---|
476 | mddOne = mdd_one(mddManager); |
---|
477 | |
---|
478 | if (careStates == NIL(array_t)) { |
---|
479 | reached = Fsm_FsmComputeReachableStates(fsm, 0, verbosity, 0, 0, 1, 0, 0, |
---|
480 | Fsm_Rch_Default_c, 0, 0, |
---|
481 | NIL(array_t), FALSE, NIL(array_t)); |
---|
482 | careStatesArray = array_alloc(mdd_t *, 0); |
---|
483 | array_insert_last(mdd_t *, careStatesArray, mdd_dup(reached)); |
---|
484 | }else { |
---|
485 | reached = McMddArrayAnd(careStates); |
---|
486 | careStatesArray = mdd_array_duplicate(careStates); |
---|
487 | } |
---|
488 | |
---|
489 | onionRings = Fsm_FsmReadReachabilityOnionRings(fsm); |
---|
490 | if (onionRings == NIL(array_t)) { |
---|
491 | onionRings = array_alloc(mdd_t *, 0); |
---|
492 | array_insert_last(mdd_t *, onionRings, mdd_dup(mddOne)); |
---|
493 | }else |
---|
494 | onionRings = mdd_array_duplicate(onionRings); |
---|
495 | |
---|
496 | if (sccClosedSets == NIL(array_t)) { |
---|
497 | sccClosedSetArray = array_alloc(mdd_t *, 0); |
---|
498 | array_insert_last(mdd_t *, sccClosedSetArray, mdd_dup(reached)); |
---|
499 | }else { |
---|
500 | if (careStates != NIL(array_t)) |
---|
501 | sccClosedSetArray = mdd_array_duplicate(sccClosedSets); |
---|
502 | else { |
---|
503 | mdd_t *mdd1, *mdd2; |
---|
504 | int i; |
---|
505 | sccClosedSetArray = array_alloc(mdd_t *, 0); |
---|
506 | arrayForEachItem(mdd_t *, sccClosedSets, i, mdd1) { |
---|
507 | mdd2 = mdd_and(mdd1, reached, 1, 1); |
---|
508 | if (mdd_is_tautology(mdd2, 0)) |
---|
509 | mdd_free(mdd2); |
---|
510 | else |
---|
511 | array_insert_last(mdd_t *, sccClosedSetArray, mdd2); |
---|
512 | } |
---|
513 | } |
---|
514 | } |
---|
515 | |
---|
516 | Img_MinimizeTransitionRelation(Fsm_FsmReadOrCreateImageInfo(fsm, 1, 1), |
---|
517 | careStatesArray, Img_DefaultMinimizeMethod_c, |
---|
518 | Img_Both_c, FALSE); |
---|
519 | |
---|
520 | /* Read fairness constraints. */ |
---|
521 | if (modelFairness != NIL(Fsm_Fairness_t)) { |
---|
522 | if (!Fsm_FairnessTestIsBuchi(modelFairness)) { |
---|
523 | (void) fprintf(vis_stdout, |
---|
524 | "** mc error: non-Buechi fairness constraints not supported\n"); |
---|
525 | array_free(buechiFairness); |
---|
526 | mdd_array_free(sccClosedSetArray); |
---|
527 | mdd_array_free(onionRings); |
---|
528 | mdd_array_free(careStatesArray); |
---|
529 | mdd_free(reached); |
---|
530 | return NIL(mdd_t); |
---|
531 | } else { |
---|
532 | int j; |
---|
533 | int numBuchi = Fsm_FairnessReadNumConjunctsOfDisjunct(modelFairness, 0); |
---|
534 | for (j = 0; j < numBuchi; j++) { |
---|
535 | mdd_t *tmpMdd = Fsm_FairnessObtainFinallyInfMdd(modelFairness, 0, j, |
---|
536 | careStatesArray, |
---|
537 | dcLevel); |
---|
538 | array_insert_last(mdd_t *, buechiFairness, tmpMdd); |
---|
539 | } |
---|
540 | } |
---|
541 | } else { |
---|
542 | array_insert_last(mdd_t *, buechiFairness, mdd_one(mddManager)); |
---|
543 | } |
---|
544 | |
---|
545 | /* Enumerate the fair SCCs and accumulate their disjunction in hull. */ |
---|
546 | hull = mdd_zero(mddManager); |
---|
547 | Mc_FsmForEachFairScc(fsm, sccGen, scc, sccClosedSetArray, NIL(array_t), |
---|
548 | buechiFairness, onionRings, |
---|
549 | maxNumberOfSCCs == MC_LOCKSTEP_EARLY_TERMINATION, |
---|
550 | verbosity, dcLevel) { |
---|
551 | mdd_t *tmp = mdd_or(hull, scc, 1, 1); |
---|
552 | mdd_free(hull); |
---|
553 | hull = tmp; |
---|
554 | array_insert_last(mdd_t *, SCCs, scc); |
---|
555 | if (maxNumberOfSCCs > MC_LOCKSTEP_ALL_SCCS && |
---|
556 | array_n(SCCs) == maxNumberOfSCCs) { |
---|
557 | Mc_FsmSccGenFree(sccGen, NIL(array_t)); |
---|
558 | break; |
---|
559 | } |
---|
560 | } |
---|
561 | |
---|
562 | /* Compute (subset of) fair states and onion rings. */ |
---|
563 | if (onionRingsArrayForDbg != NIL(array_t)) { |
---|
564 | mdd_t *fairSet; |
---|
565 | int i; |
---|
566 | fairStates = Mc_FsmEvaluateEUFormula(fsm, reached, hull, |
---|
567 | NIL(mdd_t), mddOne, careStatesArray, |
---|
568 | MC_NO_EARLY_TERMINATION, |
---|
569 | NIL(array_t), Mc_None_c, NIL(array_t), |
---|
570 | verbosity, dcLevel, NIL(boolean)); |
---|
571 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
572 | mdd_t *restrictedFairSet = mdd_and(fairSet, hull, 1, 1); |
---|
573 | array_t *setOfRings = array_alloc(mdd_t *, 0); |
---|
574 | mdd_t *EU = Mc_FsmEvaluateEUFormula(fsm, fairStates, restrictedFairSet, |
---|
575 | NIL(mdd_t), mddOne, careStatesArray, |
---|
576 | MC_NO_EARLY_TERMINATION, |
---|
577 | NIL(array_t), Mc_None_c, setOfRings, |
---|
578 | verbosity, dcLevel, NIL(boolean)); |
---|
579 | array_insert_last(array_t *, onionRingsArrayForDbg, setOfRings); |
---|
580 | mdd_free(restrictedFairSet); |
---|
581 | mdd_free(EU); |
---|
582 | } |
---|
583 | } else { |
---|
584 | fairStates = mdd_dup(hull); |
---|
585 | } |
---|
586 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
587 | fprintf(vis_stdout, |
---|
588 | "--Fair States: %d image computations, %d preimage computations\n", |
---|
589 | Img_GetNumberOfImageComputation(Img_Forward_c) - nImgComps, |
---|
590 | Img_GetNumberOfImageComputation(Img_Backward_c) - nPreComps); |
---|
591 | } |
---|
592 | |
---|
593 | /* Clean up. */ |
---|
594 | mdd_array_free(sccClosedSetArray); |
---|
595 | mdd_free(reached); |
---|
596 | mdd_free(hull); |
---|
597 | mdd_free(mddOne); |
---|
598 | mdd_array_free(careStatesArray); |
---|
599 | mdd_array_free(buechiFairness); |
---|
600 | return fairStates; |
---|
601 | |
---|
602 | } /* McFsmRefineFairSCCsByLockStep */ |
---|
603 | |
---|
604 | |
---|
605 | /**Function******************************************************************** |
---|
606 | |
---|
607 | Synopsis [Computes one fair SCC of an FSM, by LinearStep.] |
---|
608 | |
---|
609 | Description [Computes one fair SCC of the state transition graph of |
---|
610 | an FSM. Returns the fair SCC if one exists; NULL otherwise. This |
---|
611 | function uses the linear steps SCC enumeration algorithm of |
---|
612 | Gentilini, Piazza, and Policriti, "Computing strongly connected |
---|
613 | components in a linear number of symbolic steps," and with the |
---|
614 | addition of an early termination test.<p> |
---|
615 | |
---|
616 | On input, the heap is supposed to contain a set of SCC-closed state |
---|
617 | sets together with their spine-sets. If earlyTermination is |
---|
618 | requested, the heap is left in an inconsistent state; otherwise, it |
---|
619 | contains a set of SCC-closed sets that contains all fair SCCs that |
---|
620 | were on the heap on input, except the one that has been enumerated. |
---|
621 | The number of sets may be different, and some non-fair SCCs may no |
---|
622 | longer be present.<p> |
---|
623 | |
---|
624 | The onionRing parameter is an array of state sets that is used to |
---|
625 | pick a seed close to a target. Typically, these onion rings come |
---|
626 | from reachability analysis. The target states in this case are the |
---|
627 | initial states of the FSM, and the objective of choosing a seed |
---|
628 | close to them is to reduce the length of the stem of a |
---|
629 | counterexample in the language emptiness check. However, any |
---|
630 | collection of sets that together cover all the states on the heap |
---|
631 | will work. If one is not concerned with a specific target, but |
---|
632 | rather with speed, then passing an array with just one component set |
---|
633 | to the constant one is preferable.] |
---|
634 | |
---|
635 | SideEffects [Updates the priority queue. The number of SCC examined |
---|
636 | (i.e., the number of chosen seeds) is added to sccExamined.] |
---|
637 | |
---|
638 | SeeAlso [Mc_FsmForEachFairScc] |
---|
639 | |
---|
640 | ******************************************************************************/ |
---|
641 | mdd_t * |
---|
642 | McFsmComputeOneFairSccByLinearStep( |
---|
643 | Fsm_Fsm_t *fsm, |
---|
644 | Heap_t *priorityQueue, |
---|
645 | array_t *buechiFairness, |
---|
646 | array_t *onionRings, |
---|
647 | boolean earlyTermination, |
---|
648 | Mc_VerbosityLevel verbosity, |
---|
649 | Mc_DcLevel dcLevel, |
---|
650 | int *sccExamined) |
---|
651 | { |
---|
652 | mdd_t *mddOne, *SCC = NIL(mdd_t); |
---|
653 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
654 | int nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c); |
---|
655 | int nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c); |
---|
656 | array_t *careStatesArray = array_alloc(mdd_t *, 0); |
---|
657 | int totalSCCs = 0; |
---|
658 | boolean foundScc = FALSE; |
---|
659 | array_t *activeFairness = NIL(array_t); |
---|
660 | int firstActive = 0; |
---|
661 | gns_t *gns; |
---|
662 | |
---|
663 | /* Initialization. */ |
---|
664 | mddOne = mdd_one(mddManager); |
---|
665 | array_insert(mdd_t *, careStatesArray, 0, mddOne); |
---|
666 | |
---|
667 | while (Heap_HeapCount(priorityQueue)) { |
---|
668 | mdd_t *V, *F, *fFront, *bFront, *fairSet; |
---|
669 | mdd_t *S, *NODE, *newS, *newNODE, *preNODE; |
---|
670 | long ringIndex; |
---|
671 | int retval UNUSED = Heap_HeapExtractMin(priorityQueue, &gns, |
---|
672 | &ringIndex); |
---|
673 | assert(retval && ringIndex < array_n(onionRings)); |
---|
674 | |
---|
675 | /* Extract the SCC-closed set, together with its spine-set */ |
---|
676 | V = gns->states; |
---|
677 | S = gns->spine; |
---|
678 | NODE = gns->node; |
---|
679 | FREE(gns); |
---|
680 | |
---|
681 | /* Determine the seed for which the SCC is computed */ |
---|
682 | if (mdd_is_tautology(S, 0) ) { |
---|
683 | assert( mdd_is_tautology(NODE, 0) ); |
---|
684 | mdd_free(NODE); |
---|
685 | NODE = LockstepPickSeed(fsm, V, buechiFairness, onionRings, ringIndex); |
---|
686 | } |
---|
687 | |
---|
688 | if (earlyTermination == TRUE) { |
---|
689 | int i; |
---|
690 | activeFairness = array_alloc(mdd_t *, 0); |
---|
691 | for (i = 0; i < array_n(buechiFairness); i++) { |
---|
692 | mdd_t *fairSet = array_fetch(mdd_t *, buechiFairness, i); |
---|
693 | if (!mdd_lequal(NODE, fairSet, 1, 1)) { |
---|
694 | array_insert_last(mdd_t *, activeFairness, fairSet); |
---|
695 | } |
---|
696 | } |
---|
697 | } |
---|
698 | |
---|
699 | /* Compute the forward-set of seed, together with a new spine-set */ |
---|
700 | { |
---|
701 | array_t *newCareStatesArray = array_alloc(mdd_t *, 0); |
---|
702 | array_t *stack = array_alloc(mdd_t *, 0); |
---|
703 | mdd_t *tempMdd, *tempMdd2; |
---|
704 | int i; |
---|
705 | /* (1) Compute the forward-set, and push it onto STACK */ |
---|
706 | F = mdd_zero(mddManager); |
---|
707 | fFront = mdd_dup(NODE); |
---|
708 | while (!mdd_is_tautology(fFront, 0)) { |
---|
709 | array_insert_last(mdd_t *, stack, mdd_dup(fFront)); |
---|
710 | |
---|
711 | tempMdd = F; |
---|
712 | F = mdd_or(F, fFront, 1, 1); |
---|
713 | mdd_free(tempMdd); |
---|
714 | |
---|
715 | tempMdd = Mc_FsmEvaluateEYFormula(fsm, fFront, mddOne, careStatesArray, |
---|
716 | verbosity, dcLevel); |
---|
717 | mdd_free(fFront); |
---|
718 | tempMdd2 = mdd_and(tempMdd, V, 1, 1); |
---|
719 | mdd_free(tempMdd); |
---|
720 | fFront = mdd_and(tempMdd2, F, 1, 0); |
---|
721 | mdd_free(tempMdd2); |
---|
722 | } |
---|
723 | mdd_free(fFront); |
---|
724 | /* (2) Determine a spine-set of the forward-set */ |
---|
725 | i = array_n(stack) - 1; |
---|
726 | fFront = array_fetch(mdd_t *, stack, i); |
---|
727 | newNODE = Mc_ComputeAState(fFront, fsm); |
---|
728 | mdd_free(fFront); |
---|
729 | |
---|
730 | newS = mdd_dup(newNODE); |
---|
731 | while (i > 0) { |
---|
732 | fFront = array_fetch(mdd_t *, stack, --i); |
---|
733 | /* Chao: The use of DCs here may slow down the computation, |
---|
734 | * even though it reduces the peak BDD size |
---|
735 | */ |
---|
736 | /* array_insert(mdd_t *, newCareStatesArray, 0, fFront); */ |
---|
737 | array_insert(mdd_t *, newCareStatesArray, 0, mddOne); |
---|
738 | tempMdd = Mc_FsmEvaluateEXFormula(fsm, newS, mddOne, newCareStatesArray, |
---|
739 | verbosity, dcLevel); |
---|
740 | tempMdd2 = mdd_and(tempMdd, fFront, 1, 1); |
---|
741 | mdd_free(tempMdd); |
---|
742 | mdd_free(fFront); |
---|
743 | |
---|
744 | tempMdd = Mc_ComputeAState(tempMdd2, fsm); |
---|
745 | mdd_free(tempMdd2); |
---|
746 | |
---|
747 | tempMdd2 = newS; |
---|
748 | newS = mdd_or(newS, tempMdd, 1, 1); |
---|
749 | mdd_free(tempMdd2); |
---|
750 | mdd_free(tempMdd); |
---|
751 | } |
---|
752 | array_free(stack); |
---|
753 | array_free(newCareStatesArray); |
---|
754 | } |
---|
755 | /* now, we have {F, newS, newNODE} */ |
---|
756 | |
---|
757 | /* Determine the SCC containing NODE */ |
---|
758 | SCC = mdd_dup(NODE); |
---|
759 | bFront = mdd_dup(NODE); |
---|
760 | while (1) { |
---|
761 | mdd_t *tempMdd, *tempMdd2; |
---|
762 | |
---|
763 | if (earlyTermination == TRUE) { |
---|
764 | mdd_t * meet = mdd_and(SCC, NODE, 1, 0); |
---|
765 | if (!mdd_is_tautology(meet, 0)) { |
---|
766 | assert(mdd_lequal(meet, V, 1, 1)); |
---|
767 | for ( ; firstActive < array_n(activeFairness); firstActive++) { |
---|
768 | mdd_t *fairSet = array_fetch(mdd_t *, activeFairness, firstActive); |
---|
769 | if (mdd_lequal(meet, fairSet, 1, 0)) break; |
---|
770 | } |
---|
771 | mdd_free(meet); |
---|
772 | if (firstActive == array_n(activeFairness)) { |
---|
773 | int i; |
---|
774 | (void) fprintf(vis_stdout, "EARLY TERMINATION!\n"); |
---|
775 | totalSCCs++; |
---|
776 | /* Trim fair sets to guarantee counterexample will go through |
---|
777 | * this SCC. |
---|
778 | */ |
---|
779 | for (i = 0; i < array_n(buechiFairness); i++) { |
---|
780 | mdd_t *fairSet = array_fetch(mdd_t *, buechiFairness, i); |
---|
781 | mdd_t *trimmed = mdd_and(fairSet, SCC, 1, 1); |
---|
782 | mdd_free(fairSet); |
---|
783 | array_insert(mdd_t *, buechiFairness, i, trimmed); |
---|
784 | } |
---|
785 | mdd_free(bFront); |
---|
786 | mdd_free(F); |
---|
787 | mdd_free(V); |
---|
788 | mdd_free(S); |
---|
789 | mdd_free(NODE); |
---|
790 | mdd_free(newS); |
---|
791 | mdd_free(newNODE); |
---|
792 | array_free(activeFairness); |
---|
793 | |
---|
794 | foundScc = TRUE; |
---|
795 | goto cleanUp; |
---|
796 | } |
---|
797 | } |
---|
798 | mdd_free(meet); |
---|
799 | } |
---|
800 | |
---|
801 | tempMdd = Mc_FsmEvaluateEXFormula(fsm, bFront, mddOne, careStatesArray, |
---|
802 | verbosity, dcLevel); |
---|
803 | tempMdd2 = mdd_and(tempMdd, F, 1, 1); |
---|
804 | mdd_free(tempMdd); |
---|
805 | |
---|
806 | tempMdd = bFront; |
---|
807 | bFront = mdd_and(tempMdd2, SCC, 1, 0); |
---|
808 | mdd_free(tempMdd2); |
---|
809 | mdd_free(tempMdd); |
---|
810 | if (mdd_is_tautology(bFront, 0)) break; |
---|
811 | |
---|
812 | tempMdd = SCC; |
---|
813 | SCC = mdd_or(SCC, bFront, 1, 1); |
---|
814 | mdd_free(tempMdd); |
---|
815 | } |
---|
816 | mdd_free(bFront); |
---|
817 | |
---|
818 | totalSCCs++; |
---|
819 | preNODE = Mc_FsmEvaluateEYFormula(fsm, NODE, mddOne, careStatesArray, |
---|
820 | verbosity, dcLevel); |
---|
821 | |
---|
822 | /* Check for fairness. If SCC is a trival SCC, skip the check */ |
---|
823 | if ( !mdd_equal(SCC, NODE) || mdd_lequal(NODE, preNODE, 1, 1) ) { |
---|
824 | /* Check fairness constraints. */ |
---|
825 | int i; |
---|
826 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
827 | if (mdd_lequal(SCC, fairSet, 1, 0)) break; |
---|
828 | } |
---|
829 | if (i == array_n(buechiFairness)) { |
---|
830 | /* All fairness iconditions intersected. We have a fair SCC. */ |
---|
831 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
832 | array_t *PSvars = Fsm_FsmReadPresentStateVars(fsm); |
---|
833 | fprintf(vis_stdout, "--linearSCC: found a fair SCC with %.0f states\n", |
---|
834 | mdd_count_onset(mddManager, SCC, PSvars)); |
---|
835 | /* (void) bdd_print_minterm(SCC); */ |
---|
836 | } |
---|
837 | foundScc = TRUE; |
---|
838 | } |
---|
839 | } |
---|
840 | mdd_free(preNODE); |
---|
841 | mdd_free(NODE); |
---|
842 | |
---|
843 | /* Divide the remaining states of V into V minus |
---|
844 | * the forward set F, and the rest (minus the fair SCC). Add the two |
---|
845 | * sets thus obtained to the priority queue. */ |
---|
846 | { |
---|
847 | mdd_t *V1, *S1, *NODE1; |
---|
848 | mdd_t *tempMdd, *tempMdd2; |
---|
849 | |
---|
850 | V1 = mdd_and(V, F, 1, 0); |
---|
851 | S1 = mdd_and(S, SCC, 1, 0); |
---|
852 | tempMdd = mdd_and(SCC, S, 1, 1); |
---|
853 | tempMdd2 = Mc_FsmEvaluateEXFormula(fsm, tempMdd, mddOne, |
---|
854 | careStatesArray, |
---|
855 | verbosity, dcLevel); |
---|
856 | mdd_free(tempMdd); |
---|
857 | NODE1 = mdd_and(tempMdd2, S1, 1, 1); |
---|
858 | mdd_free(tempMdd2); |
---|
859 | LinearstepQueueEnqueue(fsm, priorityQueue, V1, S1, NODE1, |
---|
860 | onionRings, McLS_G_c, |
---|
861 | buechiFairness, verbosity, dcLevel); |
---|
862 | |
---|
863 | V1 = mdd_and(F, SCC, 1, 0); |
---|
864 | S1 = mdd_and(newS, SCC, 1, 0); |
---|
865 | NODE1 = mdd_and(newNODE, SCC, 1, 0); |
---|
866 | LinearstepQueueEnqueue(fsm, priorityQueue, V1, S1, NODE1, |
---|
867 | onionRings, McLS_H_c, |
---|
868 | buechiFairness, verbosity, dcLevel); |
---|
869 | } |
---|
870 | mdd_free(F); |
---|
871 | mdd_free(V); |
---|
872 | mdd_free(S); |
---|
873 | mdd_free(newS); |
---|
874 | mdd_free(newNODE); |
---|
875 | |
---|
876 | if (foundScc == TRUE) break; |
---|
877 | mdd_free(SCC); |
---|
878 | } |
---|
879 | |
---|
880 | cleanUp: |
---|
881 | mdd_free(mddOne); |
---|
882 | array_free(careStatesArray); |
---|
883 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
884 | fprintf(vis_stdout, |
---|
885 | "--linearSCC: found %s fair SCC out of %d examined\n", |
---|
886 | foundScc ? "one" : "no", totalSCCs); |
---|
887 | fprintf(vis_stdout, |
---|
888 | "--linearSCC: %d image computations, %d preimage computations\n", |
---|
889 | Img_GetNumberOfImageComputation(Img_Forward_c) - nImgComps, |
---|
890 | Img_GetNumberOfImageComputation(Img_Backward_c) - nPreComps); |
---|
891 | } |
---|
892 | *sccExamined += totalSCCs; |
---|
893 | return foundScc ? SCC : NIL(mdd_t); |
---|
894 | |
---|
895 | } /* McFsmComputeOneFairSccByLinearStep */ |
---|
896 | |
---|
897 | |
---|
898 | /**Function******************************************************************** |
---|
899 | |
---|
900 | Synopsis [Computes one fair SCC of an FSM, by LockStep.] |
---|
901 | |
---|
902 | Description [Computes one fair SCC of the state transition graph of |
---|
903 | an FSM. Returns the fair SCC if one exists; NULL otherwise. This |
---|
904 | function uses the lockstep SCC enumeration algorithm of Bloem, |
---|
905 | Gabow, and Somenzi (FMCAD'00) implemented as described in Ravi, |
---|
906 | Bloem, and Somenzi (FMCAD'00), and with the addition of an early |
---|
907 | termination test.<p> |
---|
908 | |
---|
909 | On input, the heap is supposed to contain a set of SCC-closed state |
---|
910 | sets. If earlyTermination is requested, the heap is left in an |
---|
911 | inconsistent state; otherwise, it contains a set of SCC-closed sets |
---|
912 | that contains all fair SCCs that were on the heap on input except |
---|
913 | the one that has been enumerated. The number of sets may be |
---|
914 | different, and some non-fair SCCs may no longer be present.<p> |
---|
915 | |
---|
916 | The onionRing parameter is an array of state sets that is used to |
---|
917 | pick a seed close to a target. Typically, these onion rings come |
---|
918 | from reachability analysis. The target states in this case are the |
---|
919 | initial states of the FSM, and the objective of choosing a seed |
---|
920 | close to them is to reduce the length of the stem of a |
---|
921 | counterexample in the language emptiness check. However, any |
---|
922 | collection of sets that together cover all the states on the heap |
---|
923 | will work. If one is not concerned with a specific target, but |
---|
924 | rather with speed, then passing an array with just one component set |
---|
925 | to the constant one is preferable.] |
---|
926 | |
---|
927 | SideEffects [Updates the priority queue. The number of SCC examined |
---|
928 | (i.e., the number of chosen seeds) is added to sccExamined.] |
---|
929 | |
---|
930 | SeeAlso [Mc_FsmForEachFairScc] |
---|
931 | |
---|
932 | ******************************************************************************/ |
---|
933 | mdd_t * |
---|
934 | McFsmComputeOneFairSccByLockStep( |
---|
935 | Fsm_Fsm_t *fsm, |
---|
936 | Heap_t *priorityQueue, |
---|
937 | array_t *buechiFairness, |
---|
938 | array_t *onionRings, |
---|
939 | boolean earlyTermination, |
---|
940 | Mc_VerbosityLevel verbosity, |
---|
941 | Mc_DcLevel dcLevel, |
---|
942 | int *sccExamined) |
---|
943 | { |
---|
944 | mdd_t *mddOne, *SCC = NIL(mdd_t); |
---|
945 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
946 | int nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c); |
---|
947 | int nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c); |
---|
948 | array_t *careStatesArray = array_alloc(mdd_t *, 0); |
---|
949 | int totalSCCs = 0; |
---|
950 | boolean foundScc = FALSE; |
---|
951 | array_t *activeFairness = NIL(array_t); |
---|
952 | int firstActive = 0; |
---|
953 | |
---|
954 | /* Initialization. */ |
---|
955 | mddOne = mdd_one(mddManager); |
---|
956 | array_insert(mdd_t *, careStatesArray, 0, mddOne); |
---|
957 | |
---|
958 | while (Heap_HeapCount(priorityQueue)) { |
---|
959 | mdd_t *V, *seed, *B, *F, *fFront, *bFront, *fairSet; |
---|
960 | mdd_t *converged, *first, *second; |
---|
961 | long ringIndex; |
---|
962 | McLockstepMode firstMode, secondMode; |
---|
963 | int retval UNUSED = Heap_HeapExtractMin(priorityQueue, &V, &ringIndex); |
---|
964 | assert(retval && ringIndex < array_n(onionRings)); |
---|
965 | /* Here, V contains at least one nontrivial SCC. We then choose the |
---|
966 | * seed for a new SCC, which may turn out to be trivial. */ |
---|
967 | seed = LockstepPickSeed(fsm, V, buechiFairness, onionRings, ringIndex); |
---|
968 | |
---|
969 | if (earlyTermination == TRUE) { |
---|
970 | int i; |
---|
971 | activeFairness = array_alloc(mdd_t *, 0); |
---|
972 | for (i = 0; i < array_n(buechiFairness); i++) { |
---|
973 | mdd_t *fairSet = array_fetch(mdd_t *, buechiFairness, i); |
---|
974 | if (!mdd_lequal(seed, fairSet, 1, 1)) { |
---|
975 | array_insert_last(mdd_t *, activeFairness, fairSet); |
---|
976 | } |
---|
977 | } |
---|
978 | } |
---|
979 | |
---|
980 | /* Do lockstep search from seed. Leave the seed initially out of |
---|
981 | * F and B to facilitate the detection of trivial SCCs. Intersect |
---|
982 | * all results with V so that we can simplify the transition |
---|
983 | * relation. */ |
---|
984 | fFront = Mc_FsmEvaluateEYFormula(fsm, seed, mddOne, careStatesArray, |
---|
985 | verbosity, dcLevel); |
---|
986 | F = mdd_and(fFront, V, 1, 1); |
---|
987 | mdd_free(fFront); |
---|
988 | fFront = mdd_dup(F); |
---|
989 | bFront = Mc_FsmEvaluateEXFormula(fsm, seed, mddOne, careStatesArray, |
---|
990 | verbosity, dcLevel); |
---|
991 | B = mdd_and(bFront, V , 1, 1); |
---|
992 | mdd_free(bFront); |
---|
993 | bFront = mdd_dup(B); |
---|
994 | /* Go until the fastest search converges. */ |
---|
995 | while (!(mdd_is_tautology(fFront, 0) || mdd_is_tautology(bFront, 0))) { |
---|
996 | mdd_t *tmp; |
---|
997 | |
---|
998 | /* If the intersection of F and B intersects all fairness |
---|
999 | * constraints the union of F and B contains at least one fair |
---|
1000 | * SCC. Since the intersection of F and B is monotonically |
---|
1001 | * non-decreasing, once a fair set has been intersected, there |
---|
1002 | * is no need to check for it any more. */ |
---|
1003 | if (earlyTermination == TRUE) { |
---|
1004 | mdd_t * meet = mdd_and(F, B, 1, 1); |
---|
1005 | if (!mdd_is_tautology(meet, 0)) { |
---|
1006 | assert(mdd_lequal(meet, V, 1, 1)); |
---|
1007 | for ( ; firstActive < array_n(activeFairness); firstActive++) { |
---|
1008 | mdd_t *fairSet = array_fetch(mdd_t *, activeFairness, firstActive); |
---|
1009 | if (mdd_lequal(meet, fairSet, 1, 0)) break; |
---|
1010 | } |
---|
1011 | if (firstActive == array_n(activeFairness)) { |
---|
1012 | int i; |
---|
1013 | (void) fprintf(vis_stdout, "EARLY TERMINATION!\n"); |
---|
1014 | totalSCCs++; |
---|
1015 | /* A fair SCC is contained in the union of F, B, and seed. */ |
---|
1016 | tmp = mdd_or(F, B, 1, 1); |
---|
1017 | SCC = mdd_or(tmp, seed, 1, 1); |
---|
1018 | mdd_free(tmp); |
---|
1019 | /* Trim fair sets to guarantee counterexample will go through |
---|
1020 | * this SCC. */ |
---|
1021 | tmp = mdd_or(meet, seed, 1, 1); |
---|
1022 | mdd_free(meet); |
---|
1023 | meet = tmp; |
---|
1024 | for (i = 0; i < array_n(buechiFairness); i++) { |
---|
1025 | mdd_t *fairSet = array_fetch(mdd_t *, buechiFairness, i); |
---|
1026 | mdd_t *trimmed = mdd_and(fairSet, meet, 1, 1); |
---|
1027 | mdd_free(fairSet); |
---|
1028 | array_insert(mdd_t *, buechiFairness, i, trimmed); |
---|
1029 | } |
---|
1030 | mdd_free(meet); |
---|
1031 | mdd_free(F); mdd_free(B); |
---|
1032 | mdd_free(fFront); mdd_free(bFront); |
---|
1033 | mdd_free(seed); mdd_free(V); |
---|
1034 | foundScc = TRUE; |
---|
1035 | array_free(activeFairness); |
---|
1036 | goto cleanUp; |
---|
1037 | } |
---|
1038 | } |
---|
1039 | mdd_free(meet); |
---|
1040 | } |
---|
1041 | |
---|
1042 | /* Forward step. */ |
---|
1043 | tmp = Mc_FsmEvaluateEYFormula(fsm, fFront, mddOne, careStatesArray, |
---|
1044 | verbosity, dcLevel); |
---|
1045 | mdd_free(fFront); |
---|
1046 | fFront = mdd_and(tmp, F, 1, 0); |
---|
1047 | mdd_free(tmp); |
---|
1048 | tmp = mdd_and(fFront, V, 1, 1); |
---|
1049 | mdd_free(fFront); |
---|
1050 | fFront = tmp; |
---|
1051 | if (mdd_is_tautology(fFront, 0)) break; |
---|
1052 | tmp = mdd_or(F, fFront, 1, 1); |
---|
1053 | mdd_free(F); |
---|
1054 | F = tmp; |
---|
1055 | /* Backward step. */ |
---|
1056 | tmp = Mc_FsmEvaluateEXFormula(fsm, bFront, mddOne, careStatesArray, |
---|
1057 | verbosity, dcLevel); |
---|
1058 | mdd_free(bFront); |
---|
1059 | bFront = mdd_and(tmp, B, 1, 0); |
---|
1060 | mdd_free(tmp); |
---|
1061 | tmp = mdd_and(bFront, V, 1, 1); |
---|
1062 | mdd_free(bFront); |
---|
1063 | bFront = tmp; |
---|
1064 | tmp = mdd_or(B, bFront, 1, 1); |
---|
1065 | mdd_free(B); |
---|
1066 | B = tmp; |
---|
1067 | } |
---|
1068 | /* Complete the slower search within the converged one. */ |
---|
1069 | if (mdd_is_tautology(fFront, 0)) { |
---|
1070 | /* Forward search converged. */ |
---|
1071 | mdd_t *tmp = mdd_and(bFront, F, 1, 1); |
---|
1072 | mdd_free(bFront); |
---|
1073 | bFront = tmp; |
---|
1074 | mdd_free(fFront); |
---|
1075 | converged = mdd_dup(F); |
---|
1076 | /* The two sets to be enqueued come from a set that has been |
---|
1077 | * already trimmed. Hence, we want to remove the trivial SCCs |
---|
1078 | * left exposed at the rearguard of F, and the trivial SCCs left |
---|
1079 | * exposed at the vanguard of B. */ |
---|
1080 | firstMode = McLS_H_c; |
---|
1081 | secondMode = McLS_G_c; |
---|
1082 | while (!mdd_is_tautology(bFront, 0)) { |
---|
1083 | tmp = Mc_FsmEvaluateEXFormula(fsm, bFront, mddOne, |
---|
1084 | careStatesArray, verbosity, dcLevel); |
---|
1085 | mdd_free(bFront); |
---|
1086 | bFront = mdd_and(tmp, B, 1, 0); |
---|
1087 | mdd_free(tmp); |
---|
1088 | tmp = mdd_and(bFront, converged, 1, 1); |
---|
1089 | mdd_free(bFront); |
---|
1090 | bFront = tmp; |
---|
1091 | tmp = mdd_or(B, bFront, 1, 1); |
---|
1092 | mdd_free(B); |
---|
1093 | B = tmp; |
---|
1094 | } |
---|
1095 | mdd_free(bFront); |
---|
1096 | } else { |
---|
1097 | /* Backward search converged. */ |
---|
1098 | mdd_t *tmp = mdd_and(fFront, B, 1, 1); |
---|
1099 | mdd_free(fFront); |
---|
1100 | fFront = tmp; |
---|
1101 | mdd_free(bFront); |
---|
1102 | converged = mdd_dup(B); |
---|
1103 | firstMode = McLS_G_c; |
---|
1104 | secondMode = McLS_H_c; |
---|
1105 | while (!mdd_is_tautology(fFront, 0)) { |
---|
1106 | tmp = Mc_FsmEvaluateEYFormula(fsm, fFront, mddOne, |
---|
1107 | careStatesArray, verbosity, dcLevel); |
---|
1108 | mdd_free(fFront); |
---|
1109 | fFront = mdd_and(tmp, F, 1 ,0); |
---|
1110 | mdd_free(tmp); |
---|
1111 | tmp = mdd_and(fFront, converged, 1, 1); |
---|
1112 | mdd_free(fFront); |
---|
1113 | fFront = tmp; |
---|
1114 | tmp = mdd_or(F, fFront, 1, 1); |
---|
1115 | mdd_free(F); |
---|
1116 | F = tmp; |
---|
1117 | } |
---|
1118 | mdd_free(fFront); |
---|
1119 | } |
---|
1120 | |
---|
1121 | totalSCCs++; |
---|
1122 | SCC = mdd_and(F, B, 1, 1); |
---|
1123 | mdd_free(F); |
---|
1124 | mdd_free(B); |
---|
1125 | /* Check for fairness. If SCC is the empty set we know that seed |
---|
1126 | * is a trivial strong component; hence, it is not fair. */ |
---|
1127 | if (mdd_is_tautology(SCC, 0)) { |
---|
1128 | mdd_t *tmp = mdd_or(converged, seed, 1, 1); |
---|
1129 | mdd_free(converged); |
---|
1130 | converged = tmp; |
---|
1131 | mdd_free(SCC); |
---|
1132 | SCC = mdd_dup(seed); |
---|
1133 | } else { |
---|
1134 | /* Check fairness constraints. */ |
---|
1135 | int i; |
---|
1136 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
1137 | if (mdd_lequal(SCC, fairSet, 1, 0)) break; |
---|
1138 | } |
---|
1139 | if (i == array_n(buechiFairness)) { |
---|
1140 | /* All fairness conditions intersected. We have a fair SCC. */ |
---|
1141 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
1142 | array_t *PSvars = Fsm_FsmReadPresentStateVars(fsm); |
---|
1143 | fprintf(vis_stdout, "--SCC: found a fair SCC with %.0f states\n", |
---|
1144 | mdd_count_onset(mddManager, SCC, PSvars)); |
---|
1145 | /* (void) bdd_print_minterm(SCC); */ |
---|
1146 | } |
---|
1147 | foundScc = TRUE; |
---|
1148 | } |
---|
1149 | } |
---|
1150 | /* Divide the remaining states of V into the converged set minus |
---|
1151 | * the fair SCC, and the rest (minus the fair SCC). Add the two |
---|
1152 | * sets thus obtained to the priority queue. */ |
---|
1153 | mdd_free(seed); |
---|
1154 | first = mdd_and(converged, SCC, 1, 0); |
---|
1155 | LockstepQueueEnqueue(fsm, priorityQueue, first, onionRings, firstMode, |
---|
1156 | buechiFairness, verbosity, dcLevel); |
---|
1157 | second = mdd_and(V, converged, 1, 0); |
---|
1158 | mdd_free(converged); |
---|
1159 | mdd_free(V); |
---|
1160 | LockstepQueueEnqueue(fsm, priorityQueue, second, onionRings, secondMode, |
---|
1161 | buechiFairness, verbosity, dcLevel); |
---|
1162 | if (earlyTermination == TRUE) { |
---|
1163 | array_free(activeFairness); |
---|
1164 | } |
---|
1165 | if (foundScc == TRUE) break; |
---|
1166 | mdd_free(SCC); |
---|
1167 | } |
---|
1168 | |
---|
1169 | cleanUp: |
---|
1170 | mdd_free(mddOne); |
---|
1171 | array_free(careStatesArray); |
---|
1172 | if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) { |
---|
1173 | fprintf(vis_stdout, |
---|
1174 | "--SCC: found %s fair SCC out of %d examined\n", |
---|
1175 | foundScc ? "one" : "no", totalSCCs); |
---|
1176 | fprintf(vis_stdout, |
---|
1177 | "--SCC: %d image computations, %d preimage computations\n", |
---|
1178 | Img_GetNumberOfImageComputation(Img_Forward_c) - nImgComps, |
---|
1179 | Img_GetNumberOfImageComputation(Img_Backward_c) - nPreComps); |
---|
1180 | } |
---|
1181 | *sccExamined += totalSCCs; |
---|
1182 | return foundScc ? SCC : NIL(mdd_t); |
---|
1183 | |
---|
1184 | } /* McFsmComputeOneFairSccByLockStep */ |
---|
1185 | |
---|
1186 | |
---|
1187 | /*---------------------------------------------------------------------------*/ |
---|
1188 | /* Definition of internal functions */ |
---|
1189 | /*---------------------------------------------------------------------------*/ |
---|
1190 | |
---|
1191 | |
---|
1192 | /*---------------------------------------------------------------------------*/ |
---|
1193 | /* Definition of static functions */ |
---|
1194 | /*---------------------------------------------------------------------------*/ |
---|
1195 | |
---|
1196 | |
---|
1197 | /**Function******************************************************************** |
---|
1198 | |
---|
1199 | Synopsis [Returns a seed state for lockstep search.] |
---|
1200 | |
---|
1201 | Description [Returns a seed state for lockstep search, or NULL in |
---|
1202 | case of failure. The strategy is to first find the innermost ring |
---|
1203 | that intersects the given set of states (V) and one fairness |
---|
1204 | constraint. The other fairness constraints are then checked to |
---|
1205 | increase the number of fairness constraints that are satisfied by |
---|
1206 | the seed. The search is greedy.] |
---|
1207 | |
---|
1208 | SideEffects [none] |
---|
1209 | |
---|
1210 | SeeAlso [McFsmComputeOneFairSccByLockStep] |
---|
1211 | |
---|
1212 | ******************************************************************************/ |
---|
1213 | static mdd_t * |
---|
1214 | LockstepPickSeed( |
---|
1215 | Fsm_Fsm_t *fsm, |
---|
1216 | mdd_t *V, |
---|
1217 | array_t *buechiFairness, |
---|
1218 | array_t *onionRings, |
---|
1219 | int ringIndex) |
---|
1220 | { |
---|
1221 | mdd_t *seed; |
---|
1222 | int i, j; |
---|
1223 | |
---|
1224 | /* We know that there is at least one state in V from each fairness |
---|
1225 | * constraint. */ |
---|
1226 | for (i = ringIndex; i < array_n(onionRings); i++) { |
---|
1227 | mdd_t *ring = array_fetch(mdd_t *, onionRings, i); |
---|
1228 | for (j = 0; j < array_n(buechiFairness); j++) { |
---|
1229 | mdd_t *fairSet = array_fetch(mdd_t *, buechiFairness, j); |
---|
1230 | if (!mdd_lequal_mod_care_set(ring, fairSet, 1, 0, V)) { |
---|
1231 | mdd_t *tmp = mdd_and(V, ring, 1, 1); |
---|
1232 | mdd_t *candidates = mdd_and(tmp, fairSet, 1, 1); |
---|
1233 | mdd_free(tmp); |
---|
1234 | for (j++; j < array_n(buechiFairness); j++) { |
---|
1235 | fairSet = array_fetch(mdd_t *, buechiFairness, j); |
---|
1236 | if (!mdd_lequal(candidates, fairSet, 1, 0)) { |
---|
1237 | tmp = mdd_and(candidates, fairSet, 1, 1); |
---|
1238 | mdd_free(candidates); |
---|
1239 | candidates = tmp; |
---|
1240 | } |
---|
1241 | } |
---|
1242 | seed = Mc_ComputeAState(candidates, fsm); |
---|
1243 | mdd_free(candidates); |
---|
1244 | return seed; |
---|
1245 | } |
---|
1246 | } |
---|
1247 | } |
---|
1248 | |
---|
1249 | assert(FALSE); /* we should never get here */ |
---|
1250 | return NIL(bdd_t); |
---|
1251 | |
---|
1252 | } /* LockstepPickSeed */ |
---|
1253 | |
---|
1254 | |
---|
1255 | /**Function******************************************************************** |
---|
1256 | |
---|
1257 | Synopsis [Adds a set of states to the priority queue of the lockstep |
---|
1258 | algorithm.] |
---|
1259 | |
---|
1260 | Description [Given a set of states, applies trimming as specified by |
---|
1261 | mode. Checks then if the trimmed set may contain a fair SCC, in |
---|
1262 | which case it adds the set to the priority queue.] |
---|
1263 | |
---|
1264 | SideEffects [May change the set of states as a result of trimming. |
---|
1265 | The old set of states is freed.] |
---|
1266 | |
---|
1267 | SeeAlso [McFsmComputeOneFairSccByLockStep] |
---|
1268 | |
---|
1269 | ******************************************************************************/ |
---|
1270 | static void |
---|
1271 | LockstepQueueEnqueue( |
---|
1272 | Fsm_Fsm_t *fsm, |
---|
1273 | Heap_t *queue, |
---|
1274 | mdd_t *states, |
---|
1275 | array_t *onionRings, |
---|
1276 | McLockstepMode mode, |
---|
1277 | array_t *buechiFairness, |
---|
1278 | Mc_VerbosityLevel verbosity, |
---|
1279 | Mc_DcLevel dcLevel) |
---|
1280 | { |
---|
1281 | mdd_t *fairSet, *ring; |
---|
1282 | int i; |
---|
1283 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
1284 | mdd_t *mddOne = mdd_one(mddManager); |
---|
1285 | array_t *careStatesArray = array_alloc(mdd_t *, 0); |
---|
1286 | array_insert_last(mdd_t *, careStatesArray, mddOne); |
---|
1287 | |
---|
1288 | #ifndef SCC_NO_TRIM |
---|
1289 | if (mode == McLS_G_c || mode == McLS_GH_c) { |
---|
1290 | mdd_t *trimmed = Mc_FsmEvaluateEGFormula(fsm, states, NIL(mdd_t), mddOne, |
---|
1291 | NIL(Fsm_Fairness_t), |
---|
1292 | careStatesArray, |
---|
1293 | MC_NO_EARLY_TERMINATION, |
---|
1294 | NIL(array_t), |
---|
1295 | Mc_None_c, NIL(array_t *), |
---|
1296 | verbosity, dcLevel, NIL(boolean), |
---|
1297 | McGSH_EL_c); |
---|
1298 | mdd_free(states); |
---|
1299 | states = trimmed; |
---|
1300 | } |
---|
1301 | if (mode == McLS_H_c || mode == McLS_GH_c) { |
---|
1302 | mdd_t *trimmed = Mc_FsmEvaluateEHFormula(fsm, states, NIL(mdd_t), mddOne, |
---|
1303 | NIL(Fsm_Fairness_t), |
---|
1304 | careStatesArray, |
---|
1305 | MC_NO_EARLY_TERMINATION, |
---|
1306 | NIL(array_t), |
---|
1307 | Mc_None_c, NIL(array_t *), |
---|
1308 | verbosity, dcLevel, NIL(boolean), |
---|
1309 | McGSH_EL_c); |
---|
1310 | mdd_free(states); |
---|
1311 | states = trimmed; |
---|
1312 | } |
---|
1313 | #endif |
---|
1314 | |
---|
1315 | mdd_free(mddOne); |
---|
1316 | array_free(careStatesArray); |
---|
1317 | if (mode == McLS_none_c) { |
---|
1318 | mdd_t *range = mdd_range_mdd(mddManager, Fsm_FsmReadPresentStateVars(fsm)); |
---|
1319 | mdd_t *valid = mdd_and(states, range, 1, 1); |
---|
1320 | mdd_free(range); |
---|
1321 | mdd_free(states); |
---|
1322 | states = valid; |
---|
1323 | } |
---|
1324 | /* Discard set of states if it does not intersect all fairness conditions. */ |
---|
1325 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
1326 | if (mdd_lequal(states, fairSet, 1, 0)) { |
---|
1327 | mdd_free(states); |
---|
1328 | return; |
---|
1329 | } |
---|
1330 | } |
---|
1331 | /* Find the innermost onion ring intersecting the set of states. |
---|
1332 | * Its index is the priority of the set. */ |
---|
1333 | arrayForEachItem(mdd_t *, onionRings, i, ring) { |
---|
1334 | if (!mdd_lequal(states, ring, 1, 0)) break; |
---|
1335 | } |
---|
1336 | assert(i < array_n(onionRings)); |
---|
1337 | Heap_HeapInsert(queue,states,i); |
---|
1338 | return; |
---|
1339 | |
---|
1340 | } /* LockstepQueueEnqueue */ |
---|
1341 | |
---|
1342 | |
---|
1343 | /**Function******************************************************************** |
---|
1344 | |
---|
1345 | Synopsis [Adds a set of states to the priority queue of the lockstep |
---|
1346 | algorithm.] |
---|
1347 | |
---|
1348 | Description [Given a set of states, applies trimming as specified by |
---|
1349 | mode. Checks then if the trimmed set may contain a fair SCC, in |
---|
1350 | which case it adds the set to the priority queue.] |
---|
1351 | |
---|
1352 | SideEffects [May change the set of states as a result of trimming. |
---|
1353 | The old set of states is freed.] |
---|
1354 | |
---|
1355 | SeeAlso [McFsmComputeOneFairSccByLockStep] |
---|
1356 | |
---|
1357 | ******************************************************************************/ |
---|
1358 | static void |
---|
1359 | LinearstepQueueEnqueue( |
---|
1360 | Fsm_Fsm_t *fsm, |
---|
1361 | Heap_t *queue, |
---|
1362 | mdd_t *states, |
---|
1363 | mdd_t *spine, |
---|
1364 | mdd_t *node, |
---|
1365 | array_t *onionRings, |
---|
1366 | McLockstepMode mode, |
---|
1367 | array_t *buechiFairness, |
---|
1368 | Mc_VerbosityLevel verbosity, |
---|
1369 | Mc_DcLevel dcLevel) |
---|
1370 | { |
---|
1371 | mdd_t *fairSet, *ring; |
---|
1372 | mdd_t *tmp, *tmp1; |
---|
1373 | int i; |
---|
1374 | gns_t *gns; |
---|
1375 | mdd_manager *mddManager = Fsm_FsmReadMddManager(fsm); |
---|
1376 | mdd_t *mddOne = mdd_one(mddManager); |
---|
1377 | array_t *careStatesArray = array_alloc(mdd_t *, 0); |
---|
1378 | array_insert_last(mdd_t *, careStatesArray, mddOne); |
---|
1379 | |
---|
1380 | #ifndef SCC_NO_TRIM |
---|
1381 | if (mode == McLS_G_c || mode == McLS_GH_c) { |
---|
1382 | mdd_t *trimmed = Mc_FsmEvaluateEGFormula(fsm, states, NIL(mdd_t), mddOne, |
---|
1383 | NIL(Fsm_Fairness_t), |
---|
1384 | careStatesArray, |
---|
1385 | MC_NO_EARLY_TERMINATION, |
---|
1386 | NIL(array_t), |
---|
1387 | Mc_None_c, NIL(array_t *), |
---|
1388 | verbosity, dcLevel, NIL(boolean), |
---|
1389 | McGSH_EL_c); |
---|
1390 | mdd_free(states); |
---|
1391 | states = trimmed; |
---|
1392 | } |
---|
1393 | if (mode == McLS_H_c || mode == McLS_GH_c) { |
---|
1394 | mdd_t *trimmed = Mc_FsmEvaluateEHFormula(fsm, states, NIL(mdd_t), mddOne, |
---|
1395 | NIL(Fsm_Fairness_t), |
---|
1396 | careStatesArray, |
---|
1397 | MC_NO_EARLY_TERMINATION, |
---|
1398 | NIL(array_t), |
---|
1399 | Mc_None_c, NIL(array_t *), |
---|
1400 | verbosity, dcLevel, NIL(boolean), |
---|
1401 | McGSH_EL_c); |
---|
1402 | mdd_free(states); |
---|
1403 | states = trimmed; |
---|
1404 | } |
---|
1405 | #endif |
---|
1406 | |
---|
1407 | if (mode == McLS_none_c) { |
---|
1408 | mdd_t *range = mdd_range_mdd(mddManager, Fsm_FsmReadPresentStateVars(fsm)); |
---|
1409 | mdd_t *valid = mdd_and(states, range, 1, 1); |
---|
1410 | mdd_free(range); |
---|
1411 | mdd_free(states); |
---|
1412 | states = valid; |
---|
1413 | } |
---|
1414 | /* Discard set of states if it does not intersect all fairness conditions. */ |
---|
1415 | arrayForEachItem(mdd_t *, buechiFairness, i, fairSet) { |
---|
1416 | if (mdd_lequal(states, fairSet, 1, 0)) { |
---|
1417 | mdd_free(states); |
---|
1418 | mdd_free(mddOne); |
---|
1419 | array_free(careStatesArray); |
---|
1420 | return; |
---|
1421 | } |
---|
1422 | } |
---|
1423 | /* Find the innermost onion ring intersecting the set of states. |
---|
1424 | * Its index is the priority of the set. */ |
---|
1425 | arrayForEachItem(mdd_t *, onionRings, i, ring) { |
---|
1426 | if (!mdd_lequal(states, ring, 1, 0)) break; |
---|
1427 | } |
---|
1428 | assert(i < array_n(onionRings)); |
---|
1429 | |
---|
1430 | /* Trim the spine-set. */ |
---|
1431 | while ( !mdd_lequal(node, states, 1, 1) ) { |
---|
1432 | tmp = node; |
---|
1433 | tmp1 = Mc_FsmEvaluateEXFormula(fsm, node, mddOne, |
---|
1434 | careStatesArray, verbosity, dcLevel); |
---|
1435 | mdd_free(tmp); |
---|
1436 | node = mdd_and(tmp1, spine, 1, 1); |
---|
1437 | mdd_free(tmp1); |
---|
1438 | } |
---|
1439 | |
---|
1440 | tmp = spine; |
---|
1441 | spine = mdd_and(spine, states, 1, 1); |
---|
1442 | mdd_free(tmp); |
---|
1443 | |
---|
1444 | #if 0 |
---|
1445 | /* Invariants that should always hold */ |
---|
1446 | assert( mdd_is_tautology(node, 0) == mdd_is_tautology(spine, 0) ); |
---|
1447 | assert(mdd_lequal(node, states, 1, 1)); |
---|
1448 | assert(mdd_lequal(node, spine, 1, 1)); |
---|
1449 | assert(mdd_lequal(spine, states, 1, 1)); |
---|
1450 | #endif |
---|
1451 | |
---|
1452 | mdd_free(mddOne); |
---|
1453 | array_free(careStatesArray); |
---|
1454 | |
---|
1455 | gns = ALLOC(gns_t, 1); |
---|
1456 | gns->states = states; |
---|
1457 | gns->node = node; |
---|
1458 | gns->spine = spine; |
---|
1459 | |
---|
1460 | |
---|
1461 | Heap_HeapInsert(queue,gns,i); |
---|
1462 | return; |
---|
1463 | |
---|
1464 | } /* LinearstepQueueEnqueue */ |
---|
1465 | |
---|
1466 | |
---|
1467 | /**Function******************************************************************** |
---|
1468 | |
---|
1469 | Synopsis [Return the SCC enumeration method.] |
---|
1470 | |
---|
1471 | Description [Get the SCC enumeration method from the environment |
---|
1472 | setting scc_method. Return 0 if it is LockStep (default), 1 if it is |
---|
1473 | LinearStep. ] |
---|
1474 | |
---|
1475 | SideEffects [] |
---|
1476 | |
---|
1477 | SeeAlso [GetSccEnumerationMethod] |
---|
1478 | |
---|
1479 | ******************************************************************************/ |
---|
1480 | static int |
---|
1481 | GetSccEnumerationMethod( void ) |
---|
1482 | { |
---|
1483 | char *flagValue; |
---|
1484 | int linearStepMethod = 0; |
---|
1485 | |
---|
1486 | flagValue = Cmd_FlagReadByName("scc_method"); |
---|
1487 | if (flagValue != NIL(char)) { |
---|
1488 | if (strcmp(flagValue, "linearstep") == 0) |
---|
1489 | linearStepMethod = 1; |
---|
1490 | else if (strcmp(flagValue, "lockstep") == 0) |
---|
1491 | linearStepMethod = 0; |
---|
1492 | else { |
---|
1493 | fprintf(vis_stderr, "** scc error: invalid scc method %s, method lockstep is used. \n", |
---|
1494 | flagValue); |
---|
1495 | } |
---|
1496 | } |
---|
1497 | |
---|
1498 | return linearStepMethod; |
---|
1499 | } |
---|