VIS

src/fsm/fsmHD.c

Go to the documentation of this file.
00001 
00076 #include "fsmInt.h"
00077 #include "bdd.h"
00078 #include "ntm.h"
00079 #include "img.h"
00080 
00081 static char rcsid[] UNUSED = "$Id: fsmHD.c,v 1.32 2005/05/16 06:23:29 fabio Exp $";
00082 
00083 /*---------------------------------------------------------------------------*/
00084 /* Constant declarations                                                     */
00085 /*---------------------------------------------------------------------------*/
00086 /* thresholds for computation */
00087 #define FSM_HD_DEADEND_RESIDUE_LIMIT 5000/*size beyond which residue is freed*/
00088 #define FSM_HD_FRONTIER_APPROX_THRESHOLD 3500 /* default frontier approximation
00089                                                  threshold */
00090 #define FSM_HD_REACHED_THRESHOLD  2000   /* Threshold below which reached is
00091                                          not decomposed */ 
00092 #define FSM_HD_DISJ_SIZE 5000            /* default Size of disjunct whose image
00093                             may be computed in dead end computation. */
00094 #define FSM_HD_DEADEND_MAX_SIZE_FACTOR 5 /* Factor such that when multiplied with
00095         the approx threshold will allow partitioning of the reached disjunct. */
00096 #define FSM_HD_FROM 0 /* Constant to indicate to subsetting method whether to use
00097                        * specified method or remap_ua */
00098 #define FSM_HD_DEADEND 1 /* Constant to indicate to subsetting method whether to use
00099                        * specified method or remap_ua */
00100 #define FSM_HD_MIN_SIZE_FROM 700 /* threshold to indicate not to subset if under this size */
00101 #define FSM_HD_DONT_FREE 0 /* flag to indicate that mdds should not be freed */
00102 #define FSM_HD_FREE 1 /* flag to indicate that mdds should be freed */
00103 #define FSM_HD_SP_THRESHOLD 2000 /* Threshold for short_paths method */
00104 
00105 /*---------------------------------------------------------------------------*/
00106 /* Type declarations                                                         */
00107 /*---------------------------------------------------------------------------*/
00108 typedef struct FsmHdSizeStruct FsmHdSizeStruct_t;
00109 
00110 /*---------------------------------------------------------------------------*/
00111 /* Structure declarations                                                    */
00112 /*---------------------------------------------------------------------------*/
00113 
00114 
00119 struct FsmHdSizeStruct {
00120   mdd_t *bdd;
00121   int size;
00122   long rnd;
00123 };
00124                   
00125 
00128 /*---------------------------------------------------------------------------*/
00129 /* Static function prototypes                                                */
00130 /*---------------------------------------------------------------------------*/
00131 
00132 static mdd_t * ComputeNewSeedsAtDeadEnd(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, mdd_t *reachableStates, FsmHdStruct_t *hdInfo, int greedy, int verbosity);
00133 static mdd_t * ComputeImageOfDecomposedParts(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, mdd_t *reachedSet, mdd_t *reachableStates, FsmHdStruct_t *hdInfo, int frontierApproxThreshold, int nvars, int *failedPartition, int greedy, int verbosity);
00134 static mdd_t * ProcessDisjunctsRecursive(mdd_manager *mddManager, Img_ImageInfo_t *imageInfo, mdd_t **reachedSet, mdd_t *reachableStates, FsmHdStruct_t *hdInfo, int frontierApproxThreshold, int nvars, int *failedPartition, int reachedSize, int greedy, int verbosity);
00135 static mdd_t * ComputeSubsetBasedOnMethod(mdd_t *fromBetween, mdd_t *fromLowerBound, FsmHdTravOptions_t *options, int fromOrDeadEnd);
00136 static mdd_t * AddStates(mdd_t *a, mdd_t *b, int freeA, int freeB);
00137 static mdd_t * SubtractStates(mdd_t *a, mdd_t *b, int freeA, int freeB);
00138 static int RandomCompare(const void *ptrX, const void *ptrY);
00139 
00143 /*---------------------------------------------------------------------------*/
00144 /* Definition of exported functions                                          */
00145 /*---------------------------------------------------------------------------*/
00146 
00164 FsmHdTravOptions_t *
00165 Fsm_FsmHdGetTravOptions(int nvars)
00166 {
00167   char *frontierApproxMethodString, *frontierApproxThresholdString;
00168   char *scrapStatesString;
00169   char *deadEndString, *qualityString;
00170   char *newOnlyString, *partialImageString, *deadEndSubsetMethodString;
00171   FsmHdTravOptions_t *options;
00172 
00173   if (nvars < 0) return NIL(FsmHdTravOptions_t);
00174   options = ALLOC(FsmHdTravOptions_t, 1);
00175   if (options == NIL(FsmHdTravOptions_t)) {
00176     return NIL(FsmHdTravOptions_t);
00177   }
00178 
00179   options->nvars = nvars;
00180   /* set defaults */
00181   options->frontierApproxMethod = BDD_APPROX_RUA;
00182   options->frontierApproxThreshold = FSM_HD_FRONTIER_APPROX_THRESHOLD;
00183   options->quality = 1.0;
00184   options->deadEnd = Fsm_Hd_DE_Con_c;
00185   options->deadEndSubsetMethod = BDD_APPROX_RUA;
00186   options->scrapStates = TRUE;
00187   options->newOnly = FALSE;
00188   options->onlyPartialImage = FALSE;
00189   options->qualityBias = 0.5;
00190   
00191   /*  method for subsetting reached, from */
00192   frontierApproxMethodString = Cmd_FlagReadByName("hd_frontier_approx_method");
00193   if (frontierApproxMethodString != NIL(char)) {
00194     if (strcmp(frontierApproxMethodString, "heavy_branch") == 0) {
00195       options->frontierApproxMethod = BDD_APPROX_HB;
00196     } else if (strcmp(frontierApproxMethodString, "short_paths") == 0) {
00197       options->frontierApproxMethod = BDD_APPROX_SP;
00198     } else if (strcmp(frontierApproxMethodString, "under_approx") == 0) {
00199       options->frontierApproxMethod = BDD_APPROX_UA;
00200     } else if (strcmp(frontierApproxMethodString, "remap_ua") == 0) {
00201       options->frontierApproxMethod = BDD_APPROX_RUA;
00202     } else if (strcmp(frontierApproxMethodString, "compress") == 0) {
00203       options->frontierApproxMethod = BDD_APPROX_COMP;
00204     } else if (strcmp(frontierApproxMethodString, "biased_rua") == 0) {
00205       options->frontierApproxMethod = BDD_APPROX_BIASED_RUA;
00206     }
00207   }
00208 
00209   /* threshold value */
00210   frontierApproxThresholdString = Cmd_FlagReadByName("hd_frontier_approx_threshold");
00211   if (frontierApproxThresholdString != NIL(char)) {
00212     options->frontierApproxThreshold = strtol(frontierApproxThresholdString,
00213                                            NULL, 10);
00214   }
00215   /* adjust threshold if too small */
00216   if ((options->frontierApproxMethod == BDD_APPROX_HB) ||
00217       (options->frontierApproxMethod == BDD_APPROX_SP) ||
00218       (options->frontierApproxMethod == BDD_APPROX_COMP)) {
00219     if (options->frontierApproxThreshold < FSM_HD_SP_THRESHOLD) {
00220       fprintf(vis_stdout, "** hd warning: Threshold too low, Correcting Frontier Approx Threshold to %d\n", FSM_HD_SP_THRESHOLD);
00221       options->frontierApproxThreshold =  FSM_HD_SP_THRESHOLD;
00222     }
00223   } else if (options->frontierApproxThreshold < 0) {
00224     fprintf(vis_stdout, "** hd warning: Threshold negative, Correcting Frontier Approx Threshold to 0\n");
00225     options->frontierApproxThreshold = FSM_HD_FRONTIER_APPROX_THRESHOLD;
00226   }
00227 
00228 
00229   /* quality option for remap_ua */
00230   qualityString = Cmd_FlagReadByName("hd_approx_quality");
00231   if (qualityString != NIL(char)) {
00232     options->quality = strtod(qualityString, NULL);
00233     if (options->quality < 0.0) {
00234       options->quality = 1.0;
00235     }
00236   }
00237 
00238   /* quality option for biased_rua */
00239   qualityString = Cmd_FlagReadByName("hd_approx_bias_quality");
00240   if (qualityString != NIL(char)) {
00241     options->qualityBias = strtod(qualityString, NULL);
00242     if (options->qualityBias < 0.0) {
00243       options->qualityBias = 0.5;
00244     }
00245   }
00246 
00247   /* method for dead end computations */
00248   deadEndString = Cmd_FlagReadByName("hd_dead_end");
00249   if (deadEndString != NIL(char)) {
00250     if (strcmp(deadEndString, "brute_force") == 0) {
00251       options->deadEnd = Fsm_Hd_DE_BF_c;
00252     } else if (strcmp(deadEndString, "conjuncts") == 0) {
00253       options->deadEnd = Fsm_Hd_DE_Con_c;
00254     } else if (strcmp(deadEndString, "hybrid") == 0) {
00255       options->deadEnd = Fsm_Hd_DE_Hyb_c;
00256     }
00257   }
00258   /*  method for subsetting reached, from during deadEnds*/
00259   deadEndSubsetMethodString = Cmd_FlagReadByName("hd_dead_end_approx_method");
00260   if (deadEndSubsetMethodString != NIL(char)) {
00261     if (strcmp(deadEndSubsetMethodString, "heavy_branch") == 0) {
00262       options->deadEndSubsetMethod = BDD_APPROX_HB;
00263     } else if (strcmp(deadEndSubsetMethodString, "short_paths") == 0) {
00264       options->deadEndSubsetMethod = BDD_APPROX_SP;
00265     } else if (strcmp(deadEndSubsetMethodString, "under_approx") == 0) {
00266       options->deadEndSubsetMethod = BDD_APPROX_UA;
00267     } else if (strcmp(deadEndSubsetMethodString, "remap_ua") == 0) {
00268       options->deadEndSubsetMethod = BDD_APPROX_RUA;
00269     } else if (strcmp(deadEndSubsetMethodString, "compress") == 0) {
00270       options->deadEndSubsetMethod = BDD_APPROX_COMP;
00271     }
00272   }
00273   /* option to not add blocking states */
00274   scrapStatesString = Cmd_FlagReadByName("hd_no_scrap_states");
00275   if (scrapStatesString != NIL(char)) {
00276     options->scrapStates = FALSE;
00277   }
00278 
00279   /* option to consider only new states instead of fromBetween */
00280   newOnlyString = Cmd_FlagReadByName("hd_new_only");
00281   if (newOnlyString != NIL(char)) {
00282     options->newOnly = TRUE;
00283   }
00284     
00285   /* perform approximate traversal with only partial images */
00286   partialImageString = Cmd_FlagReadByName("hd_only_partial_image");
00287   if (partialImageString != NIL(char)) {
00288     options->onlyPartialImage = TRUE;
00289   }
00290 
00291   return (options);
00292 } /* end of Fsm_FsmHdGetTraversalOptions */
00293 
00305 void
00306 Fsm_FsmHdFreeTravOptions(FsmHdTravOptions_t *options)
00307 {
00308   if (options) FREE(options);
00309   return;
00310 } /* end of Fsm_FsmHdFreeTravOptions */
00311 
00325 int
00326 Fsm_FsmHdOptionReadNumVars(FsmHdTravOptions_t *options)
00327 {
00328   if (options) return(options->nvars);
00329   else return 0;
00330 }
00331 
00345 int 
00346 Fsm_FsmHdOptionReadFrontierApproxThreshold(FsmHdTravOptions_t *options)
00347 {
00348   if (options) return (options->frontierApproxThreshold);
00349   else return 0;
00350 }
00351 
00365 boolean
00366 Fsm_FsmHdOptionReadOnlyPartialImage(FsmHdTravOptions_t *options)
00367 {
00368   if (options) return (options->onlyPartialImage);
00369   else return FALSE;
00370 }
00371 
00385 boolean
00386 Fsm_FsmHdOptionReadScrapStates(FsmHdTravOptions_t *options)
00387 {
00388   if (options) return (options->scrapStates);
00389   else return TRUE;
00390 }
00391 
00405 double
00406 Fsm_FsmHdOptionReadQuality(FsmHdTravOptions_t *options)
00407 {
00408   if (options) return(options->quality);
00409   else return 1.0;
00410 }
00411 
00425 bdd_approx_type_t
00426 Fsm_FsmHdOptionReadFrontierApproxMethod(FsmHdTravOptions_t *options)
00427 {
00428   if (options) return(options->frontierApproxMethod);
00429   else return BDD_APPROX_RUA;
00430 }
00431 
00445 Fsm_HdDeadEndType_t
00446 Fsm_FsmHdOptionReadDeadEnd(FsmHdTravOptions_t *options)
00447 {
00448   if (options) return(options->deadEnd);
00449   else return Fsm_Hd_DE_Con_c;
00450 }
00451 
00465 boolean
00466 Fsm_FsmHdOptionReadNewOnly(FsmHdTravOptions_t *options)
00467 {
00468   if (options) return(options->newOnly);
00469   else return FALSE;
00470 }
00471 
00485 bdd_approx_type_t
00486 Fsm_FsmHdOptionReadDeadEndSubsetMethod(FsmHdTravOptions_t *options)
00487 {
00488   if (options) return(options->deadEndSubsetMethod);
00489   else return BDD_APPROX_RUA;
00490 }
00491 
00507 int 
00508 Fsm_FsmHdOptionSetFrontierApproxThreshold(FsmHdTravOptions_t *options,
00509                                           int threshold)
00510 {
00511   if ((options->frontierApproxMethod == BDD_APPROX_HB) ||
00512       (options->frontierApproxMethod == BDD_APPROX_SP) ||
00513       (options->frontierApproxMethod == BDD_APPROX_COMP)) {
00514     if  (threshold < FSM_HD_SP_THRESHOLD) {
00515       fprintf(vis_stdout, "** hd warning: Threshold too low, Correcting Frontier Approx Threshold to %d\n", FSM_HD_SP_THRESHOLD);
00516       options->frontierApproxThreshold =  FSM_HD_SP_THRESHOLD;
00517       return 0;
00518     } else {
00519       options->frontierApproxThreshold = threshold;
00520       return 1;
00521     }
00522   } else if (threshold < 0) {
00523     fprintf(vis_stdout, "** hd warning: Threshold negative, Correcting Frontier Approx Threshold to 0\n");
00524     options->frontierApproxThreshold = FSM_HD_FRONTIER_APPROX_THRESHOLD;
00525     return 0;
00526   } else {
00527     options->frontierApproxThreshold = threshold;
00528     return 1;
00529   }
00530 }
00531 
00545 void
00546 Fsm_FsmHdOptionSetOnlyPartialImage(FsmHdTravOptions_t *options,
00547                                    boolean onlyPartial)
00548 {
00549   if (options) options->onlyPartialImage = onlyPartial;
00550   return;
00551 }
00552 
00566 void
00567 Fsm_FsmHdOptionSetScrapStates(FsmHdTravOptions_t *options, boolean scrapStates)
00568 {
00569   if (options) options->scrapStates = scrapStates;
00570   return;
00571 }
00572 
00587 void
00588 Fsm_FsmHdOptionSetQuality(FsmHdTravOptions_t *options, double quality)
00589 {
00590   if (quality > 0.0) 
00591     if (options) options->quality = quality;
00592   return;
00593 }
00594 
00608 void
00609 Fsm_FsmHdOptionSetFrontierApproxMethod(FsmHdTravOptions_t *options,
00610                                        bdd_approx_type_t approxMethod)
00611 {
00612   if (options) options->frontierApproxMethod = approxMethod;
00613   if ((options->frontierApproxMethod == BDD_APPROX_HB) ||
00614       (options->frontierApproxMethod == BDD_APPROX_SP) ||
00615       (options->frontierApproxMethod == BDD_APPROX_COMP)) {
00616     if  (options->frontierApproxThreshold < FSM_HD_SP_THRESHOLD) {
00617       fprintf(vis_stdout, "** hd warning: Threshold too low, Correcting Frontier Approx Threshold to %d\n", FSM_HD_SP_THRESHOLD);
00618       options->frontierApproxThreshold =  FSM_HD_SP_THRESHOLD;
00619       return;
00620     }
00621   } else if (options->frontierApproxThreshold < 0) {
00622     fprintf(vis_stdout, "** hd warning: Threshold negative, Correcting Frontier Approx Threshold to 0\n");
00623     options->frontierApproxThreshold = FSM_HD_FRONTIER_APPROX_THRESHOLD;
00624     return;
00625   }
00626 
00627   return;
00628 }
00629 
00643 void
00644 Fsm_FsmHdOptionSetDeadEnd(FsmHdTravOptions_t *options,
00645                           Fsm_HdDeadEndType_t deadEnd)
00646 {
00647   if (options) options->deadEnd = deadEnd;
00648   return;
00649 }
00650 
00664 void
00665 Fsm_FsmHdOptionSetNewOnly(FsmHdTravOptions_t *options, boolean newOnly)
00666 {
00667   if (options) options->newOnly = newOnly;
00668   return;
00669 }
00670 
00684 void
00685 Fsm_FsmHdOptionSetDeadEndSubsetMethod(FsmHdTravOptions_t *options,
00686                                       bdd_approx_type_t approxMethod)
00687 {
00688   if (options) options->deadEndSubsetMethod = approxMethod;
00689   return;
00690 }
00691 
00692 
00693 /*---------------------------------------------------------------------------*/
00694 /* Definition of internal functions                                          */
00695 /*---------------------------------------------------------------------------*/
00696 
00708 FsmHdMintSizeStats_t *
00709 FsmHdStatsStructAlloc(void)
00710 {
00711   FsmHdMintSizeStats_t *stats;
00712 
00713   stats = ALLOC(FsmHdMintSizeStats_t, 1);
00714   if (stats == NULL) return NULL;
00715 
00716   stats->sizeTo = 0;
00717   stats->mintermTo = 0.0;
00718   stats->sizeFrom = 0;
00719   stats->mintermFrom = 0.0;
00720   stats->sizeFromSubset = 0;
00721   stats->mintermFromSubset = 0.0;
00722   stats->sizeReached = 0;
00723   stats->mintermReached = 0.0;
00724   
00725   return stats;
00726 } /* end of FsmHdStatsStructAlloc */
00727 
00728 
00740 void
00741 FsmHdStatsStructFree(FsmHdMintSizeStats_t *stats)
00742 {
00743   FREE(stats);
00744   return;
00745 } /* end of FsmHdStatsStructFree */
00746 
00747 
00748 
00760 void
00761 FsmHdStatsComputeSizeAndMinterms(mdd_manager *mddManager,
00762                        mdd_t *f,
00763                        array_t *varArray,
00764                        int nvars,
00765                        Fsm_Hd_Quant_t field,
00766                        FsmHdMintSizeStats_t *stats)
00767 {
00768   int size;
00769   double minterms = 0.0;
00770   
00771   size = mdd_size(f);
00772   if (nvars <= 1023)
00773     minterms = mdd_count_onset(mddManager, f, varArray);
00774   
00775   switch (field) {
00776   case Fsm_Hd_From: {
00777     stats->sizeFrom = size;
00778     stats->mintermFrom = minterms; 
00779     break;
00780   }
00781   case Fsm_Hd_To: {
00782     stats->sizeTo = size;
00783     stats->mintermTo = minterms;
00784     break;
00785   }
00786   case Fsm_Hd_FromSubset: {
00787     stats->sizeFromSubset = size;
00788     stats->mintermFromSubset = minterms;
00789     break;
00790   }
00791   case Fsm_Hd_Reached: {
00792     stats->sizeReached = size;
00793     stats->mintermReached = minterms;
00794     break;
00795   }
00796   default: break;
00797   }
00798   return;
00799 } /* end of FsmHdStatsComputeSizeAndMinterms */
00800 
00811 void
00812 FsmHdStatsReset(FsmHdMintSizeStats_t *stats,
00813                 Fsm_Hd_Quant_t field)
00814 {
00815 
00816   switch (field) {
00817   case Fsm_Hd_To:
00818     stats->sizeTo = 0;
00819     stats->mintermTo = 0.0;
00820     break;
00821   case Fsm_Hd_From:
00822     stats->sizeFrom = 0;
00823     stats->mintermFrom = 0.0;
00824     break;
00825   case Fsm_Hd_FromSubset:
00826     stats->sizeFromSubset = 0;
00827     stats->mintermFromSubset = 0.0;
00828     break;
00829   case Fsm_Hd_Reached:
00830     stats->sizeReached = 0;
00831     stats->mintermReached = 0.0;
00832     break;
00833   }
00834   return;
00835 } /* end of FsmHdStatsReset */
00836 
00837 
00849 void
00850 FsmHdPrintOptions(void)
00851 {
00852   FsmHdTravOptions_t *options;
00853   char *dummy;
00854   options = Fsm_FsmHdGetTravOptions( 0);
00855   if (options == NIL(FsmHdTravOptions_t)) {
00856     fprintf(vis_stderr, "HD: Unalble to get options\n");
00857     return;
00858   }
00859 
00860   dummy = ALLOC(char, 20);
00861   if (dummy == NULL) return;
00862   switch (options->frontierApproxMethod) {
00863   case BDD_APPROX_HB: sprintf(dummy, "%s", "heavy_branch"); break;
00864   case BDD_APPROX_SP: sprintf(dummy, "%s", "short_paths"); break;
00865 
00866   case BDD_APPROX_UA: sprintf(dummy, "%s", "under_approx"); break;
00867   case BDD_APPROX_RUA: sprintf(dummy, "%s", "remap_ua"); break;
00868   case BDD_APPROX_BIASED_RUA: sprintf(dummy, "%s", "biased_rua"); break;
00869 
00870   case BDD_APPROX_COMP: sprintf(dummy, "%s", "compress"); break;
00871   default: sprintf(dummy, "%s", "remap_ua"); break;
00872   }
00873     
00874   fprintf(vis_stdout, "HD: Approx method for frontier subsets = %s\n", dummy);
00875   fprintf(vis_stdout, "HD: Threshold for frontier approximation = %d\n", options->frontierApproxThreshold);
00876   fprintf(vis_stdout, "HD: Quality option for approx methods = %g\n", options->quality);
00877   fprintf(vis_stdout, "HD: Bias quality option for the biased approx method = %g\n", options->qualityBias);
00878 
00879   switch (options->deadEnd) {
00880   case Fsm_Hd_DE_BF_c: sprintf(dummy, "%s", "brute_force"); break;
00881   case Fsm_Hd_DE_Con_c: sprintf(dummy, "%s", "conjuncts"); break;
00882   case Fsm_Hd_DE_Hyb_c: sprintf(dummy, "%s", "hybrid"); break;
00883   }
00884     
00885   fprintf(vis_stdout, "HD: Dead-End method = %s\n", dummy);
00886 
00887   switch (options->deadEndSubsetMethod) {
00888   case BDD_APPROX_HB: sprintf(dummy, "%s", "heavy_branch"); break;
00889   case BDD_APPROX_SP: sprintf(dummy, "%s", "short_paths"); break;
00890 
00891   case BDD_APPROX_UA: sprintf(dummy, "%s", "under_approx"); break;
00892   case BDD_APPROX_RUA: sprintf(dummy, "%s", "remap_ua"); break;
00893 
00894   case BDD_APPROX_COMP: sprintf(dummy, "%s", "compress"); break;
00895   default: sprintf(dummy, "%s", "remap_ua"); break;
00896   }
00897     
00898   fprintf(vis_stdout, "HD: Dead-end approx method = %s\n", dummy);
00899   FREE(dummy);
00900   
00901   fprintf(vis_stdout, "HD: Add scrap states option = ");
00902   if (options->scrapStates == TRUE) fprintf(vis_stdout, "yes\n");
00903   else fprintf(vis_stdout, "no\n");
00904 
00905   fprintf(vis_stdout, "HD: Only new states in frontier option = ");
00906   if (options->newOnly == TRUE) fprintf(vis_stdout, "yes\n");
00907   else fprintf(vis_stdout, "no\n");
00908 
00909   fprintf(vis_stdout, "HD: Only partial image option = ");
00910   if (options->onlyPartialImage == TRUE) fprintf(vis_stdout, "yes\n");
00911   else fprintf(vis_stdout, "no\n");
00912 
00913   Fsm_FsmHdFreeTravOptions(options);
00914   Img_ImagePrintPartialImageOptions();
00915   
00916   fprintf(vis_stdout, "See help page on print_hd_options for setting these options\n");
00917   return;
00918 
00919 } /* end of FsmHdPrintOptions */
00920 
00935 mdd_t *
00936 FsmHdDeadEnd(mdd_manager *mddManager,
00937              Img_ImageInfo_t *imageInfo,
00938              mdd_t *reachableStates,
00939              FsmHdStruct_t *hdInfo, 
00940              array_t *varArray,
00941              int greedy,
00942              int verbosity)
00943 {
00944   mdd_t *fromLowerBound;
00945   
00946   /* if residue is around to long, throw it away */
00947   if (hdInfo->residueCount >= 4) {
00948     if (hdInfo->deadEndResidue != NULL) {
00949       mdd_free(hdInfo->deadEndResidue);
00950       hdInfo->deadEndResidue = NULL;
00951     }
00952   }
00953       
00954   if ((hdInfo->deadEndResidue != NULL) && (greedy)) {
00955     /* dont compute new seeds out of dead end
00956      * if some states are left over from previous iterations.
00957      */
00958     fromLowerBound = hdInfo->deadEndResidue;
00959     hdInfo->deadEndResidue = NULL;
00960     assert(!mdd_is_tautology(fromLowerBound, 0));
00961     if (hdInfo->interiorStates != NIL(mdd_t))
00962       assert(mdd_lequal(fromLowerBound, hdInfo->interiorStates, 1, 0));
00963     if (verbosity >= 2) fprintf(vis_stdout, "Residue had new seeds\n");
00964     (hdInfo->residueCount)++;
00965   } else {
00966     /* compute new seeds by decomposing reachable states */
00967     if (hdInfo->deadEndResidue != NULL) {
00968       mdd_free(hdInfo->deadEndResidue);
00969       hdInfo->deadEndResidue = NULL;
00970     }
00971     hdInfo->residueCount = 0;
00972     fromLowerBound = ComputeNewSeedsAtDeadEnd(mddManager,
00973                                               imageInfo,
00974                                               reachableStates,
00975                                               hdInfo,
00976                                               greedy,
00977                                               verbosity);
00978 
00979   }
00980             
00981   /* mark that this is a dead end */
00982   hdInfo->deadEndComputation = TRUE;
00983 
00984   return (fromLowerBound);
00985 } /* end of FsmHdDeadEnd */
00986 
01021 void
01022 FsmHdFromComputeDenseSubset(mdd_manager *mddManager,
01023                             mdd_t **fromLowerBound,
01024                             mdd_t **fromUpperBound,
01025                             mdd_t **reachableStates,
01026                             mdd_t **image,
01027                             mdd_t *initialStates,
01028                             FsmHdStruct_t *hdInfo,
01029                             int shellFlag,
01030                             array_t *onionRings,
01031                             int sizeOfOnionRings,
01032                             array_t *varArray)
01033 {
01034 
01035   int thisTimeSubset;
01036   mdd_t *fromSubset, *fromBetween;
01037   mdd_t *temp, *temp1, *nonInteriorStates;
01038   float densityFrom = 0.0, densityFromSubset = 0.0; /* initialize to pacify */
01039   int numReorders;
01040   double mintResidue;
01041   int sizeResidue;
01042   int frontierApproxThreshold;
01043   int nvars;
01044   
01045   numReorders = bdd_read_reorderings(mddManager);
01046   frontierApproxThreshold = Fsm_FsmHdOptionReadFrontierApproxThreshold(hdInfo->options);
01047   nvars =  Fsm_FsmHdOptionReadNumVars(hdInfo->options);
01048 
01049    /* if image is bigger and smaller in size, switch. Add initial states.
01050    * Reset dead states since they are no longer valid.
01051    */
01052 
01053 #if 0 /* taken out for counterexamples  */
01054   if ((FsmHdStatsReadMintermReached(hdInfo->stats) <
01055        FsmHdStatsReadMintermTo(hdInfo->stats)) &&
01056       (FsmHdStatsReadSizeReached(hdInfo->stats) > FsmHdStatsReadSizeTo(hdInfo->stats))) {
01057     if (hdInfo->interiorStates != NIL(mdd_t)) mdd_free(hdInfo->interiorStates);
01058     hdInfo->interiorStates = bdd_zero(mddManager);
01059     bdd_free(*reachableStates);
01060     mdd_free(*fromUpperBound);
01061     *reachableStates = mdd_or(initialStates, *image, 1, 1);
01062     *reachableStates = AddStates(*fromLowerBound, *reachableStates,
01063                                  FSM_HD_DONT_FREE, FSM_HD_FREE);
01064     FsmHdStatsComputeSizeAndMinterms(mddManager, *reachableStates,
01065                              varArray, nvars, Fsm_Hd_Reached, hdInfo->stats);
01066     *fromUpperBound = mdd_dup(*reachableStates);
01067     if (shellFlag && *onionRings) {
01068       int onionRingCount;
01069       mdd_t *onionRing;
01070       fprintf(vis_stdout, "Onion Rings no longer valid. \n");
01071       arrayForEachItem(mdd_t *, *onionRings, onionRingCount, onionRing) {
01072         mdd_free(onionRing);
01073       }
01074       *onionRings = NIL(array_t);
01075     }
01076   }
01077 #endif  
01078 
01079   /* states which may produce new states as successors */
01080   nonInteriorStates = SubtractStates(*reachableStates, hdInfo->interiorStates,
01081                                      FSM_HD_DONT_FREE, FSM_HD_DONT_FREE);
01082 
01083   /* try and reinject the residue from a dead end into the frontier */
01084   if (hdInfo->deadEndResidue != NULL) {
01085     temp = mdd_or(*fromLowerBound, hdInfo->deadEndResidue, 1, 1);
01086   } else {
01087     temp = mdd_dup(*fromLowerBound);
01088   }
01089   /* calculate the actual "from" going to be used */
01090   if ( Fsm_FsmHdOptionReadNewOnly(hdInfo->options) == FALSE) {
01091     fromBetween = bdd_squeeze(temp, nonInteriorStates);
01092     mdd_free(temp);
01093   } else {
01094     fromBetween = temp;
01095   }
01096   mdd_free(nonInteriorStates);
01097 
01098   if (nvars <= 1023) {
01099     FsmHdStatsComputeSizeAndMinterms(mddManager, fromBetween,
01100                                      varArray, nvars,
01101                                      Fsm_Hd_From, hdInfo->stats);
01102   }
01103     
01104   /* if from is bigger in size than image, use image as from*/
01105   if (( Fsm_FsmHdOptionReadNewOnly(hdInfo->options) == FALSE) && (*image != NULL) &&
01106       (FsmHdStatsReadSizeTo(hdInfo->stats) < FsmHdStatsReadSizeFrom(hdInfo->stats))) {
01107     mdd_free(fromBetween);
01108     FsmHdStatsSetSizeFrom(hdInfo->stats, FsmHdStatsReadSizeTo(hdInfo->stats));
01109     FsmHdStatsSetMintermFrom(hdInfo->stats, FsmHdStatsReadMintermTo(hdInfo->stats));
01110     fromBetween = *image;
01111     *image = NULL;
01112   }
01113 
01114   /* free image since no longer required */
01115   if (*image != NULL) mdd_free(*image);
01116 
01117   assert(FsmHdStatsReadMintermFromSubset(hdInfo->stats) == 0.0);
01118   assert(FsmHdStatsReadSizeFromSubset(hdInfo->stats) == 0);
01119 
01120   /* flag to indicate whether a subset is computed this time */
01121   thisTimeSubset = 0;
01122 
01123   /* if size of from exceeds threshold, subset */
01124   if ((FsmHdStatsReadSizeFrom(hdInfo->stats) >  frontierApproxThreshold) &&
01125       (FsmHdStatsReadSizeFrom(hdInfo->stats) > FSM_HD_MIN_SIZE_FROM)) {
01126 
01127     /* get subset based on the different methods */
01128     fromSubset = ComputeSubsetBasedOnMethod(fromBetween,
01129                                             *fromLowerBound, hdInfo->options,
01130                                             FSM_HD_FROM);
01131     if (nvars <= 1023) {
01132       /* record stats */
01133       FsmHdStatsComputeSizeAndMinterms(mddManager, fromSubset,
01134                              varArray, nvars, 
01135                            Fsm_Hd_FromSubset, hdInfo->stats);
01136       /* compute density */
01137       densityFromSubset = FsmHdStatsReadDensityFromSubset(hdInfo->stats);
01138       densityFrom = FsmHdStatsReadDensityFrom(hdInfo->stats);
01139     }
01140                 
01141     /* check density of subset, discard the subset if not required*/
01142     if (((nvars <= 1023) &&
01143          (((densityFrom < densityFromSubset) ||
01144             (FsmHdStatsReadSizeFrom(hdInfo->stats) > 2*frontierApproxThreshold)))) ||
01145         ((nvars > 1023) &&
01146          ((bdd_apa_compare_ratios(nvars, fromSubset, fromBetween,
01147                                   FsmHdStatsReadSizeFromSubset(hdInfo->stats),
01148                                   FsmHdStatsReadSizeFrom(hdInfo->stats)) ||
01149             (FsmHdStatsReadSizeFrom(hdInfo->stats) > 2*frontierApproxThreshold))))) {
01150 
01151       /* subset chosen this time */
01152       thisTimeSubset = 1;
01153       
01154       mdd_free(fromBetween);
01155 
01156       /* discard the old bounds only if not required later */
01157       if (hdInfo->deadEndComputation || hdInfo->firstSubset) {
01158         /* store the residue since subset has been taken. Use them in
01159            subsequent iterations*/
01160         hdInfo->deadEndResidue = SubtractStates(*fromLowerBound, fromSubset,
01161                                          FSM_HD_DONT_FREE, FSM_HD_DONT_FREE);
01162         if(mdd_is_tautology(hdInfo->deadEndResidue, 0)) {
01163           mdd_free(hdInfo->deadEndResidue);
01164           hdInfo->deadEndResidue = NULL;
01165         } else if (mdd_size(hdInfo->deadEndResidue) > FSM_HD_DEADEND_RESIDUE_LIMIT) {
01166           mdd_free(hdInfo->deadEndResidue);
01167           hdInfo->deadEndResidue = NULL;
01168         } else {
01169           hdInfo->firstSubset = 0;
01170         }
01171                 
01172       }
01173       
01174       /* set from lower bound for next image computation */
01175       mdd_free(*fromLowerBound);
01176       *fromLowerBound = fromSubset;
01177                     
01178     }  else {
01179       /* discard the old bounds; since no subset is discarded */
01180       mdd_free(*fromLowerBound);
01181       /* Undo subset computation */
01182       mdd_free(fromSubset);
01183       *fromLowerBound = fromBetween;
01184     }
01185   } else {
01186     /* No subsetting here */
01187     mdd_free(*fromLowerBound);
01188     *fromLowerBound = fromBetween;
01189   }
01190 
01191   /* remove frontier from dead-end residue */
01192   if ((hdInfo->deadEndResidue != NULL) && (!hdInfo->deadEndComputation)) {
01193     hdInfo->deadEndResidue = SubtractStates(hdInfo->deadEndResidue, *fromLowerBound,
01194                                      FSM_HD_FREE, FSM_HD_DONT_FREE);
01195     if (mdd_is_tautology(hdInfo->deadEndResidue, 0)) {
01196       mdd_free(hdInfo->deadEndResidue);
01197       hdInfo->deadEndResidue = NULL;
01198     } else if (mdd_size(hdInfo->deadEndResidue) > FSM_HD_DISJ_SIZE) {
01199       mdd_free(hdInfo->deadEndResidue);
01200       hdInfo->deadEndResidue = NULL;
01201     }
01202   }
01203 
01204   /*
01205    * check size of reached if there were any reorderings since
01206    * the last time the size was measured
01207    */
01208   if (bdd_read_reorderings(mddManager)> numReorders) {
01209     FsmHdStatsSetSizeReached(hdInfo->stats, mdd_size(*reachableStates));
01210   }
01211   /* Modify Reachable states if necessary. The conditions are if
01212    * blocking states are not to be included in Reached. The exceptions
01213    * are if no subset was computed or the size of Reached is less than
01214    * 30000 or if this were a DEAD-END computation (very important:
01215    * this rule isnt violated). That is ALL states computed out of a
01216    * DEAD_END must ALWAYS be added to reached.
01217    */
01218   if (thisTimeSubset && (Fsm_FsmHdOptionReadScrapStates(hdInfo->options) == FALSE) &&
01219       (!hdInfo->deadEndComputation) && 
01220       (FsmHdStatsReadSizeReached(hdInfo->stats) > 30000)) {
01221     temp = AddStates(*fromUpperBound, *fromLowerBound,
01222                      FSM_HD_FREE, FSM_HD_DONT_FREE);
01223     temp1 = bdd_squeeze(temp, *reachableStates);
01224     mdd_free(*reachableStates);
01225     mdd_free(temp);
01226     *reachableStates = temp1;
01227     FsmHdStatsComputeSizeAndMinterms(mddManager, *reachableStates, varArray,
01228                            nvars, Fsm_Hd_Reached, hdInfo->stats);
01229     if (shellFlag && onionRings) { /* restrict the onion rings to the modified reachable set */
01230       int onionRingCount;
01231       for (onionRingCount = sizeOfOnionRings; onionRingCount < array_n(onionRings);
01232            onionRingCount++) {
01233         mdd_t *onionRing;
01234         onionRing = array_fetch(mdd_t *, onionRings, onionRingCount);
01235         temp = mdd_and(onionRing, *reachableStates, 1, 1);
01236         mdd_free(onionRing);
01237         array_insert(mdd_t *, onionRings, onionRingCount, temp);
01238       }
01239     }
01240 
01241   } else {
01242     mdd_free(*fromUpperBound);
01243   }
01244 
01245   /* Throw away dead-end residue when it gets to be a pain.
01246    * i.e., when its density is larger than Reached or when the
01247    * fraction of minterms retained in it are too small.
01248    */
01249   if (hdInfo->deadEndResidue != NULL) {
01250     mintResidue = mdd_count_onset(mddManager, hdInfo->deadEndResidue, varArray);
01251     sizeResidue = mdd_size(hdInfo->deadEndResidue);
01252     if ((mintResidue <  0.001*FsmHdStatsReadMintermReached(hdInfo->stats)) ||
01253         (mintResidue/sizeResidue > FsmHdStatsReadDensityReached(hdInfo->stats))) {
01254       mdd_free(hdInfo->deadEndResidue);
01255       hdInfo->deadEndResidue = NULL;
01256     }
01257   }
01258 
01259   /* set fromUpperBound for the next iteration */
01260   *fromUpperBound = *fromLowerBound;
01261   return;
01262 } /* end of FsmHdFromComputeDenseSubset */
01263 
01264  
01265 /*---------------------------------------------------------------------------*/
01266 /* Definition of static functions                                          */
01267 /*---------------------------------------------------------------------------*/
01268 
01291 static mdd_t *
01292 ComputeNewSeedsAtDeadEnd(mdd_manager *mddManager,
01293                          Img_ImageInfo_t *imageInfo,
01294                          mdd_t *reachableStates,
01295                          FsmHdStruct_t *hdInfo, 
01296                          int greedy,
01297                          int verbosity)
01298 {
01299   mdd_t *toCareSet, *newSeeds = NULL, *possibleSeeds, *temp;
01300   mdd_t *reachedSubset, *reachedSet;
01301   int failedPartition = 0;
01302   int frontierApproxThreshold =  Fsm_FsmHdOptionReadFrontierApproxThreshold(hdInfo->options);
01303   int deadEnd =  Fsm_FsmHdOptionReadDeadEnd(hdInfo->options);
01304   int nvars =  Fsm_FsmHdOptionReadNumVars(hdInfo->options);
01305   
01306   /* in brute force method, compute the image of the entire reached */
01307   if (deadEnd == Fsm_Hd_DE_BF_c) {
01308     toCareSet = mdd_not(reachableStates);
01309     possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01310                                                           reachableStates,
01311                                                           reachableStates,
01312                                                           toCareSet);
01313     mdd_free(toCareSet);
01314     newSeeds = SubtractStates(possibleSeeds, reachableStates,
01315                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01316     return (newSeeds);
01317   }
01318 
01319   /* in HYBRID method, first try with  a subset of the reached set */
01320   reachedSet = SubtractStates(reachableStates, hdInfo->interiorStates,
01321                             FSM_HD_DONT_FREE, FSM_HD_DONT_FREE);
01322   if (deadEnd ==  Fsm_Hd_DE_Hyb_c) {
01323     /* compute image of a subset of reached */
01324     reachedSubset = ComputeSubsetBasedOnMethod(reachedSet,
01325                                                NIL(mdd_t),
01326                                                hdInfo->options,
01327                                                FSM_HD_DEADEND);
01328                                                
01329     if (bdd_size(reachedSubset) < 2*frontierApproxThreshold) {
01330       toCareSet = mdd_not(reachableStates);
01331       possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01332                                                             reachedSubset,
01333                                                             reachableStates,
01334                                                             toCareSet);
01335       mdd_free(toCareSet);
01336       /* compute new states */
01337       newSeeds = SubtractStates(possibleSeeds, reachableStates,
01338                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01339       /* add to interior states */
01340       hdInfo->interiorStates = AddStates(hdInfo->interiorStates, reachedSubset,
01341                                   FSM_HD_FREE, FSM_HD_DONT_FREE);
01342       if (verbosity >= 2) {
01343         fprintf(vis_stdout, "Interior states added, Size = %d\n",
01344                 mdd_size(hdInfo->interiorStates));
01345       }
01346 
01347       if ((!mdd_is_tautology(newSeeds, 0)) && (greedy))  {
01348         mdd_free(reachedSet);
01349         mdd_free(reachedSubset);
01350         return (newSeeds);
01351       } else {
01352         /* reset newSeeds value for further computations */
01353         if (mdd_is_tautology(newSeeds, 0)) {
01354           mdd_free(newSeeds);
01355           newSeeds = NULL;
01356         }
01357         /* if new seeds not found or iter_decomp unsuccessful, set
01358          * reachedSet to the other part (which may be a part of the
01359          * reachable states (former) or the reachable states itself
01360          * (latter)).
01361          */
01362         reachedSet = SubtractStates(reachedSet, reachedSubset,
01363                                       FSM_HD_FREE, FSM_HD_FREE);
01364       }
01365     } else {
01366       mdd_free(reachedSubset);
01367     }
01368   }
01369   
01370   /* compute the decomposed image of reachedSet */
01371   if ((deadEnd == Fsm_Hd_DE_Con_c) ||
01372       (deadEnd == Fsm_Hd_DE_Hyb_c)) {
01373     /* this flag is set when the image of some decomposed part is
01374      * not computed due to its size.
01375      */
01376     failedPartition = 0;
01377     /* save any previously computed new states */
01378     temp = newSeeds;
01379     /* compute new seeds by recursively decomposing reachedSet */
01380     newSeeds = ComputeImageOfDecomposedParts(mddManager,
01381                                              imageInfo,
01382                                              reachedSet,
01383                                              reachableStates,
01384                                              hdInfo,
01385                                              frontierApproxThreshold,
01386                                              nvars,
01387                                              &failedPartition,
01388                                              greedy,
01389                                              verbosity);
01390     /* combine new states */
01391     newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01392 
01393     /* if no remains or partition didnt fail, return new Seeds */
01394     /* if greedy and new states found, return */
01395     if ((mdd_lequal(reachedSet, hdInfo->interiorStates, 1, 1)) ||
01396         ((newSeeds != NULL) && (greedy))) {
01397       /* assert that the entire image was computed */
01398       if (mdd_lequal(reachedSet, hdInfo->interiorStates, 1, 1)) assert(!failedPartition);
01399       mdd_free(reachedSet);
01400       if (newSeeds == NULL)
01401         newSeeds = bdd_zero(mddManager);
01402       else
01403         assert(!mdd_is_tautology(newSeeds, 0));
01404       return(newSeeds);
01405     }
01406 
01407     /* continue if either no new states have been found or the
01408      * computation is not greedy */
01409     /* new set whose image is to be computed  */
01410     reachedSet = SubtractStates(reachedSet, hdInfo->interiorStates,
01411                                 FSM_HD_FREE, FSM_HD_DONT_FREE);
01412     
01413     
01414     /* one last shot with a subsetting the remains */
01415     /* reachedSubset is the subset of reached remains */
01416     reachedSubset = ComputeSubsetBasedOnMethod(reachedSet,
01417                                                NIL(mdd_t),
01418                                                hdInfo->options,
01419                                                FSM_HD_DEADEND);
01420         
01421     /* compute image of the subset above */
01422     toCareSet = mdd_not(reachableStates);
01423     possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01424                                                           reachedSubset,
01425                                                           reachableStates,
01426                                                           toCareSet);
01427     mdd_free(toCareSet);
01428     /* add to interior states */
01429     hdInfo->interiorStates = AddStates(hdInfo->interiorStates, reachedSubset,
01430                                 FSM_HD_FREE, FSM_HD_FREE);
01431     if (verbosity >= 2) {
01432       fprintf(vis_stdout, "Interior states added, Size = %d\n",
01433               mdd_size(hdInfo->interiorStates));
01434     }
01435     /* combine all new states */
01436     temp = newSeeds;
01437     newSeeds = SubtractStates(possibleSeeds, reachableStates,
01438                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01439     newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01440 
01441     /* if no new seeds, compute the image of (reachedSet - reachedSubset) */
01442     if ((mdd_is_tautology(newSeeds, 0) != 1) && (greedy)) {
01443       mdd_free(reachedSet);
01444       mdd_free(reachedSubset);
01445       return newSeeds;
01446     } else {
01447       /* reset newSeeds for further computation */
01448       if (mdd_is_tautology(newSeeds, 0)) {
01449         mdd_free(newSeeds);
01450         newSeeds = NULL;
01451       }
01452       /* set reached = reachedSet - reachedSubset */
01453       reachedSet  = SubtractStates(reachedSet, reachedSubset,
01454                                    FSM_HD_FREE, FSM_HD_FREE);
01455     }
01456 
01457     /* save previously computed new states */
01458     temp = newSeeds;
01459     failedPartition = 0;
01460     /* try decomposition again */
01461     newSeeds = ComputeImageOfDecomposedParts(mddManager,
01462                                              imageInfo,
01463                                              reachedSet,
01464                                              reachableStates, hdInfo, 
01465                                              frontierApproxThreshold,
01466                                              nvars,
01467                                              &failedPartition,
01468                                              greedy,
01469                                              verbosity);
01470     /* combine all new states */
01471     newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01472     /* if no remains or partition didnt fail, return new Seeds */
01473     /* if greedy and new states found, return */
01474     if ((mdd_lequal(reachedSet, hdInfo->interiorStates, 1, 1)) ||
01475         ((newSeeds != NULL) && (greedy))) {
01476       /* assert that the entire image was computed */
01477       if (mdd_lequal(reachedSet, hdInfo->interiorStates, 1, 1)) assert(!failedPartition);
01478       mdd_free(reachedSet);
01479       if (newSeeds == NULL)
01480         newSeeds = bdd_zero(mddManager);
01481       else
01482         assert(!mdd_is_tautology(newSeeds, 0));
01483       return(newSeeds);
01484     }
01485 
01486     /* continue if either no new states have been found or the
01487      * computation is not greedy */
01488     /* new set whose image is to be computed  */
01489     reachedSet = SubtractStates(reachedSet, hdInfo->interiorStates,
01490                                 FSM_HD_FREE, FSM_HD_DONT_FREE);
01491     
01492     /* now bite the bullet and compute the image of the whole
01493      * remainder.
01494      */
01495     toCareSet = mdd_not(reachableStates);
01496     possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01497                                                           reachedSet,
01498                                                           reachableStates,
01499                                                           toCareSet);
01500     mdd_free(toCareSet);
01501     /* add to interios states */
01502     hdInfo->interiorStates = AddStates(hdInfo->interiorStates, reachedSet,
01503                                 FSM_HD_FREE, FSM_HD_FREE);
01504     if (verbosity >= 2) {
01505       fprintf(vis_stdout, "Interior states added, Size = %d\n",
01506               mdd_size(hdInfo->interiorStates));
01507     }
01508     /* combine all new states */
01509     temp = newSeeds;
01510     newSeeds = SubtractStates(possibleSeeds, reachableStates,
01511                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01512     newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01513 
01514   }
01515   return newSeeds;
01516 }
01517 
01518 
01534 static mdd_t *
01535 ComputeImageOfDecomposedParts(mdd_manager *mddManager,
01536                               Img_ImageInfo_t *imageInfo,
01537                               mdd_t *reachedSet,
01538                               mdd_t *reachableStates,
01539                               FsmHdStruct_t *hdInfo, 
01540                               int frontierApproxThreshold,
01541                               int nvars,
01542                               int *failedPartition,
01543                               int greedy,
01544                               int verbosity)
01545 {
01546 
01547   mdd_t *temp, *newSeeds, *possibleSeeds;
01548   mdd_t *toCareSet;
01549   int reachedSize, threshold;
01550     
01551   /* initialize some variables */
01552   newSeeds = NULL;
01553   reachedSize = mdd_size(reachedSet);
01554   threshold = (FSM_HD_REACHED_THRESHOLD > frontierApproxThreshold) ? FSM_HD_REACHED_THRESHOLD : frontierApproxThreshold;
01555 
01556   /* compute the image of reached if it is small */
01557   if (reachedSize < threshold) {
01558     toCareSet = mdd_not(reachableStates);
01559     possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01560                                                           reachedSet,
01561                                                           reachableStates,
01562                                                           toCareSet);
01563     mdd_free(toCareSet);
01564     newSeeds = SubtractStates(possibleSeeds, reachableStates,
01565                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01566     if (mdd_is_tautology(newSeeds, 0)) {
01567       mdd_free(newSeeds);
01568       newSeeds = NULL;
01569     }
01570     hdInfo->interiorStates = AddStates(hdInfo->interiorStates, reachedSet,
01571                                 FSM_HD_FREE, FSM_HD_DONT_FREE);
01572     return (newSeeds);
01573   }
01574 
01575   /* create conjuncts of the complement, disjuncts of the
01576    * reachable set
01577    */
01578   temp = mdd_dup(reachedSet);
01579   /* set threshold to some non-trivial value */
01580   if (frontierApproxThreshold <= 0)
01581     frontierApproxThreshold = FSM_HD_REACHED_THRESHOLD/
01582       FSM_HD_DEADEND_MAX_SIZE_FACTOR;
01583   /* compute the image of decomposed parts. Return when some new seeds are
01584    * found.
01585    */
01586   newSeeds = ProcessDisjunctsRecursive(mddManager,
01587                                        imageInfo,
01588                                        &temp,
01589                                        reachableStates,
01590                                        hdInfo, 
01591                                        frontierApproxThreshold,
01592                                        nvars,
01593                                        failedPartition,
01594                                        reachedSize,
01595                                        greedy,
01596                                        verbosity);
01597                                          
01598   return (newSeeds);
01599     
01600 }
01601 
01623 static mdd_t *
01624 ProcessDisjunctsRecursive(mdd_manager *mddManager,
01625                           Img_ImageInfo_t *imageInfo,
01626                           mdd_t **reachedSet,
01627                           mdd_t *reachableStates,
01628                           FsmHdStruct_t *hdInfo, 
01629                           int frontierApproxThreshold,
01630                           int nvars,
01631                           int *failedPartition,
01632                           int reachedSize,
01633                           int greedy,
01634                           int verbosity)
01635 {
01636   mdd_t *toCareSet, *newSeeds, *possibleSeeds;
01637   mdd_t *temp, *subset;
01638   int  tempSize;
01639   int hitConstant;
01640   mdd_t **disjArray;
01641   char *decompString;
01642   int i;
01643   int numParts;
01644   FsmHdSizeStruct_t sizeStruct;
01645   array_t *sizeArray;
01646   
01647   hitConstant = 0;
01648 
01649   assert((!mdd_is_tautology(*reachedSet, 1)) &&
01650          (!mdd_is_tautology(*reachedSet, 0)));
01651   if (verbosity >= 2) {
01652     fprintf(vis_stdout, "Orig Size = %d, ",mdd_size(*reachedSet));
01653   }
01654 
01655   /* decompose reached set into disjuntive parts */
01656   decompString = Cmd_FlagReadByName("hd_decomp");
01657   if (decompString == NIL(char)) {
01658     numParts = bdd_var_decomp(*reachedSet,
01659                                         (bdd_partition_type_t)BDD_DISJUNCTS,
01660                                         &disjArray);
01661   } else if (strcmp(decompString, "var") == 0) {
01662     numParts = bdd_var_decomp(*reachedSet,
01663                                         (bdd_partition_type_t)BDD_DISJUNCTS,
01664                                         &disjArray);
01665   } else if (strcmp(decompString, "gen") == 0) {
01666     numParts = bdd_gen_decomp(*reachedSet,
01667                                         (bdd_partition_type_t)BDD_DISJUNCTS,
01668                                         &disjArray);
01669   } else if (strcmp(decompString, "approx") == 0) {
01670     numParts = bdd_approx_decomp(*reachedSet,
01671                                            (bdd_partition_type_t)BDD_DISJUNCTS,
01672                                            &disjArray);
01673   } else if (strcmp(decompString, "iter") == 0) {
01674     numParts = bdd_iter_decomp(*reachedSet,
01675                                          (bdd_partition_type_t)BDD_DISJUNCTS,
01676                                          &disjArray);
01677   } else {
01678     numParts = bdd_var_decomp(*reachedSet,
01679                                         (bdd_partition_type_t)BDD_DISJUNCTS,
01680                                         &disjArray);
01681   }
01682   mdd_free(*reachedSet);
01683 
01684   /* decomposition failed */
01685   if (numParts == 0) return NULL;
01686 
01687   /* decomposition failed, stop recurring */
01688   if (numParts == 1) hitConstant = 1;
01689   
01690   /* allocate array with bdds and sizes */
01691   sizeArray = array_alloc(FsmHdSizeStruct_t,  0);  
01692   if (sizeArray == NIL(array_t)) {
01693     for (i = 0; i < numParts; i++) {
01694       mdd_free(disjArray[i]);
01695     }
01696     FREE(disjArray);
01697     return NULL;
01698   }
01699   
01700   /* free all constants and partitions that are larger than the
01701    * original reached size
01702    */
01703   for (i = 0; i < numParts; i++) {
01704     assert(!mdd_is_tautology(disjArray[i], 1));
01705     tempSize = bdd_size(disjArray[i]);
01706     if ((tempSize >= reachedSize) ||
01707         (tempSize == 1)) {
01708       if (tempSize == 1) {
01709         hitConstant = 1;
01710         assert (mdd_is_tautology(disjArray[i], 0));
01711       } else {
01712         *failedPartition = 1;
01713       }
01714       mdd_free(disjArray[i]);
01715     } else {
01716       sizeStruct.bdd = disjArray[i];
01717       sizeStruct.size = tempSize;
01718       sizeStruct.rnd = util_random();
01719       array_insert_last(FsmHdSizeStruct_t, sizeArray, sizeStruct);
01720     }
01721   }
01722   FREE(disjArray);
01723 
01724   if (array_n(sizeArray) == 0) {
01725     array_free(sizeArray);
01726     return (NULL);
01727   }
01728   
01729   /* shuffle parts randomly. */
01730   if (array_n(sizeArray) > 1) {
01731     array_sort(sizeArray, RandomCompare);
01732   } 
01733 
01734   if (verbosity >= 2) {
01735     arrayForEachItem(FsmHdSizeStruct_t, sizeArray, i, sizeStruct) {
01736       fprintf(vis_stdout , "disjSize[%d] = %d ", i, sizeStruct.size);
01737     }
01738     fprintf(vis_stdout, "\n");
01739   }
01740   
01741   /* now compute image of parts or recur*/
01742   newSeeds = NULL;
01743   arrayForEachItem(FsmHdSizeStruct_t, sizeArray, i, sizeStruct) {
01744     temp = NULL;
01745     if ((sizeStruct.size <
01746          frontierApproxThreshold*FSM_HD_DEADEND_MAX_SIZE_FACTOR) ||
01747         (sizeStruct.size < FSM_HD_DISJ_SIZE)) {
01748       /* if this partition is small enough, compute its image */
01749       /* compute image */
01750       toCareSet = mdd_not(reachableStates);
01751       possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01752                                                             sizeStruct.bdd,
01753                                                             reachableStates,
01754                                                             toCareSet); 
01755       mdd_free(toCareSet);
01756       /* update interior states */
01757       hdInfo->interiorStates = AddStates(hdInfo->interiorStates, sizeStruct.bdd,
01758                                   FSM_HD_FREE, FSM_HD_FREE);
01759       if (verbosity >= 2) {
01760         fprintf(vis_stdout, "Interior states added, Size = %d\n",
01761                 mdd_size(hdInfo->interiorStates));
01762       }
01763       /* store new states if any were already found */
01764       temp = newSeeds;
01765       /* compute new states of this image */
01766       newSeeds = SubtractStates(possibleSeeds, reachableStates,
01767                               FSM_HD_FREE, FSM_HD_DONT_FREE);
01768       /* add up states or set newSeeds to NULL if no new states */
01769       if (temp != NULL) {
01770         assert(!mdd_is_tautology(temp, 0));
01771         newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01772       } else if (mdd_is_tautology(newSeeds, 0) == 1) {
01773         mdd_free(newSeeds);
01774         newSeeds = NULL;
01775       } 
01776     } else if ((!hitConstant) && ((newSeeds == NULL) ||
01777                                   (!greedy) ||
01778                                   (sizeStruct.size < 3* FSM_HD_DISJ_SIZE))) {
01779       /* recur if size is small enough, or non-greedy computation or
01780        * no new states have been found yet. But not if a constant is hit. */
01781       /* store any new states already computed */
01782       temp = newSeeds;
01783       newSeeds = ProcessDisjunctsRecursive(mddManager,
01784                                            imageInfo,
01785                                            &(sizeStruct.bdd),
01786                                            reachableStates, hdInfo, 
01787                                            frontierApproxThreshold,
01788                                            nvars,
01789                                            failedPartition,
01790                                            reachedSize,
01791                                            greedy,
01792                                            verbosity);
01793       /* if new seeds not NULL, then not zero either */
01794       if (newSeeds != NULL) {
01795         assert(!mdd_is_tautology(newSeeds, 0));
01796         /* add states */
01797         if (temp != NULL) {
01798           newSeeds = AddStates(temp, newSeeds, FSM_HD_FREE, FSM_HD_FREE);
01799         }
01800       } else {
01801         newSeeds = temp;
01802       }
01803     } else {
01804       /* if this partition is too large, compute the image of its
01805        *  subset if the subset is small enough */
01806       /* set failed partition as image is not being computed of this
01807        *  whole part */
01808       *failedPartition = 1;
01809       /* compute subset */
01810       subset = bdd_approx_remap_ua(sizeStruct.bdd,
01811                                    (bdd_approx_dir_t)BDD_UNDER_APPROX,
01812                                    nvars, 0, 1.0);
01813       mdd_free(sizeStruct.bdd);
01814       tempSize = bdd_size(subset);
01815       /* compute image of subset if small enough */
01816       if ((tempSize < frontierApproxThreshold*FSM_HD_DEADEND_MAX_SIZE_FACTOR) ||
01817           (tempSize < FSM_HD_DISJ_SIZE)) {
01818         /* compute image */
01819         toCareSet = mdd_not(reachableStates);
01820         possibleSeeds = Img_ImageInfoComputeFwdWithDomainVars(imageInfo,
01821                                                               subset,
01822                                                               reachableStates,
01823                                                               toCareSet);
01824         mdd_free(toCareSet);
01825         /* update dead states */
01826         hdInfo->interiorStates = AddStates(hdInfo->interiorStates, subset,
01827                                     FSM_HD_FREE, FSM_HD_FREE);
01828         if (verbosity >= 2) {
01829           fprintf(vis_stdout, "Interior states added, Size = %d\n",
01830                   mdd_size(hdInfo->interiorStates));
01831         }
01832         /* store new states if any were already found */
01833         temp = newSeeds;
01834         /* compute new states of this image */
01835         newSeeds = SubtractStates(possibleSeeds, reachableStates,
01836                                 FSM_HD_FREE, FSM_HD_DONT_FREE);
01837         /* add up states or set newSeeds to NULL if no new states */
01838         if (temp != NULL) {
01839           assert(!mdd_is_tautology(temp, 0));
01840           newSeeds = AddStates(newSeeds, temp, FSM_HD_FREE, FSM_HD_FREE);
01841         } else if (mdd_is_tautology(newSeeds, 0) == 1) {
01842           mdd_free(newSeeds);
01843           newSeeds = NULL;
01844         }       
01845       } else {
01846         mdd_free(subset);
01847       }
01848     }
01849   } /* end of array for each */
01850 
01851   array_free(sizeArray);
01852                 
01853   return (newSeeds);
01854 
01855 } /* end of ProcessDisjunctsRecursive */
01856 
01857 
01858 
01871 static mdd_t *
01872 ComputeSubsetBasedOnMethod(mdd_t *fromBetween,
01873                            mdd_t *fromLowerBound,
01874                            FsmHdTravOptions_t *options,
01875                            int fromOrDeadEnd)
01876 {
01877   mdd_t *fromSubset;
01878   int frontierApproxThreshold =  Fsm_FsmHdOptionReadFrontierApproxThreshold(options);
01879   int frontierApproxMethod;
01880   double quality =  Fsm_FsmHdOptionReadQuality(options);
01881   int nvars =  Fsm_FsmHdOptionReadNumVars(options);
01882                              
01883   
01884   frontierApproxMethod = (fromOrDeadEnd == FSM_HD_FROM) ?
01885      Fsm_FsmHdOptionReadFrontierApproxMethod(options) :
01886     ((fromOrDeadEnd == FSM_HD_DEADEND) ?
01887       Fsm_FsmHdOptionReadDeadEndSubsetMethod(options) :
01888       Fsm_FsmHdOptionReadFrontierApproxMethod(options));
01889   
01890   /* based on approximation method specified, compute subset */
01891   switch (frontierApproxMethod) {
01892   case BDD_APPROX_HB:
01893     frontierApproxThreshold = (frontierApproxThreshold < FSM_HD_SP_THRESHOLD) ? FSM_HD_SP_THRESHOLD: frontierApproxThreshold;
01894     fromSubset = bdd_approx_hb(fromBetween,
01895                                (bdd_approx_dir_t)BDD_UNDER_APPROX,
01896                                nvars, frontierApproxThreshold);
01897     if (fromLowerBound != NIL(mdd_t)) {
01898       if (!bdd_equal(fromBetween,fromLowerBound))  {
01899         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01900           mdd_free(fromSubset);
01901           fromSubset = bdd_approx_hb(fromLowerBound,
01902                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01903                                      nvars, frontierApproxThreshold);
01904         }
01905       }
01906     }
01907                     
01908     break;
01909   case BDD_APPROX_SP:
01910     frontierApproxThreshold = (frontierApproxThreshold < FSM_HD_SP_THRESHOLD) ? FSM_HD_SP_THRESHOLD: frontierApproxThreshold;
01911     fromSubset = bdd_approx_sp(fromBetween,
01912                                (bdd_approx_dir_t)BDD_UNDER_APPROX,
01913                                nvars, frontierApproxThreshold,
01914                                0);
01915     if (fromLowerBound != NIL(mdd_t)) {
01916       if (!bdd_equal(fromBetween,fromLowerBound))  {
01917         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01918           mdd_free(fromSubset);
01919           fromSubset = bdd_approx_sp(fromLowerBound,
01920                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01921                                      nvars, frontierApproxThreshold,
01922                                      0);
01923         }
01924       }
01925     }
01926                     
01927     break;
01928   case BDD_APPROX_UA:
01929     fromSubset = bdd_approx_ua(fromBetween,
01930                                (bdd_approx_dir_t)BDD_UNDER_APPROX,
01931                                nvars, frontierApproxThreshold,
01932                                0, quality);
01933     if (fromLowerBound != NIL(mdd_t)) {
01934       if (!bdd_equal(fromBetween,fromLowerBound))  {
01935         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01936           mdd_free(fromSubset);
01937           fromSubset = bdd_approx_ua(fromLowerBound,
01938                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01939                                      nvars, frontierApproxThreshold,
01940                                      0, quality);
01941         }
01942       }
01943     }
01944     break;
01945   case BDD_APPROX_RUA:
01946     fromSubset = bdd_approx_remap_ua(fromBetween,
01947                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01948                                      nvars, frontierApproxThreshold,
01949                                      quality );
01950     if (fromLowerBound != NIL(mdd_t)) {
01951       if (!bdd_equal(fromBetween,fromLowerBound))  {
01952         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01953           mdd_free(fromSubset);
01954           fromSubset = bdd_approx_remap_ua(fromLowerBound,
01955                                            (bdd_approx_dir_t)BDD_UNDER_APPROX,
01956                                            nvars, frontierApproxThreshold,
01957                                            quality);
01958         }
01959       }
01960     }
01961                     
01962     break;
01963   case BDD_APPROX_BIASED_RUA:
01964     if (fromLowerBound == NIL(mdd_t)) {
01965       fromLowerBound = fromBetween;
01966     }
01967     fromSubset = bdd_approx_biased_rua(fromBetween,
01968                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01969                                        fromLowerBound,
01970                                        nvars, frontierApproxThreshold,
01971                                      quality, options->qualityBias );
01972     if (fromLowerBound != NIL(mdd_t)) {
01973       if (!bdd_equal(fromBetween,fromLowerBound))  {
01974         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01975           mdd_free(fromSubset);
01976           fromSubset = bdd_approx_remap_ua(fromLowerBound,
01977                                            (bdd_approx_dir_t)BDD_UNDER_APPROX,
01978                                            nvars, frontierApproxThreshold,
01979                                            quality);
01980         }
01981       }
01982     }
01983     break;
01984   case BDD_APPROX_COMP:
01985     frontierApproxThreshold = (frontierApproxThreshold < FSM_HD_SP_THRESHOLD) ? FSM_HD_SP_THRESHOLD: frontierApproxThreshold;
01986     fromSubset = bdd_approx_compress(fromBetween,
01987                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
01988                                      nvars, frontierApproxThreshold);
01989 
01990     if (fromLowerBound != NIL(mdd_t)) {
01991       if (!bdd_equal(fromBetween,fromLowerBound))  {
01992         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
01993           mdd_free(fromSubset);
01994           fromSubset = bdd_approx_compress(fromLowerBound,
01995                                            (bdd_approx_dir_t)BDD_UNDER_APPROX,
01996                                            nvars, frontierApproxThreshold);
01997         }
01998       }
01999     }
02000 
02001     break;
02002   default:
02003     fromSubset = bdd_approx_remap_ua(fromBetween,
02004                                      (bdd_approx_dir_t)BDD_UNDER_APPROX,
02005                                      nvars, frontierApproxThreshold,
02006                                      quality );
02007     if (fromLowerBound != NIL(mdd_t)) {
02008       if (!bdd_equal(fromBetween,fromLowerBound))  {
02009         if (mdd_lequal(fromSubset, fromLowerBound, 1, 0)) {
02010           mdd_free(fromSubset);
02011           fromSubset = bdd_approx_remap_ua(fromLowerBound,
02012                                            (bdd_approx_dir_t)BDD_UNDER_APPROX,
02013                                            nvars, frontierApproxThreshold,
02014                                            quality);
02015         }
02016       }
02017     }
02018     break;
02019   }
02020 
02021   return (fromSubset);
02022 } /* end of ComputeSubsetBasedOnMethod */
02023 
02024 
02034 static mdd_t *
02035 AddStates(mdd_t *a, mdd_t *b, int freeA, int freeB)
02036 {
02037   mdd_t *result;
02038   if ((a != NULL) && (b != NULL)) {
02039     result = mdd_or(a, b, 1, 1);
02040   } else if ((a == NULL) && (b == NULL)) {
02041     result = a;
02042   } else if (a == NULL) {
02043     result = mdd_dup(b);
02044   } else {
02045     result =  mdd_dup(a);
02046   }
02047   if ((freeA == FSM_HD_FREE) && (a != NULL))  mdd_free(a);
02048   if ((freeB == FSM_HD_FREE) && (b != NULL)) mdd_free(b);
02049   return result;
02050 } /* end of AddStates */
02051 
02052 
02053 
02063 static mdd_t *
02064 SubtractStates(mdd_t *a, mdd_t *b, int freeA, int freeB)
02065 {
02066   mdd_t *result;
02067   if ((a != NULL) && (b != NULL)) {
02068     result = mdd_and(a, b, 1, 0);
02069   } else if ((a == NULL) && (b == NULL)) {
02070     result = a;
02071   } else if (b == NULL) {
02072     result =  mdd_dup(a);
02073   } else { /* a = NULL , b != NULL */
02074     result = NULL;
02075   }
02076   if ((freeA == FSM_HD_FREE) && (a != NULL))  mdd_free(a);
02077   if ((freeB == FSM_HD_FREE) && (b != NULL)) mdd_free(b);
02078   return result;
02079 } /* end of SubtractStates */
02080 
02081 
02091 static int
02092 RandomCompare(const void *ptrX,
02093               const void *ptrY)
02094 {
02095   FsmHdSizeStruct_t *sizeStruct1 = (FsmHdSizeStruct_t *)ptrX;
02096   FsmHdSizeStruct_t *sizeStruct2 = (FsmHdSizeStruct_t *)ptrY;
02097 
02098   if (sizeStruct1->rnd > sizeStruct2->rnd) return 1;
02099   else if (sizeStruct1->rnd < sizeStruct2->rnd) return -1;
02100   else return 0;
02101 } /* end of BddSizeCompare */