VIS

src/mc/mcGFP.c

Go to the documentation of this file.
00001 
00024 #include "mcInt.h"
00025 
00026 
00027 /*---------------------------------------------------------------------------*/
00028 /* Constant declarations                                                     */
00029 /*---------------------------------------------------------------------------*/
00030 
00031 /*---------------------------------------------------------------------------*/
00032 /* Stucture declarations                                                     */
00033 /*---------------------------------------------------------------------------*/
00034 
00047 struct McGSHOpSetStruct {
00048   array_t *flags;               /* flag array for quick membership test */
00049   int cnt;                      /* number of operators in set */
00050   int last;                     /* last operator applied */
00051   int nextToLast;               /* next to last operator applied */
00052   int exBudget;                 /* allowed number of EXs in budget schedule */
00053   int exCount;                  /* EXs applied so far (EUs included) */
00054   Mc_GSHScheduleType schedule;  /* operator schedule */
00055 };
00056 
00057 
00058 /*---------------------------------------------------------------------------*/
00059 /* Type declarations                                                         */
00060 /*---------------------------------------------------------------------------*/
00061 
00062 typedef struct McGSHOpSetStruct McGSHOpSet_t;
00063 
00064 /*---------------------------------------------------------------------------*/
00065 /* Variable declarations                                                     */
00066 /*---------------------------------------------------------------------------*/
00067 
00068 #ifndef lint
00069 static char rcsid[] UNUSED = "$Id: mcGFP.c,v 1.10 2002/09/16 00:47:16 fabio Exp $";
00070 #endif
00071 
00072 /*---------------------------------------------------------------------------*/
00073 /* Macro declarations                                                        */
00074 /*---------------------------------------------------------------------------*/
00075 
00083 #define GSHoperatorIsEX(op,set) ((op) == (array_n((set)->flags) - 1))
00084 
00087 /*---------------------------------------------------------------------------*/
00088 /* Static function prototypes                                                */
00089 /*---------------------------------------------------------------------------*/
00090 
00091 static int PickOperatorForGSH ARGS((McGSHOpSet_t *set));
00092 static boolean ConvergedGSH ARGS((mdd_t *Z, mdd_t *zeta, int opIndex, McGSHOpSet_t *opSet, array_t *careStatesArray, Mc_EarlyTermination_t *earlyTermination, boolean *fixpoint));
00093 static McGSHOpSet_t * AllocOperatorSetGSH ARGS((int n, Mc_GSHScheduleType schedule));
00094 static void FreeOperatorSetGSH ARGS((McGSHOpSet_t *set));
00095 static void EmptyOperatorSetGSH ARGS((McGSHOpSet_t *set));
00096 static boolean IsMemberOperatorSetGSH ARGS((McGSHOpSet_t *set, int opIndex));
00097 static int SizeOperatorSetGSH ARGS((McGSHOpSet_t *set));
00098 static int PushOperatorSetGSH ARGS((McGSHOpSet_t *set, int opIndex));
00099 
00103 /*---------------------------------------------------------------------------*/
00104 /* Definition of internal functions                                          */
00105 /*---------------------------------------------------------------------------*/
00106 
00107 
00128 mdd_t*
00129 McFsmEvaluateEGFormulaUsingGSH(
00130   Fsm_Fsm_t *modelFsm,
00131   mdd_t *invariantMdd,
00132   mdd_t *overapprox,
00133   mdd_t *fairStates,
00134   Fsm_Fairness_t *modelFairness,
00135   array_t *careStatesArray,
00136   Mc_EarlyTermination_t *earlyTermination,
00137   array_t **pOnionRingsArrayForDbg,
00138   Mc_VerbosityLevel verbosity,
00139   Mc_DcLevel dcLevel,
00140   boolean *fixpoint,
00141   Mc_GSHScheduleType schedule)
00142 {
00143   int i,n;
00144   array_t *onionRings;
00145   boolean useRings;
00146   mdd_manager *mddManager;
00147   mdd_t *mddOne;
00148   mdd_t *iterate;
00149   array_t *buechiFairness;
00150   int nPreComps;
00151   int nIterations;
00152   McGSHOpSet_t *operatorSet;
00153 
00154   /* Here's how the pOnionRingsArrayForDbg works.  It is a pointer to
00155   ** an array of arrays of mdds.  There is one entry for every
00156   ** fairness constraint, and this entry is the array of the onion
00157   ** rings of the EU computation that corresponds to this constraint.
00158   ** Every time the EU for a given constraint is recomputed, the
00159   ** corresponding array of rings is renewed.  */
00160   assert(pOnionRingsArrayForDbg == NIL(array_t *) ||
00161          *pOnionRingsArrayForDbg == NIL(array_t) ||
00162          array_n(*pOnionRingsArrayForDbg) == 0);  
00163 
00164   useRings = (pOnionRingsArrayForDbg != NIL(array_t *) &&
00165               *pOnionRingsArrayForDbg != NIL(array_t));
00166 
00167   /* Initialization. */
00168   nIterations = 0;
00169   nPreComps = Img_GetNumberOfImageComputation(Img_Backward_c);
00170   onionRings = NIL(array_t);
00171   mddManager = Fsm_FsmReadMddManager(modelFsm);
00172   mddOne = mdd_one(mddManager);
00173 
00174   /* If an overapproxiamtion of the greatest fixpoint is given, use it. */
00175   if(overapprox != NIL(mdd_t)){
00176     iterate = mdd_and(invariantMdd, overapprox, 1, 1);
00177   } else {
00178     iterate = mdd_dup(invariantMdd);
00179   }
00180 
00181   /* See if we need to enter the loop at all.  If we wanted to test for
00182   ** early termination here, we should fix the onion rings. */
00183   if (mdd_is_tautology(iterate, 0)) {
00184     mdd_free(mddOne);
00185     if (fixpoint != NIL(boolean)) *fixpoint = mdd_is_tautology(iterate, 0);
00186     return(iterate);
00187   }
00188 
00189   /* Read fairness constraints. */
00190   buechiFairness = array_alloc(mdd_t *, 0);
00191   if (modelFairness != NIL(Fsm_Fairness_t)) {
00192     if (!Fsm_FairnessTestIsBuchi(modelFairness)) {
00193       (void) fprintf(vis_stdout,
00194                "** mc error: non-Buechi fairness constraints not supported\n");
00195       array_free(buechiFairness);
00196       mdd_free(iterate);
00197       mdd_free(mddOne);
00198 
00199       if (fixpoint != NIL(boolean)) *fixpoint = FALSE;
00200       return NIL(mdd_t);
00201     } else {
00202       int j;
00203       int numBuechi = Fsm_FairnessReadNumConjunctsOfDisjunct(modelFairness, 0);
00204       for (j = 0; j < numBuechi; j++) {
00205         mdd_t *tmpMdd = Fsm_FairnessObtainFinallyInfMdd(modelFairness, 0, j,
00206                                                 careStatesArray, dcLevel);
00207         array_insert_last(mdd_t *, buechiFairness, tmpMdd);
00208       }
00209     }
00210   } else {
00211     array_insert_last(mdd_t *, buechiFairness, mdd_one(mddManager));
00212   }
00213 
00214   /* Initialize set of disabled operators (to the empty set). */
00215   n = array_n(buechiFairness);
00216   operatorSet = AllocOperatorSetGSH(n, schedule);
00217 
00218   /* Iterate until all operators disabled or early termination. */
00219   while (TRUE) {
00220     mdd_t *oldIterate = iterate;
00221     int opIndex = PickOperatorForGSH(operatorSet);
00222     nIterations++;
00223     if (GSHoperatorIsEX(opIndex,operatorSet)) {
00224       mdd_t *EX = Mc_FsmEvaluateEXFormula(modelFsm, oldIterate, mddOne,
00225                                           careStatesArray, verbosity,
00226                                           dcLevel);
00227       iterate = mdd_and(EX, oldIterate, 1, 1);
00228       mdd_free(EX);
00229     } else {
00230       mdd_t *Fi = array_fetch(mdd_t *, buechiFairness, opIndex);
00231       mdd_t *target = mdd_and(Fi, iterate, 1, 1);
00232 
00233       /* Dispose of the old set of onion rings for this fairness constraint
00234       ** if it exists, and allocate a fresh array for a new set of rings. */
00235       if (useRings) {
00236         if (opIndex < array_n(*pOnionRingsArrayForDbg)) {
00237           onionRings = array_fetch(array_t *, *pOnionRingsArrayForDbg,
00238                                    opIndex);
00239           mdd_array_free(onionRings);
00240         }
00241         onionRings = array_alloc(mdd_t *, 0);
00242         array_insert(array_t *, *pOnionRingsArrayForDbg, opIndex, onionRings);
00243       }
00244 
00245       iterate = Mc_FsmEvaluateEUFormula(modelFsm, oldIterate, target,
00246                                         NIL(mdd_t), mddOne, careStatesArray,
00247                                         MC_NO_EARLY_TERMINATION, NIL(array_t),
00248                                         Mc_None_c, onionRings, verbosity,
00249                                         dcLevel, NIL(boolean));
00250       mdd_free(target);
00251     }
00252     if (ConvergedGSH(iterate, oldIterate, opIndex, operatorSet,
00253                      careStatesArray, earlyTermination, fixpoint)) {
00254       mdd_free(oldIterate);
00255       break;
00256     }
00257     mdd_free(oldIterate);
00258   }
00259 
00260   /* Free operator set. */
00261   FreeOperatorSetGSH(operatorSet);
00262 
00263   /* Sanity checks for onion rings and diagnostic prints. */
00264   if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) {
00265     if (useRings) {
00266       for (i = 0 ; i < array_n(*pOnionRingsArrayForDbg); i++) {
00267         int j;
00268         mdd_t *Fi = array_fetch(mdd_t *, buechiFairness, i);
00269         array_t *onionRings = array_fetch(array_t *, *pOnionRingsArrayForDbg,
00270                                           i);
00271         /* Early termination with random schedules may leave holes. */
00272         if (onionRings == NIL(array_t)) continue;
00273         for (j = 0; j < array_n(onionRings); j++) {
00274           mdd_t *ring = array_fetch(mdd_t *, onionRings, j);
00275           if (j == 0) {
00276             if (!mdd_lequal_mod_care_set_array(ring, Fi, 1, 1,
00277                                                careStatesArray)) {
00278               fprintf(vis_stderr, "** mc error: Problem w/ dbg in EG - ");
00279               fprintf(vis_stderr,
00280                       "inner most ring not in Fi (fairness constraint).\n");
00281             }
00282           }
00283           if (!mdd_lequal_mod_care_set_array(ring, invariantMdd, 1, 1,
00284                                              careStatesArray)) {
00285             fprintf(vis_stderr, "** mc error: Problem w/ dbg in EG - ");
00286             fprintf(vis_stderr, "onion ring of last EU fails invariant\n");
00287           }
00288         }
00289       }
00290     }
00291 
00292     if (verbosity == McVerbosityMax_c) {
00293       mdd_t *tmpMdd = careStatesArray ?
00294         mdd_and_array(iterate, careStatesArray, 1, 1) : mdd_dup(iterate);
00295       fprintf(vis_stdout,
00296               "--There are %.0f care states satisfying EG formula\n",
00297               mdd_count_onset(mddManager, tmpMdd,
00298                               Fsm_FsmReadPresentStateVars(modelFsm)));
00299 #ifdef DEBUG_MC
00300       /* The following 2 lines are just for debug. */
00301       fprintf(vis_stdout, "EG satisfying minterms :\n");
00302       (void)_McPrintSatisfyingMinterms(tmpMdd, modelFsm);
00303 #endif
00304       mdd_free(tmpMdd);
00305     } else {
00306       fprintf(vis_stdout, "--There are %.0f states satisfying EG formula\n",
00307               mdd_count_onset(mddManager, iterate,
00308                               Fsm_FsmReadPresentStateVars(modelFsm)));
00309     }
00310 
00311     fprintf(vis_stdout, "--EG: %d iterations, %d preimage computations\n",
00312             nIterations,
00313             Img_GetNumberOfImageComputation(Img_Backward_c) - nPreComps);
00314   }
00315 
00316   mdd_array_free(buechiFairness);
00317   mdd_free(mddOne);
00318 
00319   return iterate;
00320 
00321 } /* McFsmEvaluateEGFormulaUsingGSH */
00322 
00323 
00344 mdd_t*
00345 McFsmEvaluateEHFormulaUsingGSH(
00346   Fsm_Fsm_t *modelFsm,
00347   mdd_t *invariantMdd,
00348   mdd_t *overapprox,
00349   mdd_t *fairStates,
00350   Fsm_Fairness_t *modelFairness,
00351   array_t *careStatesArray,
00352   Mc_EarlyTermination_t *earlyTermination,
00353   array_t **pOnionRingsArrayForDbg,
00354   Mc_VerbosityLevel verbosity,
00355   Mc_DcLevel dcLevel,
00356   boolean *fixpoint,
00357   Mc_GSHScheduleType schedule)
00358 {
00359   int i,n;
00360   array_t *onionRings;
00361   boolean useRings;
00362   mdd_manager *mddManager;
00363   mdd_t *mddOne;
00364   mdd_t *iterate;
00365   array_t *buechiFairness;
00366   int nImgComps;
00367   int nIterations;
00368   McGSHOpSet_t *operatorSet;
00369 
00370   /* Here's how the pOnionRingsArrayForDbg works.  It is a pointer to
00371   ** an array of arrays of mdds.  There is one entry for every
00372   ** fairness constraint, and this entry is the array of the onion
00373   ** rings of the ES computation that corresponds to this constraint.
00374   ** Every time the ES for a given constraint is recomputed, the
00375   ** corresponding array of rings is renewed.  */
00376   assert(pOnionRingsArrayForDbg == NIL(array_t *) ||
00377          *pOnionRingsArrayForDbg == NIL(array_t) ||
00378          array_n(*pOnionRingsArrayForDbg) == 0);  
00379 
00380   useRings = (pOnionRingsArrayForDbg != NIL(array_t *) &&
00381               *pOnionRingsArrayForDbg != NIL(array_t));
00382 
00383   /* Initialization. */
00384   nIterations = 0;
00385   nImgComps = Img_GetNumberOfImageComputation(Img_Forward_c);
00386   onionRings = NIL(array_t);
00387   mddManager = Fsm_FsmReadMddManager(modelFsm);
00388   mddOne = mdd_one(mddManager);
00389 
00390   /* If an overapproxiamtion of the greatest fixpoint is given, use it. */
00391   if(overapprox != NIL(mdd_t)){
00392     iterate = mdd_and(invariantMdd, overapprox, 1, 1);
00393   } else {
00394     iterate = mdd_dup(invariantMdd);
00395   }
00396 
00397   /* See if we need to enter the loop at all. */
00398   if (mdd_is_tautology(iterate, 0) ||
00399     McCheckEarlyTerminationForOverapprox(earlyTermination,
00400                                          iterate, careStatesArray)) {
00401     mdd_free(mddOne);
00402 
00403     if (fixpoint != NIL(boolean)) *fixpoint = mdd_is_tautology(iterate, 0);
00404     return(iterate);
00405   }
00406 
00407   /* Read fairness constraints. */
00408   buechiFairness = array_alloc(mdd_t *, 0);
00409   if (modelFairness != NIL(Fsm_Fairness_t)) {
00410     if (!Fsm_FairnessTestIsBuchi(modelFairness)) {
00411       (void) fprintf(vis_stdout,
00412                "** mc error: non-Buechi fairness constraints not supported\n");
00413       array_free(buechiFairness);
00414       mdd_free(iterate);
00415       mdd_free(mddOne);
00416 
00417       if (fixpoint != NIL(boolean)) *fixpoint = FALSE;
00418       return NIL(mdd_t);
00419     } else {
00420       int j;
00421       int numBuechi = Fsm_FairnessReadNumConjunctsOfDisjunct(modelFairness, 0);
00422       for (j = 0; j < numBuechi; j++) {
00423         mdd_t *tmpMdd = Fsm_FairnessObtainFinallyInfMdd(modelFairness, 0, j,
00424                                                 careStatesArray, dcLevel);
00425         array_insert_last(mdd_t *, buechiFairness, tmpMdd);
00426       }
00427     }
00428   } else {
00429     array_insert_last(mdd_t *, buechiFairness, mdd_one(mddManager));
00430   }
00431 
00432   /* Initialize set of disabled operators (to the empty set). */
00433   n = array_n(buechiFairness);
00434   operatorSet = AllocOperatorSetGSH(n, schedule);
00435 
00436   /* Iterate until all operators disabled or early termination. */
00437   while (TRUE) {
00438     mdd_t *oldIterate = iterate;
00439     int opIndex = PickOperatorForGSH(operatorSet);
00440     nIterations++;
00441     if (GSHoperatorIsEX(opIndex,operatorSet)) {
00442       mdd_t *EY = Mc_FsmEvaluateEYFormula(modelFsm, oldIterate, mddOne,
00443                                           careStatesArray, verbosity,
00444                                           dcLevel);
00445       iterate = mdd_and(EY, oldIterate, 1, 1);
00446       mdd_free(EY);
00447     } else {
00448       mdd_t *Fi = array_fetch(mdd_t *, buechiFairness, opIndex);
00449       mdd_t *source = mdd_and(Fi, iterate, 1, 1);
00450 
00451       /* Dispose of the old set of onion rings for this fairness constraint
00452       ** if it exists, and allocate a fresh array for a new set of rings. */
00453       if (useRings) {
00454         if (opIndex < array_n(*pOnionRingsArrayForDbg)) {
00455           onionRings = array_fetch(array_t *, *pOnionRingsArrayForDbg,
00456                                    opIndex);
00457           mdd_array_free(onionRings);
00458         }
00459         onionRings = array_alloc(mdd_t *, 0);
00460         array_insert(array_t *, *pOnionRingsArrayForDbg, opIndex, onionRings);
00461       }
00462 
00463       iterate = Mc_FsmEvaluateESFormula(modelFsm, oldIterate, source,
00464                                         NIL(mdd_t), mddOne, careStatesArray,
00465                                         MC_NO_EARLY_TERMINATION, NIL(array_t),
00466                                         Mc_None_c, onionRings, verbosity,
00467                                         dcLevel, NIL(boolean));
00468       mdd_free(source);
00469     }
00470     if (ConvergedGSH(iterate, oldIterate, opIndex, operatorSet,
00471                      careStatesArray, earlyTermination, fixpoint)) {
00472       mdd_free(oldIterate);
00473       break;
00474     }
00475     mdd_free(oldIterate);
00476   }
00477 
00478   /* Free operator set. */
00479   FreeOperatorSetGSH(operatorSet);
00480 
00481   /* Sanity checks for onion rings and diagnostic prints. */
00482   if (verbosity == McVerbositySome_c || verbosity == McVerbosityMax_c) {
00483     if (useRings) {
00484       for (i = 0 ; i < array_n(*pOnionRingsArrayForDbg); i++) {
00485         int j;
00486         mdd_t *Fi = array_fetch(mdd_t *, buechiFairness, i);
00487         array_t *onionRings = array_fetch(array_t *, *pOnionRingsArrayForDbg,
00488                                           i);
00489         /* Early termination with random schedules may leave holes. */
00490         if (onionRings == NIL(array_t)) continue;
00491         for (j = 0; j < array_n(onionRings); j++) {
00492           mdd_t *ring = array_fetch(mdd_t *, onionRings, j);
00493           if (j == 0) {
00494             if (!mdd_lequal_mod_care_set_array(ring, Fi, 1, 1,
00495                                                careStatesArray)) {
00496               fprintf(vis_stderr, "** mc error: Problem w/ dbg in EH - ");
00497               fprintf(vis_stderr,
00498                       "inner most ring not in Fi (fairness constraint).\n");
00499             }
00500           }
00501           if (!mdd_lequal_mod_care_set_array(ring, invariantMdd, 1, 1,
00502                                              careStatesArray)) {
00503             fprintf(vis_stderr, "** mc error: Problem w/ dbg in EH - ");
00504             fprintf(vis_stderr, "onion ring of last ES fails invariant\n");
00505           }
00506         }
00507       }
00508     }
00509 
00510     if (verbosity == McVerbosityMax_c) {
00511       mdd_t *tmpMdd = careStatesArray ?
00512         mdd_and_array(iterate, careStatesArray, 1, 1) : mdd_dup(iterate);
00513       fprintf(vis_stdout,
00514               "--There are %.0f care states satisfying EH formula\n",
00515               mdd_count_onset(mddManager, tmpMdd,
00516                               Fsm_FsmReadPresentStateVars(modelFsm)));
00517 #ifdef DEBUG_MC
00518       /* The following 2 lines are just for debug. */
00519       fprintf(vis_stdout, "EH satisfying minterms :\n");
00520       (void)_McPrintSatisfyingMinterms(tmpMdd, modelFsm);
00521 #endif
00522       mdd_free(tmpMdd);
00523     } else {
00524       fprintf(vis_stdout, "--There are %.0f states satisfying EH formula\n",
00525               mdd_count_onset(mddManager, iterate,
00526                               Fsm_FsmReadPresentStateVars(modelFsm)));
00527     }
00528 
00529     fprintf(vis_stdout, "--EH: %d iterations, %d image computations\n",
00530             nIterations,
00531             Img_GetNumberOfImageComputation(Img_Forward_c) - nImgComps);
00532   }
00533 
00534   mdd_array_free(buechiFairness);
00535   mdd_free(mddOne);
00536 
00537   return iterate;
00538 
00539 } /* McFsmEvaluateEHFormulaUsingGSH */
00540 
00541 
00542 /*---------------------------------------------------------------------------*/
00543 /* Definition of static functions                                            */
00544 /*---------------------------------------------------------------------------*/
00545 
00546 
00558 static int
00559 PickOperatorForGSH(
00560   McGSHOpSet_t *set)
00561 {
00562   int nop = array_n(set->flags);
00563   int opIndex;
00564   if (set->schedule == McGSH_EL_c) {
00565     int exIndex = nop - 1;
00566     if ((set->last != exIndex) && !array_fetch(int, set->flags, exIndex)) {
00567       opIndex = exIndex;
00568     } else {
00569       if (set->last == exIndex) {
00570         opIndex = (set->nextToLast + 1) % exIndex;
00571       } else {
00572         opIndex = (set->last + 1) % exIndex;
00573       }
00574       while (array_fetch(int, set->flags, opIndex))
00575         opIndex = (opIndex + 1) % nop;
00576     }
00577     set->nextToLast = set->last;
00578   } else if (set->schedule == McGSH_EL1_c) {
00579     /* EL1 implements a round-robin policy. */
00580     opIndex = (set->last + 1) % nop;
00581     while (array_fetch(int, set->flags, opIndex))
00582       opIndex = (opIndex + 1) % nop;
00583   } else if (set->schedule == McGSH_EL2_c) {
00584     /* EL2 differs from EL1 in that it repeats EX to convergence.
00585      * We rely on the fact that EUs are always disabled after their
00586      * application. */
00587     opIndex = set->last;
00588     while (array_fetch(int, set->flags, opIndex))
00589       opIndex = (opIndex + 1) % nop;
00590   } else if (set->schedule == McGSH_Budget_c) {
00591     int exIndex = nop - 1;
00592     int newCount = Img_GetNumberOfImageComputation(Img_Backward_c);
00593     if (set->last == exIndex)
00594       set->exBudget--;
00595     else
00596       set->exBudget += newCount - set->exCount;
00597     set->exCount = newCount;
00598     /* (void) printf("budget = %d\n", set->exBudget); */
00599     if ((set->last != exIndex) && !array_fetch(int, set->flags, exIndex)) {
00600       /* At least one EX after each EU, unless EX is disabled */
00601       opIndex = exIndex;
00602       set->nextToLast = set->last;
00603     } else {
00604       if (set->last == exIndex) {
00605         if (set->exBudget > 0 && set->nextToLast == exIndex - 1) {
00606           opIndex = exIndex;
00607         } else {
00608           opIndex = (set->nextToLast + 1) % exIndex;
00609           set->nextToLast = set->last;
00610         }
00611       } else { /* EX is disabled */
00612         opIndex = (set->last + 1) % exIndex;
00613         set->nextToLast = set->last;
00614       }
00615       while (array_fetch(int, set->flags, opIndex))
00616         opIndex = (opIndex + 1) % nop;
00617     }
00618     if (opIndex == 0)
00619       set->exBudget = 0;
00620 #if 0
00621     opIndex = set->last;
00622     if (opIndex == exIndex && set->exBudget == 0)
00623       opIndex = 0;
00624     while (array_fetch(int, set->flags, opIndex))
00625       opIndex = (opIndex + 1) % nop;
00626 #endif
00627   } else {
00628     /* The random schedule uses a rather primitive way of selecting a
00629      * random integer.  However, as long as the number of operators is
00630      * small, the distribution is acceptably uniform even if we use
00631      * mod to map the result of util_random to 0 ... nop-1. */
00632     int exIndex = nop - 1;
00633     long rn = util_random();
00634     int exDisabled = array_fetch(int, set->flags, exIndex);
00635     if ((!exDisabled) && ((rn & 1024) || (set->cnt == exIndex))) {
00636       /* rn & 1024 should be true 50% of the times */
00637       opIndex = exIndex;
00638     } else {
00639       int enabledEUs = exIndex - (set->cnt - exDisabled);
00640       rn = rn % enabledEUs;
00641       assert(0 <= rn && rn < exIndex);
00642       for (opIndex = 0; TRUE; opIndex++) {
00643         assert(opIndex < exIndex);
00644         if (!array_fetch(int, set->flags, opIndex)) {
00645           if (rn == 0) {
00646             break;
00647           } else {
00648             rn--;
00649           }
00650         }
00651       }
00652     }
00653   }
00654   set->last = opIndex;
00655   return opIndex;
00656 
00657 } /* PickOperatorForGSH */
00658 
00659 
00676 static boolean
00677 ConvergedGSH(
00678   mdd_t *Z                      /* new iterate */,
00679   mdd_t *zeta                   /* old iterate */,
00680   int opIndex                   /* operator that has been just applied */,
00681   McGSHOpSet_t *opSet           /* set of disabled operators */,
00682   array_t *careStatesArray      /* array for care states */,
00683   Mc_EarlyTermination_t *earlyTermination /* early termination criterion */,
00684   boolean *fixpoint             /* reason for termination */)
00685 {
00686   boolean term_tautology = FALSE;
00687   boolean term_fixpoint = FALSE;
00688   boolean term_early = FALSE;
00689 
00690   term_tautology = mdd_is_tautology(Z, 0);
00691   if (!term_tautology)
00692     term_fixpoint =  mdd_equal_mod_care_set_array(Z, zeta, careStatesArray);
00693   if (!term_tautology && !term_fixpoint)
00694     term_early = McCheckEarlyTerminationForOverapprox(earlyTermination, Z, 
00695                                                       careStatesArray);
00696   if (term_tautology || term_early) {
00697     if (fixpoint != NIL(boolean))
00698       *fixpoint = term_tautology;
00699     return TRUE;
00700   } else if (term_fixpoint) {
00701     if (PushOperatorSetGSH(opSet,opIndex) == SizeOperatorSetGSH(opSet)) {
00702       if (fixpoint != NIL(boolean))
00703         *fixpoint = TRUE;
00704       return TRUE;
00705     } else {
00706       return FALSE;
00707     }
00708   } else {
00709     EmptyOperatorSetGSH(opSet);
00710     if (!GSHoperatorIsEX(opIndex,opSet)) {
00711       /* The operator is an EU.  Add to set. */
00712       (void) PushOperatorSetGSH(opSet,opIndex);
00713     }
00714     return FALSE;
00715   }
00716 
00717 } /* ConvergedGSH */
00718 
00719 
00731 static McGSHOpSet_t *
00732 AllocOperatorSetGSH(
00733   int n,
00734   Mc_GSHScheduleType schedule)
00735 {
00736   int i;
00737   McGSHOpSet_t *set = ALLOC(McGSHOpSet_t, 1);
00738   array_t *flags = set->flags = array_alloc(int, n+1);
00739   for (i = 0; i < n+1; i++) {
00740     array_insert(int, flags, i, 0);
00741   }
00742   set->cnt = 0;
00743   set->schedule = schedule;
00744   if (set->schedule == McGSH_EL_c) {
00745     set->last = n;
00746     set->nextToLast = n - 1;
00747   } else if (set->schedule == McGSH_EL1_c) {
00748     set->last = n;
00749   } else if (set->schedule == McGSH_EL2_c) {
00750     set->last = 0;
00751   } else if (set->schedule == McGSH_Budget_c) {
00752     set->last = n;
00753     set->nextToLast = n - 1;
00754     set->exBudget = 1;
00755     set->exCount = Img_GetNumberOfImageComputation(Img_Backward_c);
00756   } else {
00757     /* The random schedule has no history.  Hence, this initialization is
00758      * immaterial. */
00759     set->last = 0;
00760   }
00761   return set;
00762 
00763 } /* AllocOperatorSetGSH */
00764 
00765 
00777 static void
00778 FreeOperatorSetGSH(
00779   McGSHOpSet_t *set)
00780 {
00781   array_free(set->flags);
00782   FREE(set);
00783   return;
00784 
00785 } /* FreeOperatorSetGSH */
00786 
00787 
00801 static void
00802 EmptyOperatorSetGSH(
00803   McGSHOpSet_t *set)
00804 {
00805   int i;
00806   for (i = 0; i < array_n(set->flags); i++) {
00807     array_insert(int, set->flags, i, 0);
00808   }
00809   set->cnt = 0;
00810   return;
00811 
00812 } /* EmptyOperatorSetGSH */
00813 
00814 
00826 static boolean
00827 IsMemberOperatorSetGSH(
00828   McGSHOpSet_t *set,
00829   int opIndex)
00830 {
00831   return array_fetch(int, set->flags, opIndex);
00832 
00833 } /* IsMemberOperatorSetGSH */
00834 
00835 
00847 static int
00848 SizeOperatorSetGSH(
00849   McGSHOpSet_t *set)
00850 {
00851   return array_n(set->flags);
00852 
00853 } /* SizeOperatorSetGSH */
00854 
00855 
00867 static int
00868 PushOperatorSetGSH(
00869   McGSHOpSet_t *set,
00870   int opIndex)
00871 {
00872   assert(opIndex < array_n(set->flags));
00873   array_insert(int, set->flags, opIndex, 1);
00874   set->cnt++;
00875   return set->cnt;
00876 
00877 } /* PushOperatorSetGSH */