00001 
00071 #include "util.h"
00072 #include "cuddInt.h"
00073 
00074 
00075 
00076 
00077 
00078 #define DEFAULT_PAGE_SIZE 2048 
00079 #define DEFAULT_NODE_DIST_PAGE_SIZE 2048 
00080 #define MAXSHORTINT     ((DdHalfWord) ~0) 
00081 
00082 
00083 
00084 
00085 #define INITIAL_PAGES 128 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 
00094 
00095 
00096 struct NodeDist{
00097     DdHalfWord oddTopDist;
00098     DdHalfWord evenTopDist;
00099     DdHalfWord oddBotDist;
00100     DdHalfWord evenBotDist;
00101     DdNode *regResult;
00102     DdNode *compResult;
00103 };
00104 
00105 
00106 struct AssortedInfo {
00107     unsigned int maxpath;
00108     int findShortestPath;
00109     int thresholdReached;
00110     st_table *maxpathTable;
00111     int threshold;
00112 };
00113 
00114 
00115 
00116 
00117 
00118 typedef struct NodeDist NodeDist_t;
00119 
00120 
00121 
00122 
00123 
00124 #ifndef lint
00125 static char rcsid[] DD_UNUSED = "$Id: cuddSubsetSP.c,v 1.34 2009/02/19 16:23:19 fabio Exp $";
00126 #endif
00127 
00128 #ifdef DD_DEBUG
00129 static int numCalls;
00130 static int hits;
00131 static int thishit;
00132 #endif
00133 
00134 
00135 static  int             memOut; 
00136 static  DdNode          *zero, *one; 
00137 
00138 static  NodeDist_t      **nodeDistPages; 
00139 static  int             nodeDistPageIndex; 
00140 static  int             nodeDistPage; 
00141 static  int             nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE; 
00142 static  int             maxNodeDistPages; 
00143 static  NodeDist_t      *currentNodeDistPage; 
00144 
00145 static  DdNode          ***queuePages; 
00146 static  int             queuePageIndex; 
00147 static  int             queuePage; 
00148 static  int             queuePageSize = DEFAULT_PAGE_SIZE; 
00149 static  int             maxQueuePages; 
00150 static  DdNode          **currentQueuePage; 
00151 
00152 
00153 
00154 
00155 
00156 
00157 #ifdef __cplusplus
00158 extern "C" {
00159 #endif
00160 
00163 
00164 
00165 
00166 
00167 static void ResizeNodeDistPages (void);
00168 static void ResizeQueuePages (void);
00169 static void CreateTopDist (st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp);
00170 static int CreateBotDist (DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp);
00171 static st_table * CreatePathTable (DdNode *node, unsigned int *pathLengthArray, FILE *fp);
00172 static unsigned int AssessPathLength (unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp);
00173 static DdNode * BuildSubsetBdd (DdManager *dd, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable);
00174 static enum st_retval stPathTableDdFree (char *key, char *value, char *arg);
00175 
00178 #ifdef __cplusplus
00179 }
00180 #endif
00181 
00182 
00183 
00184 
00185 
00186 
00215 DdNode *
00216 Cudd_SubsetShortPaths(
00217   DdManager * dd ,
00218   DdNode * f ,
00219   int  numVars ,
00220   int  threshold ,
00221   int  hardlimit )
00222 {
00223     DdNode *subset;
00224 
00225     memOut = 0;
00226     do {
00227         dd->reordered = 0;
00228         subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
00229     } while((dd->reordered ==1) && (!memOut));
00230 
00231     return(subset);
00232 
00233 } 
00234 
00235 
00267 DdNode *
00268 Cudd_SupersetShortPaths(
00269   DdManager * dd ,
00270   DdNode * f ,
00271   int  numVars ,
00272   int  threshold ,
00273   int  hardlimit )
00274 {
00275     DdNode *subset, *g;
00276 
00277     g = Cudd_Not(f);
00278     memOut = 0;
00279     do {
00280         dd->reordered = 0;
00281         subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
00282     } while((dd->reordered ==1) && (!memOut));
00283 
00284     return(Cudd_NotCond(subset, (subset != NULL)));
00285 
00286 } 
00287 
00288 
00289 
00290 
00291 
00292 
00293 
00311 DdNode *
00312 cuddSubsetShortPaths(
00313   DdManager * dd ,
00314   DdNode * f ,
00315   int  numVars ,
00316   int  threshold ,
00317   int  hardlimit )
00318 {
00319     st_table *pathTable;
00320     DdNode *N, *subset;
00321 
00322     unsigned int  *pathLengthArray;
00323     unsigned int maxpath, oddLen, evenLen, pathLength, *excess;
00324     int i;
00325     NodeDist_t  *nodeStat;
00326     struct AssortedInfo *info;
00327     st_table *subsetNodeTable;
00328 
00329     one = DD_ONE(dd);
00330     zero = Cudd_Not(one);
00331 
00332     if (numVars == 0) {
00333       
00334       numVars = Cudd_ReadSize(dd);
00335     }
00336 
00337     if (threshold > numVars) {
00338         threshold = threshold - numVars;
00339     }
00340     if (f == NULL) {
00341         fprintf(dd->err, "Cannot partition, nil object\n");
00342         dd->errorCode = CUDD_INVALID_ARG;
00343         return(NULL);
00344     }
00345     if (Cudd_IsConstant(f))
00346         return (f);
00347 
00348     pathLengthArray = ALLOC(unsigned int, numVars+1);
00349     for (i = 0; i < numVars+1; i++) pathLengthArray[i] = 0;
00350 
00351 
00352 #ifdef DD_DEBUG
00353     numCalls = 0;
00354 #endif
00355 
00356     pathTable = CreatePathTable(f, pathLengthArray, dd->err);
00357 
00358     if ((pathTable == NULL) || (memOut)) {
00359         if (pathTable != NULL)
00360             st_free_table(pathTable);
00361         FREE(pathLengthArray);
00362         return (NIL(DdNode));
00363     }
00364 
00365     excess = ALLOC(unsigned int, 1);
00366     *excess = 0;
00367     maxpath = AssessPathLength(pathLengthArray, threshold, numVars, excess,
00368                                dd->err);
00369 
00370     if (maxpath != (unsigned) (numVars + 1)) {
00371 
00372         info = ALLOC(struct AssortedInfo, 1);
00373         info->maxpath = maxpath;
00374         info->findShortestPath = 0;
00375         info->thresholdReached = *excess;
00376         info->maxpathTable = st_init_table(st_ptrcmp, st_ptrhash);
00377         info->threshold = threshold;
00378 
00379 #ifdef DD_DEBUG
00380         (void) fprintf(dd->out, "Path length array\n");
00381         for (i = 0; i < (numVars+1); i++) {
00382             if (pathLengthArray[i])
00383                 (void) fprintf(dd->out, "%d ",i);
00384         }
00385         (void) fprintf(dd->out, "\n");
00386         for (i = 0; i < (numVars+1); i++) {
00387             if (pathLengthArray[i])
00388                 (void) fprintf(dd->out, "%d ",pathLengthArray[i]);
00389         }
00390         (void) fprintf(dd->out, "\n");
00391         (void) fprintf(dd->out, "Maxpath  = %d, Thresholdreached = %d\n",
00392                        maxpath, info->thresholdReached);
00393 #endif
00394 
00395         N = Cudd_Regular(f);
00396         if (!st_lookup(pathTable, N, &nodeStat)) {
00397             fprintf(dd->err, "Something wrong, root node must be in table\n");
00398             dd->errorCode = CUDD_INTERNAL_ERROR;
00399             FREE(excess);
00400             FREE(info);
00401             return(NULL);
00402         } else {
00403             if ((nodeStat->oddTopDist != MAXSHORTINT) &&
00404                 (nodeStat->oddBotDist != MAXSHORTINT))
00405                 oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
00406             else
00407                 oddLen = MAXSHORTINT;
00408 
00409             if ((nodeStat->evenTopDist != MAXSHORTINT) &&
00410                 (nodeStat->evenBotDist != MAXSHORTINT))
00411                 evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
00412             else
00413                 evenLen = MAXSHORTINT;
00414 
00415             pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
00416             if (pathLength > maxpath) {
00417                 (void) fprintf(dd->err, "All computations are bogus, since root has path length greater than max path length within threshold %u, %u\n", maxpath, pathLength);
00418                 dd->errorCode = CUDD_INTERNAL_ERROR;
00419                 return(NULL);
00420             }
00421         }
00422 
00423 #ifdef DD_DEBUG
00424         numCalls = 0;
00425         hits = 0;
00426         thishit = 0;
00427 #endif
00428         
00429         if (hardlimit) {
00430             subsetNodeTable = st_init_table(st_ptrcmp, st_ptrhash);
00431         } else {
00432             subsetNodeTable = NIL(st_table);
00433         }
00434         subset = BuildSubsetBdd(dd, pathTable, f, info, subsetNodeTable);
00435         if (subset != NULL) {
00436             cuddRef(subset);
00437         }
00438         
00439 
00440 #ifdef DD_DEBUG
00441         (void) fprintf(dd->out, "Hits = %d, New==Node = %d, NumCalls = %d\n",
00442                 hits, thishit, numCalls);
00443 #endif
00444 
00445         if (subsetNodeTable != NIL(st_table)) {
00446             st_free_table(subsetNodeTable);
00447         }
00448         st_free_table(info->maxpathTable);
00449         st_foreach(pathTable, stPathTableDdFree, (char *)dd);
00450 
00451         FREE(info);
00452 
00453     } else {
00454         subset = f;
00455         cuddRef(subset);
00456     }
00457     FREE(excess);
00458     st_free_table(pathTable);
00459     FREE(pathLengthArray);
00460     for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
00461     FREE(nodeDistPages);
00462 
00463 #ifdef DD_DEBUG
00464     
00465     if (subset != NULL) {
00466         DdNode *check;
00467         check = Cudd_bddIteConstant(dd, subset, f, one);
00468         if (check != one) {
00469             (void) fprintf(dd->err, "Wrong partition\n");
00470             dd->errorCode = CUDD_INTERNAL_ERROR;
00471             return(NULL);
00472         }
00473     }
00474 #endif
00475 
00476     if (subset != NULL) {
00477         cuddDeref(subset);
00478         return(subset);
00479     } else {
00480         return(NULL);
00481     }
00482 
00483 } 
00484 
00485 
00486 
00487 
00488 
00489 
00490 
00507 static void
00508 ResizeNodeDistPages(void)
00509 {
00510     int i;
00511     NodeDist_t **newNodeDistPages;
00512 
00513     
00514     nodeDistPage++;
00515 
00516     
00517 
00518 
00519 
00520     if (nodeDistPage == maxNodeDistPages) {
00521         newNodeDistPages = ALLOC(NodeDist_t *,maxNodeDistPages + INITIAL_PAGES);
00522         if (newNodeDistPages == NULL) {
00523             for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
00524             FREE(nodeDistPages);
00525             memOut = 1;
00526             return;
00527         } else {
00528             for (i = 0; i < maxNodeDistPages; i++) {
00529                 newNodeDistPages[i] = nodeDistPages[i];
00530             }
00531             
00532             maxNodeDistPages += INITIAL_PAGES;
00533             FREE(nodeDistPages);
00534             nodeDistPages = newNodeDistPages;
00535         }
00536     }
00537     
00538     currentNodeDistPage = nodeDistPages[nodeDistPage] = ALLOC(NodeDist_t,
00539                                                               nodeDistPageSize);
00540     if (currentNodeDistPage == NULL) {
00541         for (i = 0; i < nodeDistPage; i++) FREE(nodeDistPages[i]);
00542         FREE(nodeDistPages);
00543         memOut = 1;
00544         return;
00545     }
00546     
00547     nodeDistPageIndex = 0;
00548     return;
00549 
00550 } 
00551 
00552 
00569 static void
00570 ResizeQueuePages(void)
00571 {
00572     int i;
00573     DdNode ***newQueuePages;
00574 
00575     queuePage++;
00576     
00577 
00578 
00579 
00580     if (queuePage == maxQueuePages) {
00581         newQueuePages = ALLOC(DdNode **,maxQueuePages + INITIAL_PAGES);
00582         if (newQueuePages == NULL) {
00583             for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
00584             FREE(queuePages);
00585             memOut = 1;
00586             return;
00587         } else {
00588             for (i = 0; i < maxQueuePages; i++) {
00589                 newQueuePages[i] = queuePages[i];
00590             }
00591             
00592             maxQueuePages += INITIAL_PAGES;
00593             FREE(queuePages);
00594             queuePages = newQueuePages;
00595         }
00596     }
00597     
00598     currentQueuePage = queuePages[queuePage] = ALLOC(DdNode *,queuePageSize);
00599     if (currentQueuePage == NULL) {
00600         for (i = 0; i < queuePage; i++) FREE(queuePages[i]);
00601         FREE(queuePages);
00602         memOut = 1;
00603         return;
00604     }
00605     
00606     queuePageIndex = 0;
00607     return;
00608 
00609 } 
00610 
00611 
00630 static void
00631 CreateTopDist(
00632   st_table * pathTable ,
00633   int  parentPage ,
00634   int  parentQueueIndex ,
00635   int  topLen ,
00636   DdNode ** childPage ,
00637   int  childQueueIndex ,
00638   int  numParents ,
00639   FILE *fp )
00640 {
00641     NodeDist_t *nodeStat;
00642     DdNode *N, *Nv, *Nnv, *node, *child, *regChild;
00643     int  i;
00644     int processingDone, childrenCount;
00645 
00646 #ifdef DD_DEBUG
00647     numCalls++;
00648 
00649     
00650     
00651     
00652     if ((queuePages[parentPage] == childPage) && (parentQueueIndex ==
00653                                                   childQueueIndex)) {
00654         fprintf(fp, "Should not happen that they are equal\n");
00655     }
00656     assert(queuePageIndex == childQueueIndex);
00657     assert(currentQueuePage == childPage);
00658 #endif
00659     
00660 
00661 
00662     childrenCount = 0;
00663     
00664     while (numParents) {
00665         numParents--;
00666         if (parentQueueIndex == queuePageSize) {
00667             parentPage++;
00668             parentQueueIndex = 0;
00669         }
00670         
00671         node = *(queuePages[parentPage] + parentQueueIndex);
00672         parentQueueIndex++;
00673         
00674         N = Cudd_Regular(node);
00675         Nv = Cudd_T(N);
00676         Nnv = Cudd_E(N);
00677 
00678         Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
00679         Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
00680 
00681         processingDone = 2;
00682         while (processingDone) {
00683             
00684 
00685 
00686             if (processingDone == 2) {
00687                 child = Nv;
00688             } else {
00689                 child = Nnv;
00690             }
00691 
00692             regChild = Cudd_Regular(child);
00693             
00694             if (!Cudd_IsConstant(child)) {
00695                 
00696 
00697 
00698                 if (!st_lookup(pathTable, regChild, &nodeStat)) {
00699                     
00700                     
00701                     if (nodeDistPageIndex == nodeDistPageSize)
00702                         ResizeNodeDistPages();
00703                     if (memOut) {
00704                         for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
00705                         FREE(queuePages);
00706                         st_free_table(pathTable);
00707                         return;
00708                     }
00709                     
00710                     nodeStat = currentNodeDistPage + nodeDistPageIndex;
00711                     nodeDistPageIndex++;
00712 
00713                     
00714                     nodeStat->oddTopDist = MAXSHORTINT;
00715                     nodeStat->evenTopDist = MAXSHORTINT;
00716                     nodeStat->evenBotDist = MAXSHORTINT;
00717                     nodeStat->oddBotDist = MAXSHORTINT;
00718                     nodeStat->regResult = NULL;
00719                     nodeStat->compResult = NULL;
00720                     
00721 
00722 
00723                     if (Cudd_IsComplement(child)) {
00724                         nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
00725                     } else {
00726                         nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
00727                     }
00728 
00729                     
00730                     if (st_insert(pathTable, (char *)regChild,
00731                                   (char *)nodeStat) == ST_OUT_OF_MEM) {
00732                         memOut = 1;
00733                         for (i = 0; i <= nodeDistPage; i++)
00734                             FREE(nodeDistPages[i]);
00735                         FREE(nodeDistPages);
00736                         for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
00737                         FREE(queuePages);
00738                         st_free_table(pathTable);
00739                         return;
00740                     }
00741 
00742                     
00743 
00744 
00745 
00746 
00747 
00748                     if (queuePageIndex == queuePageSize) ResizeQueuePages();
00749                     if (memOut) {
00750                         for (i = 0; i <= nodeDistPage; i++)
00751                             FREE(nodeDistPages[i]);
00752                         FREE(nodeDistPages);
00753                         st_free_table(pathTable);
00754                         return;
00755                     }
00756                     *(currentQueuePage + queuePageIndex) = child;
00757                     queuePageIndex++;
00758 
00759                     childrenCount++;
00760                 } else {
00761                     
00762                     
00763                     if (((Cudd_IsComplement(child)) && (nodeStat->oddTopDist ==
00764                           MAXSHORTINT)) || ((!Cudd_IsComplement(child)) &&
00765                                   (nodeStat->evenTopDist == MAXSHORTINT))) {
00766 
00767                         if (queuePageIndex == queuePageSize) ResizeQueuePages();
00768                         if (memOut) {
00769                             for (i = 0; i <= nodeDistPage; i++)
00770                                 FREE(nodeDistPages[i]);
00771                             FREE(nodeDistPages);
00772                             st_free_table(pathTable);
00773                             return;
00774 
00775                         }
00776                         *(currentQueuePage + queuePageIndex) = child;
00777                         queuePageIndex++;
00778 
00779                         
00780                         if (Cudd_IsComplement(child)) {
00781                             nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
00782                         } else {
00783                             nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
00784                         }
00785                         childrenCount++;
00786                     }
00787 
00788                 } 
00789             } 
00790             processingDone--;
00791         } 
00792     }  
00793 
00794 #ifdef DD_DEBUG
00795     assert(queuePages[parentPage] == childPage);
00796     assert(parentQueueIndex == childQueueIndex);
00797 #endif
00798 
00799     if (childrenCount != 0) {
00800         topLen++;
00801         childPage = currentQueuePage;
00802         childQueueIndex = queuePageIndex;
00803         CreateTopDist(pathTable, parentPage, parentQueueIndex, topLen,
00804                       childPage, childQueueIndex, childrenCount, fp);
00805     }
00806 
00807     return;
00808 
00809 } 
00810 
00811 
00831 static int
00832 CreateBotDist(
00833   DdNode * node ,
00834   st_table * pathTable ,
00835   unsigned int * pathLengthArray ,
00836   FILE *fp )
00837 {
00838     DdNode *N, *Nv, *Nnv;
00839     DdNode *realChild;
00840     DdNode *child, *regChild;
00841     NodeDist_t *nodeStat, *nodeStatChild;
00842     unsigned int  oddLen, evenLen, pathLength;
00843     DdHalfWord botDist;
00844     int processingDone;
00845 
00846     if (Cudd_IsConstant(node))
00847         return(1);
00848     N = Cudd_Regular(node);
00849     
00850     
00851 
00852     if (!st_lookup(pathTable, N, &nodeStat)) {
00853         fprintf(fp, "Something wrong, the entry doesn't exist\n");
00854         return(0);
00855     }
00856 
00857     
00858     if ((nodeStat->oddTopDist != MAXSHORTINT) &&
00859         (nodeStat->oddBotDist != MAXSHORTINT))
00860         oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
00861     else
00862         oddLen = MAXSHORTINT;
00863 
00864     
00865     if (!((nodeStat->evenTopDist == MAXSHORTINT) ||
00866           (nodeStat->evenBotDist == MAXSHORTINT)))
00867         evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
00868     else
00869         evenLen = MAXSHORTINT;
00870 
00871     
00872     pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
00873 
00874     Nv = Cudd_T(N);
00875     Nnv = Cudd_E(N);
00876 
00877     
00878     processingDone = 0;
00879     while (processingDone != 2) {
00880         if (!processingDone) {
00881             child = Nv;
00882         } else {
00883             child = Nnv;
00884         }
00885 
00886         realChild = Cudd_NotCond(child, Cudd_IsComplement(node));
00887         regChild = Cudd_Regular(child);
00888         if (Cudd_IsConstant(realChild)) {
00889             
00890 
00891 
00892             if (Cudd_IsComplement(child))
00893                 nodeStat->oddBotDist = 1;
00894             else
00895                 nodeStat->evenBotDist = 1;
00896         } else {
00897             
00898             if (!st_lookup(pathTable, regChild, &nodeStatChild)) {
00899                 fprintf(fp, "Something wrong, node in table should have been created in top dist proc.\n");
00900                 return(0);
00901             }
00902 
00903             if (nodeStatChild->oddBotDist == MAXSHORTINT) {
00904                 if (nodeStatChild->evenBotDist == MAXSHORTINT) {
00905                     if (!CreateBotDist(realChild, pathTable, pathLengthArray, fp))
00906                         return(0);
00907                 } else {
00908                     fprintf(fp, "Something wrong, both bot nodeStats should be there\n");
00909                     return(0);
00910                 }
00911             }
00912 
00913             
00914 
00915 
00916             if (Cudd_IsComplement(child)) {
00917                 
00918 
00919 
00920 
00921 
00922 
00923                 if (nodeStatChild->oddBotDist != MAXSHORTINT)
00924                     botDist = nodeStatChild->oddBotDist + 1;
00925                 else
00926                     botDist = MAXSHORTINT;
00927                 if (nodeStat->evenBotDist > botDist )
00928                     nodeStat->evenBotDist = botDist;
00929 
00930                 if (nodeStatChild->evenBotDist != MAXSHORTINT)
00931                     botDist = nodeStatChild->evenBotDist + 1;
00932                 else
00933                     botDist = MAXSHORTINT;
00934                 if (nodeStat->oddBotDist > botDist)
00935                     nodeStat->oddBotDist = botDist;
00936 
00937             } else {
00938                 
00939 
00940 
00941 
00942 
00943 
00944                 if (nodeStatChild->evenBotDist != MAXSHORTINT)
00945                     botDist = nodeStatChild->evenBotDist + 1;
00946                 else
00947                     botDist = MAXSHORTINT;
00948                 if (nodeStat->evenBotDist > botDist)
00949                     nodeStat->evenBotDist = botDist;
00950 
00951                 if (nodeStatChild->oddBotDist != MAXSHORTINT)
00952                     botDist = nodeStatChild->oddBotDist + 1;
00953                 else
00954                     botDist = MAXSHORTINT;
00955                 if (nodeStat->oddBotDist > botDist)
00956                     nodeStat->oddBotDist = botDist;
00957             }
00958         } 
00959         processingDone++;
00960     } 
00961 
00962     
00963     if ((nodeStat->oddTopDist != MAXSHORTINT) &&
00964         (nodeStat->oddBotDist != MAXSHORTINT))
00965         oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
00966     else
00967         oddLen = MAXSHORTINT;
00968 
00969     if ((nodeStat->evenTopDist != MAXSHORTINT) &&
00970         (nodeStat->evenBotDist != MAXSHORTINT))
00971         evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
00972     else
00973         evenLen = MAXSHORTINT;
00974 
00975     
00976 
00977     if (oddLen < pathLength ) {
00978         if (pathLength != MAXSHORTINT)
00979             pathLengthArray[pathLength]--;
00980         if (oddLen != MAXSHORTINT)
00981             pathLengthArray[oddLen]++;
00982         pathLength = oddLen;
00983     }
00984     if (evenLen < pathLength ) {
00985         if (pathLength != MAXSHORTINT)
00986             pathLengthArray[pathLength]--;
00987         if (evenLen != MAXSHORTINT)
00988             pathLengthArray[evenLen]++;
00989     }
00990 
00991     return(1);
00992 
00993 } 
00994 
00995 
01014 static st_table *
01015 CreatePathTable(
01016   DdNode * node ,
01017   unsigned int * pathLengthArray ,
01018   FILE *fp )
01019 {
01020 
01021     st_table *pathTable;
01022     NodeDist_t *nodeStat;
01023     DdHalfWord topLen;
01024     DdNode *N;
01025     int i, numParents;
01026     int insertValue;
01027     DdNode **childPage;
01028     int parentPage;
01029     int childQueueIndex, parentQueueIndex;
01030 
01031     
01032     pathTable = st_init_table(st_ptrcmp,st_ptrhash);
01033 
01034     
01035     maxNodeDistPages = INITIAL_PAGES;
01036     nodeDistPages = ALLOC(NodeDist_t *, maxNodeDistPages);
01037     if (nodeDistPages == NULL) {
01038         goto OUT_OF_MEM;
01039     }
01040     nodeDistPage = 0;
01041     currentNodeDistPage = nodeDistPages[nodeDistPage] =
01042         ALLOC(NodeDist_t, nodeDistPageSize);
01043     if (currentNodeDistPage == NULL) {
01044         for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
01045         FREE(nodeDistPages);
01046         goto OUT_OF_MEM;
01047     }
01048     nodeDistPageIndex = 0;
01049 
01050     
01051     maxQueuePages = INITIAL_PAGES;
01052     queuePages = ALLOC(DdNode **, maxQueuePages);
01053     if (queuePages == NULL) {
01054         goto OUT_OF_MEM;
01055     }
01056     queuePage = 0;
01057     currentQueuePage  = queuePages[queuePage] = ALLOC(DdNode *, queuePageSize);
01058     if (currentQueuePage == NULL) {
01059         for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
01060         FREE(queuePages);
01061         goto OUT_OF_MEM;
01062     }
01063     queuePageIndex = 0;
01064 
01065     
01066     parentPage = queuePage;
01067     parentQueueIndex = queuePageIndex;
01068     topLen = 0;
01069     *(currentQueuePage + queuePageIndex) = node;
01070     queuePageIndex++;
01071     childPage = currentQueuePage;
01072     childQueueIndex = queuePageIndex;
01073 
01074     N = Cudd_Regular(node);
01075 
01076     if (nodeDistPageIndex == nodeDistPageSize) ResizeNodeDistPages();
01077     if (memOut) {
01078         for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
01079         FREE(nodeDistPages);
01080         for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
01081         FREE(queuePages);
01082         st_free_table(pathTable);
01083         goto OUT_OF_MEM;
01084     }
01085 
01086     nodeStat = currentNodeDistPage + nodeDistPageIndex;
01087     nodeDistPageIndex++;
01088 
01089     nodeStat->oddTopDist = MAXSHORTINT;
01090     nodeStat->evenTopDist = MAXSHORTINT;
01091     nodeStat->evenBotDist = MAXSHORTINT;
01092     nodeStat->oddBotDist = MAXSHORTINT;
01093     nodeStat->regResult = NULL;
01094     nodeStat->compResult = NULL;
01095 
01096     insertValue = st_insert(pathTable, (char *)N, (char *)nodeStat);
01097     if (insertValue == ST_OUT_OF_MEM) {
01098         memOut = 1;
01099         for (i = 0; i <= nodeDistPage; i++) FREE(nodeDistPages[i]);
01100         FREE(nodeDistPages);
01101         for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
01102         FREE(queuePages);
01103         st_free_table(pathTable);
01104         goto OUT_OF_MEM;
01105     } else if (insertValue == 1) {
01106         fprintf(fp, "Something wrong, the entry exists but didnt show up in st_lookup\n");
01107         return(NULL);
01108     }
01109 
01110     if (Cudd_IsComplement(node)) {
01111         nodeStat->oddTopDist = 0;
01112     } else {
01113         nodeStat->evenTopDist = 0;
01114     }
01115     numParents = 1;
01116     
01117 
01118 
01119 #ifdef DD_DEBUG
01120     numCalls = 0;
01121 #endif
01122     CreateTopDist(pathTable, parentPage, parentQueueIndex, (int) topLen,
01123                   childPage, childQueueIndex, numParents, fp);
01124     if (memOut) {
01125         fprintf(fp, "Out of Memory and cant count path lengths\n");
01126         goto OUT_OF_MEM;
01127     }
01128 
01129 #ifdef DD_DEBUG
01130     numCalls = 0;
01131 #endif
01132     
01133 
01134 
01135     if (!CreateBotDist(node, pathTable, pathLengthArray, fp)) return(NULL);
01136 
01137     
01138     for (i = 0; i <= queuePage; i++) FREE(queuePages[i]);
01139     FREE(queuePages);
01140     return(pathTable);
01141 
01142 OUT_OF_MEM:
01143     (void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
01144     memOut = 1;
01145     return(NULL);
01146 
01147 } 
01148 
01149 
01166 static unsigned int
01167 AssessPathLength(
01168   unsigned int * pathLengthArray ,
01169   int  threshold ,
01170   int  numVars ,
01171   unsigned int * excess ,
01172   FILE *fp )
01173 {
01174     unsigned int i, maxpath;
01175     int temp;
01176 
01177     temp = threshold;
01178     i = 0;
01179     maxpath = 0;
01180     
01181 
01182 
01183     while ((i < (unsigned) numVars+1) && (temp > 0)) {
01184         if (pathLengthArray[i] > 0) {
01185             maxpath = i;
01186             temp = temp - pathLengthArray[i];
01187         }
01188         i++;
01189     }
01190     
01191     if (temp >= 0) {
01192         maxpath++; 
01193 
01194         *excess = 0;
01195     } else { 
01196 
01197         *excess = temp + pathLengthArray[maxpath];
01198     }
01199 
01200     if (maxpath == 0) {
01201         fprintf(fp, "Path Length array seems to be all zeroes, check\n");
01202     }
01203     return(maxpath);
01204 
01205 } 
01206 
01207 
01250 static DdNode *
01251 BuildSubsetBdd(
01252   DdManager * dd ,
01253   st_table * pathTable ,
01254   DdNode * node ,
01255   struct AssortedInfo * info ,
01256   st_table * subsetNodeTable )
01257 {
01258     DdNode *N, *Nv, *Nnv;
01259     DdNode *ThenBranch, *ElseBranch, *childBranch;
01260     DdNode *child, *regChild, *regNnv, *regNv;
01261     NodeDist_t *nodeStatNv, *nodeStat, *nodeStatNnv;
01262     DdNode *neW, *topv, *regNew;
01263     char *entry;
01264     unsigned int topid;
01265     unsigned int childPathLength, oddLen, evenLen, NnvPathLength, NvPathLength;
01266     unsigned int NvBotDist, NnvBotDist;
01267     int tiebreakChild;
01268     int  processingDone, thenDone, elseDone;
01269 
01270 
01271 #ifdef DD_DEBUG
01272     numCalls++;
01273 #endif
01274     if (Cudd_IsConstant(node))
01275         return(node);
01276 
01277     N = Cudd_Regular(node);
01278     
01279     if (!st_lookup(pathTable, N, &nodeStat)) {
01280         (void) fprintf(dd->err, "Something wrong, node must be in table \n");
01281         dd->errorCode = CUDD_INTERNAL_ERROR;
01282         return(NULL);
01283     }
01284     
01285 
01286 
01287 
01288 
01289 
01290 
01291 
01292     
01293     if (Cudd_IsComplement(node)) {
01294         if  (nodeStat->compResult != NULL) {
01295 #ifdef DD_DEBUG
01296             hits++;
01297 #endif
01298             return(nodeStat->compResult);
01299         }
01300     } else {
01301         
01302 
01303 
01304         if (nodeStat->regResult != NULL) {
01305 #ifdef DD_DEBUG
01306             hits++;
01307 #endif
01308             return(nodeStat->regResult);
01309         }
01310     }
01311 
01312 
01313     
01314     Nv = Cudd_T(N);
01315     Nnv = Cudd_E(N);
01316 
01317     Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
01318     Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
01319 
01320     
01321     processingDone = 0;
01322     
01323     thenDone = 0;
01324     ThenBranch = NULL;
01325     
01326     elseDone = 0;
01327     ElseBranch = NULL;
01328     
01329     if (Cudd_IsConstant(Nv)) {
01330         
01331         if ((Nv == DD_ONE(dd)) && (info->findShortestPath)) {
01332             info->findShortestPath = 0;
01333         }
01334 
01335         ThenBranch = Nv;
01336         cuddRef(ThenBranch);
01337         if (ThenBranch == NULL) {
01338             return(NULL);
01339         }
01340 
01341         thenDone++;
01342         processingDone++;
01343         NvBotDist = MAXSHORTINT;
01344     } else {
01345         
01346         regNv = Cudd_Regular(Nv);
01347         
01348         if (!st_lookup(pathTable, regNv, &nodeStatNv) ) {
01349             (void) fprintf(dd->err, "Something wrong, node must be in table\n");
01350             dd->errorCode = CUDD_INTERNAL_ERROR;
01351             return(NULL);
01352         }
01353         
01354         if ((nodeStatNv->oddTopDist != MAXSHORTINT) &&
01355             (nodeStatNv->oddBotDist != MAXSHORTINT)) {
01356             oddLen = (nodeStatNv->oddTopDist + nodeStatNv->oddBotDist);
01357         } else {
01358             oddLen = MAXSHORTINT;
01359         }
01360 
01361         if ((nodeStatNv->evenTopDist != MAXSHORTINT) &&
01362             (nodeStatNv->evenBotDist != MAXSHORTINT)) {
01363             evenLen = (nodeStatNv->evenTopDist +nodeStatNv->evenBotDist);
01364         } else {
01365             evenLen = MAXSHORTINT;
01366         }
01367 
01368         NvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
01369         NvBotDist = (oddLen <= evenLen) ? nodeStatNv->oddBotDist:
01370                                                    nodeStatNv->evenBotDist;
01371     }
01372     
01373     if (Cudd_IsConstant(Nnv)) {
01374         
01375         if ((Nnv == DD_ONE(dd)) && (info->findShortestPath)) {
01376             info->findShortestPath = 0;
01377         }
01378 
01379         ElseBranch = Nnv;
01380         cuddRef(ElseBranch);
01381         if (ElseBranch == NULL) {
01382             return(NULL);
01383         }
01384 
01385         elseDone++;
01386         processingDone++;
01387         NnvBotDist = MAXSHORTINT;
01388     } else {
01389         
01390         regNnv = Cudd_Regular(Nnv);
01391         
01392         if (!st_lookup(pathTable, regNnv, &nodeStatNnv) ) {
01393             (void) fprintf(dd->err, "Something wrong, node must be in table\n");
01394             dd->errorCode = CUDD_INTERNAL_ERROR;
01395             return(NULL);
01396         }
01397         
01398         if ((nodeStatNnv->oddTopDist != MAXSHORTINT) &&
01399             (nodeStatNnv->oddBotDist != MAXSHORTINT)) {
01400             oddLen = (nodeStatNnv->oddTopDist + nodeStatNnv->oddBotDist);
01401         } else {
01402             oddLen = MAXSHORTINT;
01403         }
01404 
01405         if ((nodeStatNnv->evenTopDist != MAXSHORTINT) &&
01406             (nodeStatNnv->evenBotDist != MAXSHORTINT)) {
01407             evenLen = (nodeStatNnv->evenTopDist +nodeStatNnv->evenBotDist);
01408         } else {
01409             evenLen = MAXSHORTINT;
01410         }
01411 
01412         NnvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
01413         NnvBotDist = (oddLen <= evenLen) ? nodeStatNnv->oddBotDist :
01414                                                    nodeStatNnv->evenBotDist;
01415     }
01416 
01417     tiebreakChild = (NvBotDist <= NnvBotDist) ? 1 : 0;
01418     
01419     while (processingDone != 2) {
01420         if (!processingDone) {
01421             
01422             
01423 
01424 
01425             if ((NvPathLength < NnvPathLength) ||
01426                 ((NvPathLength == NnvPathLength) && (tiebreakChild == 1))) {
01427                 child = Nv;
01428                 regChild = regNv;
01429                 thenDone = 1;
01430                 childPathLength = NvPathLength;
01431             } else {
01432                 child = Nnv;
01433                 regChild = regNnv;
01434                 elseDone = 1;
01435                 childPathLength = NnvPathLength;
01436             } 
01437         } else {
01438             
01439             if (thenDone) {
01440                 child = Nnv;
01441                 regChild = regNnv;
01442                 elseDone = 1;
01443                 childPathLength = NnvPathLength;
01444             } else {
01445                 child = Nv;
01446                 regChild = regNv;
01447                 thenDone = 1;
01448                 childPathLength = NvPathLength;
01449             } 
01450         } 
01451 
01452         
01453 
01454 
01455         if (childPathLength > info->maxpath) {
01456             
01457             childBranch = zero;
01458         } else {
01459             if (childPathLength < info->maxpath) {
01460                 if (info->findShortestPath) {
01461                     info->findShortestPath = 0;
01462                 }
01463                 childBranch = BuildSubsetBdd(dd, pathTable, child, info,
01464                                              subsetNodeTable);
01465 
01466             } else { 
01467                 
01468 
01469                 if (st_lookup(info->maxpathTable, (char *)regChild,
01470                               (char **)&entry)) {
01471                     
01472 
01473                     if (info->findShortestPath) {
01474                         info->findShortestPath = 0;
01475                     }
01476                     childBranch = BuildSubsetBdd(dd, pathTable, child, info,
01477                                                  subsetNodeTable);
01478                 } else {
01479                     
01480 
01481 
01482 
01483                     if (info->thresholdReached <= 0) {
01484                         if (info->findShortestPath) {
01485                             if (st_insert(info->maxpathTable, (char *)regChild,
01486                                           (char *)NIL(char)) == ST_OUT_OF_MEM) {
01487                                 memOut = 1;
01488                                 (void) fprintf(dd->err, "OUT of memory\n");
01489                                 info->thresholdReached = 0;
01490                                 childBranch = zero;
01491                             } else {
01492                                 info->thresholdReached--;
01493                                 childBranch = BuildSubsetBdd(dd, pathTable,
01494                                                     child, info,subsetNodeTable);
01495                             }
01496                         } else { 
01497 
01498                             childBranch = zero;
01499                         }
01500                     } else { 
01501 
01502                         if (st_insert(info->maxpathTable, (char *)regChild,
01503                                       (char *)NIL(char)) == ST_OUT_OF_MEM) {
01504                             memOut = 1;
01505                             (void) fprintf(dd->err, "OUT of memory\n");
01506                             info->thresholdReached = 0;
01507                             childBranch = zero;
01508                         } else {
01509                             info->thresholdReached--;
01510                             if (info->thresholdReached <= 0) {
01511                                 info->findShortestPath = 1;
01512                             }
01513                             childBranch = BuildSubsetBdd(dd, pathTable,
01514                                                  child, info, subsetNodeTable);
01515 
01516                         } 
01517                     } 
01518                 } 
01519             } 
01520         } 
01521         if (childBranch == NULL) {
01522             
01523             if (ThenBranch != NULL) {
01524                 Cudd_RecursiveDeref(dd, ThenBranch);
01525                 ThenBranch = NULL;
01526             }
01527             if (ElseBranch != NULL) {
01528                 Cudd_RecursiveDeref(dd, ElseBranch);
01529                 ElseBranch = NULL;
01530             }
01531             return(NULL);
01532         }
01533 
01534         cuddRef(childBranch);
01535 
01536         if (child == Nv) {
01537             ThenBranch = childBranch;
01538         } else {
01539             ElseBranch = childBranch;
01540         }
01541         processingDone++;
01542 
01543     } 
01544 
01545     info->findShortestPath = 0;
01546     topid = Cudd_NodeReadIndex(N);
01547     topv = Cudd_ReadVars(dd, topid);
01548     cuddRef(topv);
01549     neW = cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
01550     if (neW != NULL) {
01551         cuddRef(neW);
01552     }
01553     Cudd_RecursiveDeref(dd, topv);
01554     Cudd_RecursiveDeref(dd, ThenBranch);
01555     Cudd_RecursiveDeref(dd, ElseBranch);
01556 
01557 
01558     
01559     if (subsetNodeTable != NIL(st_table)) {
01560         
01561         regNew = Cudd_Regular(neW);
01562         
01563 
01564 
01565         if (!st_lookup(subsetNodeTable, (char *)regNew, (char **)&entry)) {
01566             if (!Cudd_IsConstant(regNew)) {
01567                 if (st_insert(subsetNodeTable, (char *)regNew,
01568                               (char *)NULL) == ST_OUT_OF_MEM) {
01569                     (void) fprintf(dd->err, "Out of memory\n");
01570                     return (NULL);
01571                 }
01572                 if (st_count(subsetNodeTable) > info->threshold) {
01573                     info->thresholdReached = 0;
01574                 }
01575             }
01576         }
01577     }
01578 
01579 
01580     if (neW == NULL) {
01581         return(NULL);
01582     } else {
01583         
01584         if (Cudd_IsComplement(node)) {
01585             nodeStat->compResult = neW;
01586             cuddRef(nodeStat->compResult);
01587             
01588 
01589 
01590 
01591             if (neW == node) {
01592 #ifdef DD_DEBUG
01593                 thishit++;
01594 #endif
01595                 
01596 
01597 
01598 
01599                 if (nodeStat->regResult != NULL) {
01600                     Cudd_RecursiveDeref(dd, nodeStat->regResult);
01601                 }
01602                 nodeStat->regResult = Cudd_Not(neW);
01603                 cuddRef(nodeStat->regResult);
01604             }
01605 
01606         } else {
01607             nodeStat->regResult = neW;
01608             cuddRef(nodeStat->regResult);
01609             if (neW == node) {
01610 #ifdef DD_DEBUG
01611                 thishit++;
01612 #endif
01613                 if (nodeStat->compResult != NULL) {
01614                     Cudd_RecursiveDeref(dd, nodeStat->compResult);
01615                 }
01616                 nodeStat->compResult = Cudd_Not(neW);
01617                 cuddRef(nodeStat->compResult);
01618             }
01619         }
01620 
01621         cuddDeref(neW);
01622         return(neW);
01623     } 
01624 } 
01625 
01626 
01638 static enum st_retval
01639 stPathTableDdFree(
01640   char * key,
01641   char * value,
01642   char * arg)
01643 {
01644     NodeDist_t *nodeStat;
01645     DdManager *dd;
01646 
01647     nodeStat = (NodeDist_t *)value;
01648     dd = (DdManager *)arg;
01649     if (nodeStat->regResult != NULL) {
01650         Cudd_RecursiveDeref(dd, nodeStat->regResult);
01651     }
01652     if (nodeStat->compResult != NULL) {
01653         Cudd_RecursiveDeref(dd, nodeStat->compResult);
01654     }
01655     return(ST_CONTINUE);
01656 
01657 }