00001 
00052 #include "util_hack.h"
00053 #include "cuddInt.h"
00054 
00055 
00056 
00057 
00058 
00059 
00060 #define DD_NORMAL_SIFT  0
00061 #define DD_LAZY_SIFT    1
00062 
00063 
00064 #define DD_SIFT_DOWN    0
00065 #define DD_SIFT_UP      1
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 
00077 
00078 
00079 #ifndef lint
00080 static char rcsid[] DD_UNUSED = "$Id: cuddGroup.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
00081 #endif
00082 
00083 static  int     *entry;
00084 extern  int     ddTotalNumberSwapping;
00085 #ifdef DD_STATS
00086 extern  int     ddTotalNISwaps;
00087 static  int     extsymmcalls;
00088 static  int     extsymm;
00089 static  int     secdiffcalls;
00090 static  int     secdiff;
00091 static  int     secdiffmisfire;
00092 #endif
00093 #ifdef DD_DEBUG
00094 static  int     pr = 0; 
00095                         
00096 #endif
00097 static int originalSize;
00098 static int originalLevel;
00099 
00100 
00101 
00102 
00103 
00106 
00107 
00108 
00109 
00110 static int ddTreeSiftingAux ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
00111 #ifdef DD_STATS
00112 static int ddCountInternalMtrNodes ARGS((DdManager *table, MtrNode *treenode));
00113 #endif
00114 static int ddReorderChildren ARGS((DdManager *table, MtrNode *treenode, Cudd_ReorderingType method));
00115 static void ddFindNodeHiLo ARGS((DdManager *table, MtrNode *treenode, int *lower, int *upper));
00116 static int ddUniqueCompareGroup ARGS((int *ptrX, int *ptrY));
00117 static int ddGroupSifting ARGS((DdManager *table, int lower, int upper, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
00118 static void ddCreateGroup ARGS((DdManager *table, int x, int y));
00119 static int ddGroupSiftingAux ARGS((DdManager *table, int x, int xLow, int xHigh, int (*checkFunction)(DdManager *, int, int), int lazyFlag));
00120 static int ddGroupSiftingUp ARGS((DdManager *table, int y, int xLow, int (*checkFunction)(DdManager *, int, int), Move **moves));
00121 static int ddGroupSiftingDown ARGS((DdManager *table, int x, int xHigh, int (*checkFunction)(DdManager *, int, int), Move **moves));
00122 static int ddGroupMove ARGS((DdManager *table, int x, int y, Move **moves));
00123 static int ddGroupMoveBackward ARGS((DdManager *table, int x, int y));
00124 static int ddGroupSiftingBackward ARGS((DdManager *table, Move *moves, int size, int upFlag, int lazyFlag));
00125 static void ddMergeGroups ARGS((DdManager *table, MtrNode *treenode, int low, int high));
00126 static void ddDissolveGroup ARGS((DdManager *table, int x, int y));
00127 static int ddNoCheck ARGS((DdManager *table, int x, int y));
00128 static int ddSecDiffCheck ARGS((DdManager *table, int x, int y));
00129 static int ddExtSymmCheck ARGS((DdManager *table, int x, int y));
00130 static int ddVarGroupCheck ARGS((DdManager * table, int x, int y)); 
00131 static int ddSetVarHandled ARGS((DdManager *dd, int index));
00132 static int ddResetVarHandled ARGS((DdManager *dd, int index));
00133 static int ddIsVarHandled ARGS((DdManager *dd, int index));
00134 
00138 
00139 
00140 
00141 
00142 
00160 MtrNode *
00161 Cudd_MakeTreeNode(
00162   DdManager * dd ,
00163   unsigned int  low ,
00164   unsigned int  size ,
00165   unsigned int  type )
00166 {
00167     MtrNode *group;
00168     MtrNode *tree;
00169     unsigned int level;
00170 
00171     
00172 
00173 
00174 
00175 
00176     level = (low < (unsigned int) dd->size) ? dd->perm[low] : low;
00177 
00178     if (level + size - 1> (int) MTR_MAXHIGH)
00179         return(NULL);
00180 
00181     
00182     tree = dd->tree;
00183     if (tree == NULL) {
00184         dd->tree = tree = Mtr_InitGroupTree(0, dd->size);
00185         if (tree == NULL)
00186             return(NULL);
00187         tree->index = dd->invperm[0];
00188     }
00189 
00190     
00191 
00192 
00193     tree->size = ddMax(tree->size, ddMax(level + size, (unsigned) dd->size));
00194 
00195     
00196     group = Mtr_MakeGroup(tree, level, size, type);
00197     if (group == NULL)
00198         return(NULL);
00199 
00200     
00201 
00202 
00203 
00204     group->index = (MtrHalfWord) low;
00205 
00206     return(group);
00207 
00208 } 
00209 
00210 
00211 
00212 
00213 
00214 
00215 
00228 int
00229 cuddTreeSifting(
00230   DdManager * table ,
00231   Cudd_ReorderingType method )
00232 {
00233     int i;
00234     int nvars;
00235     int result;
00236     int tempTree;
00237 
00238     
00239 
00240 
00241 
00242     tempTree = table->tree == NULL;
00243     if (tempTree) {
00244         table->tree = Mtr_InitGroupTree(0,table->size);
00245         table->tree->index = table->invperm[0];
00246     }
00247     nvars = table->size;
00248 
00249 #ifdef DD_DEBUG
00250     if (pr > 0 && !tempTree) (void) fprintf(table->out,"cuddTreeSifting:");
00251     Mtr_PrintGroups(table->tree,pr <= 0);
00252 #endif
00253 
00254 #ifdef DD_STATS
00255     extsymmcalls = 0;
00256     extsymm = 0;
00257     secdiffcalls = 0;
00258     secdiff = 0;
00259     secdiffmisfire = 0;
00260 
00261     (void) fprintf(table->out,"\n");
00262     if (!tempTree)
00263         (void) fprintf(table->out,"#:IM_NODES  %8d: group tree nodes\n",
00264                        ddCountInternalMtrNodes(table,table->tree));
00265 #endif
00266 
00267     
00268 
00269 
00270 
00271     for (i = 0; i < nvars; i++)
00272         table->subtables[i].next = i;
00273 
00274 
00275     
00276     result = ddTreeSiftingAux(table, table->tree, method);
00277 
00278 #ifdef DD_STATS         
00279     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00280         (table->groupcheck == CUDD_GROUP_CHECK7 ||
00281          table->groupcheck == CUDD_GROUP_CHECK5)) {
00282         (void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
00283         (void) fprintf(table->out,"extsymm = %d",extsymm);
00284     }
00285     if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
00286         table->groupcheck == CUDD_GROUP_CHECK7) {
00287         (void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
00288         (void) fprintf(table->out,"secdiff = %d\n",secdiff);
00289         (void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
00290     }
00291 #endif
00292 
00293     if (tempTree)
00294         Cudd_FreeTree(table);
00295     return(result);
00296 
00297 } 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00315 static int
00316 ddTreeSiftingAux(
00317   DdManager * table,
00318   MtrNode * treenode,
00319   Cudd_ReorderingType method)
00320 {
00321     MtrNode  *auxnode;
00322     int res;
00323     Cudd_AggregationType saveCheck;
00324 
00325 #ifdef DD_DEBUG
00326     Mtr_PrintGroups(treenode,1);
00327 #endif
00328 
00329     auxnode = treenode;
00330     while (auxnode != NULL) {
00331         if (auxnode->child != NULL) {
00332             if (!ddTreeSiftingAux(table, auxnode->child, method))
00333                 return(0);
00334             saveCheck = table->groupcheck;
00335             table->groupcheck = CUDD_NO_CHECK;
00336             if (method != CUDD_REORDER_LAZY_SIFT)
00337               res = ddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
00338             else
00339               res = ddReorderChildren(table, auxnode, CUDD_REORDER_LAZY_SIFT);
00340             table->groupcheck = saveCheck;
00341 
00342             if (res == 0)
00343                 return(0);
00344         } else if (auxnode->size > 1) {
00345             if (!ddReorderChildren(table, auxnode, method))
00346                 return(0);
00347         }
00348         auxnode = auxnode->younger;
00349     }
00350 
00351     return(1);
00352 
00353 } 
00354 
00355 
00356 #ifdef DD_STATS
00357 
00367 static int
00368 ddCountInternalMtrNodes(
00369   DdManager * table,
00370   MtrNode * treenode)
00371 {
00372     MtrNode *auxnode;
00373     int     count,nodeCount;
00374 
00375 
00376     nodeCount = 0;
00377     auxnode = treenode;
00378     while (auxnode != NULL) {
00379         if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
00380             nodeCount++;
00381             count = ddCountInternalMtrNodes(table,auxnode->child);
00382             nodeCount += count;
00383         }
00384         auxnode = auxnode->younger;
00385     }
00386 
00387     return(nodeCount);
00388 
00389 } 
00390 #endif
00391 
00392 
00407 static int
00408 ddReorderChildren(
00409   DdManager * table,
00410   MtrNode * treenode,
00411   Cudd_ReorderingType method)
00412 {
00413     int lower;
00414     int upper;
00415     int result;
00416     unsigned int initialSize;
00417 
00418     ddFindNodeHiLo(table,treenode,&lower,&upper);
00419     
00420     if (upper == -1)
00421         return(1);
00422 
00423     if (treenode->flags == MTR_FIXED) {
00424         result = 1;
00425     } else {
00426 #ifdef DD_STATS
00427         (void) fprintf(table->out," ");
00428 #endif
00429         switch (method) {
00430         case CUDD_REORDER_RANDOM:
00431         case CUDD_REORDER_RANDOM_PIVOT:
00432             result = cuddSwapping(table,lower,upper,method);
00433             break;
00434         case CUDD_REORDER_SIFT:
00435             result = cuddSifting(table,lower,upper);
00436             break;
00437         case CUDD_REORDER_SIFT_CONVERGE:
00438             do {
00439                 initialSize = table->keys - table->isolated;
00440                 result = cuddSifting(table,lower,upper);
00441                 if (initialSize <= table->keys - table->isolated)
00442                     break;
00443 #ifdef DD_STATS
00444                 else
00445                     (void) fprintf(table->out,"\n");
00446 #endif
00447             } while (result != 0);
00448             break;
00449         case CUDD_REORDER_SYMM_SIFT:
00450             result = cuddSymmSifting(table,lower,upper);
00451             break;
00452         case CUDD_REORDER_SYMM_SIFT_CONV:
00453             result = cuddSymmSiftingConv(table,lower,upper);
00454             break;
00455         case CUDD_REORDER_GROUP_SIFT:
00456             if (table->groupcheck == CUDD_NO_CHECK) {
00457                 result = ddGroupSifting(table,lower,upper,ddNoCheck,
00458                                         DD_NORMAL_SIFT);
00459             } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00460                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00461                                         DD_NORMAL_SIFT);
00462             } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00463                 result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00464                                         DD_NORMAL_SIFT);
00465             } else {
00466                 (void) fprintf(table->err,
00467                                "Unknown group ckecking method\n");
00468                 result = 0;
00469             }
00470             break;
00471         case CUDD_REORDER_GROUP_SIFT_CONV:
00472             do {
00473                 initialSize = table->keys - table->isolated;
00474                 if (table->groupcheck == CUDD_NO_CHECK) {
00475                     result = ddGroupSifting(table,lower,upper,ddNoCheck,
00476                                             DD_NORMAL_SIFT);
00477                 } else if (table->groupcheck == CUDD_GROUP_CHECK5) {
00478                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00479                                             DD_NORMAL_SIFT);
00480                 } else if (table->groupcheck == CUDD_GROUP_CHECK7) {
00481                     result = ddGroupSifting(table,lower,upper,ddExtSymmCheck,
00482                                             DD_NORMAL_SIFT);
00483                 } else {
00484                     (void) fprintf(table->err,
00485                                    "Unknown group ckecking method\n");
00486                     result = 0;
00487                 }
00488 #ifdef DD_STATS
00489                 (void) fprintf(table->out,"\n");
00490 #endif
00491                 result = cuddWindowReorder(table,lower,upper,
00492                                            CUDD_REORDER_WINDOW4);
00493                 if (initialSize <= table->keys - table->isolated)
00494                     break;
00495 #ifdef DD_STATS
00496                 else
00497                     (void) fprintf(table->out,"\n");
00498 #endif
00499             } while (result != 0);
00500             break;
00501         case CUDD_REORDER_WINDOW2:
00502         case CUDD_REORDER_WINDOW3:
00503         case CUDD_REORDER_WINDOW4:
00504         case CUDD_REORDER_WINDOW2_CONV:
00505         case CUDD_REORDER_WINDOW3_CONV:
00506         case CUDD_REORDER_WINDOW4_CONV:
00507             result = cuddWindowReorder(table,lower,upper,method);
00508             break;
00509         case CUDD_REORDER_ANNEALING:
00510             result = cuddAnnealing(table,lower,upper);
00511             break;
00512         case CUDD_REORDER_GENETIC:
00513             result = cuddGa(table,lower,upper);
00514             break;
00515         case CUDD_REORDER_LINEAR:
00516             result = cuddLinearAndSifting(table,lower,upper);
00517             break;
00518         case CUDD_REORDER_LINEAR_CONVERGE:
00519             do {
00520                 initialSize = table->keys - table->isolated;
00521                 result = cuddLinearAndSifting(table,lower,upper);
00522                 if (initialSize <= table->keys - table->isolated)
00523                     break;
00524 #ifdef DD_STATS
00525                 else
00526                     (void) fprintf(table->out,"\n");
00527 #endif
00528             } while (result != 0);
00529             break;
00530         case CUDD_REORDER_EXACT:
00531             result = cuddExact(table,lower,upper);
00532             break;
00533         case CUDD_REORDER_LAZY_SIFT:
00534             result = ddGroupSifting(table,lower,upper,ddVarGroupCheck,
00535                                     DD_LAZY_SIFT);
00536             break;
00537         default:
00538             return(0);
00539         }
00540     }
00541 
00542     
00543 
00544 
00545 
00546     ddMergeGroups(table,treenode,lower,upper);
00547 
00548 #ifdef DD_DEBUG
00549     if (pr > 0) (void) fprintf(table->out,"ddReorderChildren:");
00550 #endif
00551 
00552     return(result);
00553 
00554 } 
00555 
00556 
00571 static void
00572 ddFindNodeHiLo(
00573   DdManager * table,
00574   MtrNode * treenode,
00575   int * lower,
00576   int * upper)
00577 {
00578     int low;
00579     int high;
00580 
00581     
00582 
00583 
00584 
00585     if ((int) treenode->low >= table->size) {
00586         *lower = table->size;
00587         *upper = -1;
00588         return;
00589     }
00590 
00591     *lower = low = (unsigned int) table->perm[treenode->index];
00592     high = (int) (low + treenode->size - 1);
00593 
00594     if (high >= table->size) {
00595         
00596 
00597 
00598 
00599 
00600 
00601 
00602         MtrNode *auxnode = treenode->child;
00603         if (auxnode == NULL) {
00604             *upper = (unsigned int) table->size - 1;
00605         } else {
00606             
00607 
00608 
00609 
00610 
00611             while (auxnode != NULL) {
00612                 int thisLower = table->perm[auxnode->low];
00613                 int thisUpper = thisLower + auxnode->size - 1;
00614                 if (thisUpper >= table->size && thisLower < table->size)
00615                     *upper = (unsigned int) thisLower - 1;
00616                 auxnode = auxnode->younger;
00617             }
00618         }
00619     } else {
00620         
00621         *upper = (unsigned int) high;
00622     }
00623 
00624 #ifdef DD_DEBUG
00625     
00626     assert(treenode->size >= *upper - *lower + 1);
00627 #endif
00628 
00629     return;
00630 
00631 } 
00632 
00633 
00646 static int
00647 ddUniqueCompareGroup(
00648   int * ptrX,
00649   int * ptrY)
00650 {
00651 #if 0
00652     if (entry[*ptrY] == entry[*ptrX]) {
00653         return((*ptrX) - (*ptrY));
00654     }
00655 #endif
00656     return(entry[*ptrY] - entry[*ptrX]);
00657 
00658 } 
00659 
00660 
00674 static int
00675 ddGroupSifting(
00676   DdManager * table,
00677   int  lower,
00678   int  upper,
00679   int (*checkFunction)(DdManager *, int, int),
00680   int lazyFlag)
00681 {
00682     int         *var;
00683     int         i,j,x,xInit;
00684     int         nvars;
00685     int         classes;
00686     int         result;
00687     int         *sifted;
00688     int         merged;
00689     int         dissolve;
00690 #ifdef DD_STATS
00691     unsigned    previousSize;
00692 #endif
00693     int         xindex;
00694 
00695     nvars = table->size;
00696 
00697     
00698     entry = NULL;
00699     sifted = NULL;
00700     var = ALLOC(int,nvars);
00701     if (var == NULL) {
00702         table->errorCode = CUDD_MEMORY_OUT;
00703         goto ddGroupSiftingOutOfMem;
00704     }
00705     entry = ALLOC(int,nvars);
00706     if (entry == NULL) {
00707         table->errorCode = CUDD_MEMORY_OUT;
00708         goto ddGroupSiftingOutOfMem;
00709     }
00710     sifted = ALLOC(int,nvars);
00711     if (sifted == NULL) {
00712         table->errorCode = CUDD_MEMORY_OUT;
00713         goto ddGroupSiftingOutOfMem;
00714     }
00715 
00716     
00717     for (i = 0, classes = 0; i < nvars; i++) {
00718         sifted[i] = 0;
00719         x = table->perm[i];
00720         if ((unsigned) x >= table->subtables[x].next) {
00721             entry[i] = table->subtables[x].keys;
00722             var[classes] = i;
00723             classes++;
00724         }
00725     }
00726 
00727     qsort((void *)var,classes,sizeof(int),
00728           (int (*)(const void *, const void *)) ddUniqueCompareGroup);
00729 
00730     if (lazyFlag) {
00731         for (i = 0; i < nvars; i ++) {
00732             ddResetVarHandled(table, i);
00733         }
00734     }
00735 
00736     
00737     for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
00738         if (ddTotalNumberSwapping >= table->siftMaxSwap)
00739             break;
00740         xindex = var[i];
00741         if (sifted[xindex] == 1) 
00742             continue;
00743         x = table->perm[xindex]; 
00744 
00745         if (x < lower || x > upper || table->subtables[x].bindVar == 1)
00746             continue;
00747 #ifdef DD_STATS
00748         previousSize = table->keys - table->isolated;
00749 #endif
00750 #ifdef DD_DEBUG
00751         
00752         assert((unsigned) x >= table->subtables[x].next);
00753 #endif
00754         if ((unsigned) x == table->subtables[x].next) {
00755             dissolve = 1;
00756             result = ddGroupSiftingAux(table,x,lower,upper,checkFunction,
00757                                         lazyFlag);
00758         } else {
00759             dissolve = 0;
00760             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00761         }
00762         if (!result) goto ddGroupSiftingOutOfMem;
00763 
00764         
00765         merged = 0;
00766         if (lazyFlag == 0 && table->groupcheck == CUDD_GROUP_CHECK7) {
00767             x = table->perm[xindex]; 
00768             if ((unsigned) x == table->subtables[x].next) { 
00769                 if (x != upper && sifted[table->invperm[x+1]] == 0 &&
00770                 (unsigned) x+1 == table->subtables[x+1].next) {
00771                     if (ddSecDiffCheck(table,x,x+1)) {
00772                         merged =1;
00773                         ddCreateGroup(table,x,x+1);
00774                     }
00775                 }
00776                 if (x != lower && sifted[table->invperm[x-1]] == 0 &&
00777                 (unsigned) x-1 == table->subtables[x-1].next) {
00778                     if (ddSecDiffCheck(table,x-1,x)) {
00779                         merged =1;
00780                         ddCreateGroup(table,x-1,x);
00781                     }
00782                 }
00783             }
00784         }
00785 
00786         if (merged) { 
00787             
00788             while ((unsigned) x < table->subtables[x].next)
00789                 x = table->subtables[x].next;
00790             
00791             result = ddGroupSiftingAux(table,x,lower,upper,ddNoCheck,lazyFlag);
00792             if (!result) goto ddGroupSiftingOutOfMem;
00793 #ifdef DD_STATS
00794             if (table->keys < previousSize + table->isolated) {
00795                 (void) fprintf(table->out,"_");
00796             } else if (table->keys > previousSize + table->isolated) {
00797                 (void) fprintf(table->out,"^");
00798             } else {
00799                 (void) fprintf(table->out,"*");
00800             }
00801             fflush(table->out);
00802         } else {
00803             if (table->keys < previousSize + table->isolated) {
00804                 (void) fprintf(table->out,"-");
00805             } else if (table->keys > previousSize + table->isolated) {
00806                 (void) fprintf(table->out,"+");
00807             } else {
00808                 (void) fprintf(table->out,"=");
00809             }
00810             fflush(table->out);
00811 #endif
00812         }
00813 
00814         
00815         x = table->perm[xindex];
00816         if ((unsigned) x != table->subtables[x].next) {
00817             xInit = x;
00818             do {
00819                 j = table->invperm[x];
00820                 sifted[j] = 1;
00821                 x = table->subtables[x].next;
00822             } while (x != xInit);
00823 
00824             
00825             if (lazyFlag == 0 && dissolve) {
00826                 do {
00827                     j = table->subtables[x].next;
00828                     table->subtables[x].next = x;
00829                     x = j;
00830                 } while (x != xInit);
00831             }
00832         }
00833 
00834 #ifdef DD_DEBUG
00835         if (pr > 0) (void) fprintf(table->out,"ddGroupSifting:");
00836 #endif
00837 
00838       if (lazyFlag) ddSetVarHandled(table, xindex);
00839     } 
00840 
00841     FREE(sifted);
00842     FREE(var);
00843     FREE(entry);
00844 
00845     return(1);
00846 
00847 ddGroupSiftingOutOfMem:
00848     if (entry != NULL)  FREE(entry);
00849     if (var != NULL)    FREE(var);
00850     if (sifted != NULL) FREE(sifted);
00851 
00852     return(0);
00853 
00854 } 
00855 
00856 
00869 static void
00870 ddCreateGroup(
00871   DdManager * table,
00872   int  x,
00873   int  y)
00874 {
00875     int  gybot;
00876 
00877 #ifdef DD_DEBUG
00878     assert(y == x+1);
00879 #endif
00880 
00881     
00882     gybot = y;
00883     while ((unsigned) gybot < table->subtables[gybot].next)
00884         gybot = table->subtables[gybot].next;
00885 
00886     
00887     table->subtables[x].next = y;
00888     table->subtables[gybot].next = x;
00889 
00890     return;
00891 
00892 } 
00893 
00894 
00910 static int
00911 ddGroupSiftingAux(
00912   DdManager * table,
00913   int  x,
00914   int  xLow,
00915   int  xHigh,
00916   int (*checkFunction)(DdManager *, int, int),
00917   int lazyFlag)
00918 {
00919     Move *move;
00920     Move *moves;        
00921     int  initialSize;
00922     int  result;
00923     int  y;
00924     int  topbot;
00925 
00926 #ifdef DD_DEBUG
00927     if (pr > 0) (void) fprintf(table->out,
00928                                "ddGroupSiftingAux from %d to %d\n",xLow,xHigh);
00929     assert((unsigned) x >= table->subtables[x].next); 
00930 #endif
00931 
00932     initialSize = table->keys - table->isolated;
00933     moves = NULL;
00934 
00935     originalSize = initialSize;         
00936 
00937     
00938 
00939 
00940     if ((unsigned) x == table->subtables[x].next) {
00941         
00942 
00943 
00944         for (y = x; y > xLow; y--) {
00945             if (!checkFunction(table,y-1,y))
00946                 break;
00947             topbot = table->subtables[y-1].next; 
00948             table->subtables[y-1].next = y;
00949             table->subtables[x].next = topbot; 
00950                                                
00951             y = topbot + 1; 
00952         }
00953         
00954 
00955 
00956         for (y = x; y < xHigh; y++) {
00957             if (!checkFunction(table,y,y+1))
00958                 break;
00959             
00960             topbot = y + 1;
00961             while ((unsigned) topbot < table->subtables[topbot].next) {
00962                 topbot = table->subtables[topbot].next;
00963             }
00964             table->subtables[topbot].next = table->subtables[y].next;
00965             table->subtables[y].next = y + 1;
00966             y = topbot - 1; 
00967         }
00968     }
00969 
00970     
00971 
00972 
00973     while ((unsigned) x < table->subtables[x].next)
00974         x = table->subtables[x].next;
00975 
00976     originalLevel = x;                  
00977 
00978     if (x == xLow) { 
00979 #ifdef DD_DEBUG
00980         
00981         assert((unsigned) x == table->subtables[x].next);
00982 #endif
00983         if (x == xHigh) return(1);      
00984 
00985         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
00986             goto ddGroupSiftingAuxOutOfMem;
00987         
00988 
00989         
00990         result = ddGroupSiftingBackward(table,moves,initialSize,
00991                                         DD_SIFT_DOWN,lazyFlag);
00992 #ifdef DD_DEBUG
00993         assert(table->keys - table->isolated <= (unsigned) initialSize);
00994 #endif
00995         if (!result) goto ddGroupSiftingAuxOutOfMem;
00996 
00997     } else if (cuddNextHigh(table,x) > xHigh) { 
00998 #ifdef DD_DEBUG
00999         
01000         assert((unsigned) x >= table->subtables[x].next);
01001 #endif
01002         
01003         x = table->subtables[x].next;
01004 
01005         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01006             goto ddGroupSiftingAuxOutOfMem;
01007         
01008 
01009         
01010         result = ddGroupSiftingBackward(table,moves,initialSize,
01011                                         DD_SIFT_UP,lazyFlag);
01012 #ifdef DD_DEBUG
01013         assert(table->keys - table->isolated <= (unsigned) initialSize);
01014 #endif
01015         if (!result) goto ddGroupSiftingAuxOutOfMem;
01016 
01017     } else if (x - xLow > xHigh - x) { 
01018         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01019             goto ddGroupSiftingAuxOutOfMem;
01020         
01021 
01022         
01023         if (moves) {
01024             x = moves->y;
01025         }
01026         while ((unsigned) x < table->subtables[x].next)
01027             x = table->subtables[x].next;
01028         x = table->subtables[x].next;
01029 #ifdef DD_DEBUG
01030         
01031         assert((unsigned) x <= table->subtables[x].next);
01032 #endif
01033 
01034         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01035             goto ddGroupSiftingAuxOutOfMem;
01036 
01037         
01038         result = ddGroupSiftingBackward(table,moves,initialSize,
01039                                         DD_SIFT_UP,lazyFlag);
01040 #ifdef DD_DEBUG
01041         assert(table->keys - table->isolated <= (unsigned) initialSize);
01042 #endif
01043         if (!result) goto ddGroupSiftingAuxOutOfMem;
01044 
01045     } else { 
01046         
01047         x = table->subtables[x].next;
01048 
01049         if (!ddGroupSiftingUp(table,x,xLow,checkFunction,&moves))
01050             goto ddGroupSiftingAuxOutOfMem;
01051         
01052 
01053         if (moves) {
01054             x = moves->x;
01055         }
01056         while ((unsigned) x < table->subtables[x].next)
01057             x = table->subtables[x].next;
01058 #ifdef DD_DEBUG
01059         
01060         assert((unsigned) x >= table->subtables[x].next);
01061 #endif
01062 
01063         if (!ddGroupSiftingDown(table,x,xHigh,checkFunction,&moves))
01064             goto ddGroupSiftingAuxOutOfMem;
01065 
01066         
01067         result = ddGroupSiftingBackward(table,moves,initialSize,
01068                                         DD_SIFT_DOWN,lazyFlag);
01069 #ifdef DD_DEBUG
01070         assert(table->keys - table->isolated <= (unsigned) initialSize);
01071 #endif
01072         if (!result) goto ddGroupSiftingAuxOutOfMem;
01073     }
01074 
01075     while (moves != NULL) {
01076         move = moves->next;
01077         cuddDeallocNode(table, (DdNode *) moves);
01078         moves = move;
01079     }
01080 
01081     return(1);
01082 
01083 ddGroupSiftingAuxOutOfMem:
01084     while (moves != NULL) {
01085         move = moves->next;
01086         cuddDeallocNode(table, (DdNode *) moves);
01087         moves = move;
01088     }
01089 
01090     return(0);
01091 
01092 } 
01093 
01094 
01110 static int
01111 ddGroupSiftingUp(
01112   DdManager * table,
01113   int  y,
01114   int  xLow,
01115   int (*checkFunction)(DdManager *, int, int),
01116   Move ** moves)
01117 {
01118     Move *move;
01119     int  x;
01120     int  size;
01121     int  i;
01122     int  gxtop,gybot;
01123     int  limitSize;
01124     int  xindex, yindex;
01125     int  zindex;
01126     int  z;
01127     int  isolated;
01128     int  L;     
01129 #ifdef DD_DEBUG
01130     int  checkL;
01131 #endif
01132 
01133     yindex = table->invperm[y];
01134 
01135     
01136 
01137 
01138 
01139 
01140 
01141 
01142 
01143 
01144     limitSize = L = table->keys - table->isolated;
01145     gybot = y;
01146     while ((unsigned) gybot < table->subtables[gybot].next)
01147         gybot = table->subtables[gybot].next;
01148     for (z = xLow + 1; z <= gybot; z++) {
01149         zindex = table->invperm[z];
01150         if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01151             isolated = table->vars[zindex]->ref == 1;
01152             L -= table->subtables[z].keys - isolated;
01153         }
01154     }
01155 
01156     originalLevel = y;                  
01157 
01158     x = cuddNextLow(table,y);
01159     while (x >= xLow && L <= limitSize) {
01160 #ifdef DD_DEBUG
01161         gybot = y;
01162         while ((unsigned) gybot < table->subtables[gybot].next)
01163             gybot = table->subtables[gybot].next;
01164         checkL = table->keys - table->isolated;
01165         for (z = xLow + 1; z <= gybot; z++) {
01166             zindex = table->invperm[z];
01167             if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) {
01168                 isolated = table->vars[zindex]->ref == 1;
01169                 checkL -= table->subtables[z].keys - isolated;
01170             }
01171         }
01172         if (pr > 0 && L != checkL) {
01173             (void) fprintf(table->out,
01174                            "Inaccurate lower bound: L = %d checkL = %d\n",
01175                            L, checkL);
01176         }
01177 #endif
01178         gxtop = table->subtables[x].next;
01179         if (checkFunction(table,x,y)) {
01180             
01181             table->subtables[x].next = y;
01182             i = table->subtables[y].next;
01183             while (table->subtables[i].next != (unsigned) y)
01184                 i = table->subtables[i].next;
01185             table->subtables[i].next = gxtop;
01186             move = (Move *)cuddDynamicAllocNode(table);
01187             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01188             move->x = x;
01189             move->y = y;
01190             move->flags = MTR_NEWNODE;
01191             move->size = table->keys - table->isolated;
01192             move->next = *moves;
01193             *moves = move;
01194         } else if (table->subtables[x].next == (unsigned) x &&
01195                    table->subtables[y].next == (unsigned) y) {
01196             
01197             xindex = table->invperm[x];
01198             size = cuddSwapInPlace(table,x,y);
01199 #ifdef DD_DEBUG
01200             assert(table->subtables[x].next == (unsigned) x);
01201             assert(table->subtables[y].next == (unsigned) y);
01202 #endif
01203             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01204             
01205             if (cuddTestInteract(table,xindex,yindex)) {
01206                 isolated = table->vars[xindex]->ref == 1;
01207                 L += table->subtables[y].keys - isolated;
01208             }
01209             move = (Move *)cuddDynamicAllocNode(table);
01210             if (move == NULL) goto ddGroupSiftingUpOutOfMem;
01211             move->x = x;
01212             move->y = y;
01213             move->flags = MTR_DEFAULT;
01214             move->size = size;
01215             move->next = *moves;
01216             *moves = move;
01217 
01218 #ifdef DD_DEBUG
01219             if (pr > 0) (void) fprintf(table->out,
01220                                        "ddGroupSiftingUp (2 single groups):\n");
01221 #endif
01222             if ((double) size > (double) limitSize * table->maxGrowth)
01223                 return(1);
01224             if (size < limitSize) limitSize = size;
01225         } else { 
01226             size = ddGroupMove(table,x,y,moves);
01227             if (size == 0) goto ddGroupSiftingUpOutOfMem;
01228             
01229             z = (*moves)->y;
01230             do {
01231                 zindex = table->invperm[z];
01232                 if (cuddTestInteract(table,zindex,yindex)) {
01233                     isolated = table->vars[zindex]->ref == 1;
01234                     L += table->subtables[z].keys - isolated;
01235                 }
01236                 z = table->subtables[z].next;
01237             } while (z != (int) (*moves)->y);
01238             if ((double) size > (double) limitSize * table->maxGrowth)
01239                 return(1);
01240             if (size < limitSize) limitSize = size;
01241         }
01242         y = gxtop;
01243         x = cuddNextLow(table,y);
01244     }
01245 
01246     return(1);
01247 
01248 ddGroupSiftingUpOutOfMem:
01249     while (*moves != NULL) {
01250         move = (*moves)->next;
01251         cuddDeallocNode(table, (DdNode *) *moves);
01252         *moves = move;
01253     }
01254     return(0);
01255 
01256 } 
01257 
01258 
01270 static int
01271 ddGroupSiftingDown(
01272   DdManager * table,
01273   int  x,
01274   int  xHigh,
01275   int (*checkFunction)(DdManager *, int, int),
01276   Move ** moves)
01277 {
01278     Move *move;
01279     int  y;
01280     int  size;
01281     int  limitSize;
01282     int  gxtop,gybot;
01283     int  R;     
01284     int  xindex, yindex;
01285     int  isolated, allVars;
01286     int  z;
01287     int  zindex;
01288 #ifdef DD_DEBUG
01289     int  checkR;
01290 #endif
01291 
01292     
01293 
01294 
01295 
01296 
01297     y = x;
01298     allVars = 1;
01299     do {
01300         if (table->subtables[y].keys != 1) {
01301             allVars = 0;
01302             break;
01303         }
01304         y = table->subtables[y].next;
01305     } while (table->subtables[y].next != (unsigned) x);
01306     if (allVars)
01307         return(1);
01308     
01309     
01310     xindex = table->invperm[x];
01311     gxtop = table->subtables[x].next;
01312     limitSize = size = table->keys - table->isolated;
01313     R = 0;
01314     for (z = xHigh; z > gxtop; z--) {
01315         zindex = table->invperm[z];
01316         if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01317             isolated = table->vars[zindex]->ref == 1;
01318             R += table->subtables[z].keys - isolated;
01319         }
01320     }
01321 
01322     originalLevel = x;                  
01323 
01324     y = cuddNextHigh(table,x);
01325     while (y <= xHigh && size - R < limitSize) {
01326 #ifdef DD_DEBUG
01327         gxtop = table->subtables[x].next;
01328         checkR = 0;
01329         for (z = xHigh; z > gxtop; z--) {
01330             zindex = table->invperm[z];
01331             if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01332                 isolated = table->vars[zindex]->ref == 1;
01333                 checkR += table->subtables[z].keys - isolated;
01334             }
01335         }
01336         assert(R >= checkR);
01337 #endif
01338         
01339         gybot = table->subtables[y].next;
01340         while (table->subtables[gybot].next != (unsigned) y)
01341             gybot = table->subtables[gybot].next;
01342 
01343         if (checkFunction(table,x,y)) {
01344             
01345             gxtop = table->subtables[x].next;
01346             table->subtables[x].next = y;
01347             table->subtables[gybot].next = gxtop;
01348             move = (Move *)cuddDynamicAllocNode(table);
01349             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01350             move->x = x;
01351             move->y = y;
01352             move->flags = MTR_NEWNODE;
01353             move->size = table->keys - table->isolated;
01354             move->next = *moves;
01355             *moves = move;
01356         } else if (table->subtables[x].next == (unsigned) x &&
01357                    table->subtables[y].next == (unsigned) y) {
01358             
01359             
01360             yindex = table->invperm[y];
01361             if (cuddTestInteract(table,xindex,yindex)) {
01362                 isolated = table->vars[yindex]->ref == 1;
01363                 R -= table->subtables[y].keys - isolated;
01364             }
01365             size = cuddSwapInPlace(table,x,y);
01366 #ifdef DD_DEBUG
01367             assert(table->subtables[x].next == (unsigned) x);
01368             assert(table->subtables[y].next == (unsigned) y);
01369 #endif
01370             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01371 
01372             
01373             move = (Move *) cuddDynamicAllocNode(table);
01374             if (move == NULL) goto ddGroupSiftingDownOutOfMem;
01375             move->x = x;
01376             move->y = y;
01377             move->flags = MTR_DEFAULT;
01378             move->size = size;
01379             move->next = *moves;
01380             *moves = move;
01381 
01382 #ifdef DD_DEBUG
01383             if (pr > 0) (void) fprintf(table->out,
01384                                        "ddGroupSiftingDown (2 single groups):\n");
01385 #endif
01386             if ((double) size > (double) limitSize * table->maxGrowth)
01387                 return(1);
01388             if (size < limitSize) limitSize = size;
01389 
01390             x = y;
01391             y = cuddNextHigh(table,x);
01392         } else { 
01393             
01394             gxtop = table->subtables[x].next;
01395             z = gxtop + 1;
01396             do {
01397                 zindex = table->invperm[z];
01398                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01399                     isolated = table->vars[zindex]->ref == 1;
01400                     R -= table->subtables[z].keys - isolated;
01401                 }
01402                 z++;
01403             } while (z <= gybot);
01404             size = ddGroupMove(table,x,y,moves);
01405             if (size == 0) goto ddGroupSiftingDownOutOfMem;
01406             if ((double) size > (double) limitSize * table->maxGrowth)
01407                 return(1);
01408             if (size < limitSize) limitSize = size;
01409 
01410             
01411             gxtop = table->subtables[gybot].next;
01412             for (z = gxtop + 1; z <= gybot; z++) {
01413                 zindex = table->invperm[z];
01414                 if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) {
01415                     isolated = table->vars[zindex]->ref == 1;
01416                     R += table->subtables[z].keys - isolated;
01417                 }
01418             }
01419         }
01420         x = gybot;
01421         y = cuddNextHigh(table,x);
01422     }
01423 
01424     return(1);
01425 
01426 ddGroupSiftingDownOutOfMem:
01427     while (*moves != NULL) {
01428         move = (*moves)->next;
01429         cuddDeallocNode(table, (DdNode *) *moves);
01430         *moves = move;
01431     }
01432 
01433     return(0);
01434 
01435 } 
01436 
01437 
01448 static int
01449 ddGroupMove(
01450   DdManager * table,
01451   int  x,
01452   int  y,
01453   Move ** moves)
01454 {
01455     Move *move;
01456     int  size;
01457     int  i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01458     int  swapx,swapy;
01459 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01460     int  initialSize,bestSize;
01461 #endif
01462 
01463 #if DD_DEBUG
01464     
01465     assert(x < y);
01466 #endif
01467     
01468     xbot = x;
01469     xtop = table->subtables[x].next;
01470     xsize = xbot - xtop + 1;
01471     ybot = y;
01472     while ((unsigned) ybot < table->subtables[ybot].next)
01473         ybot = table->subtables[ybot].next;
01474     ytop = y;
01475     ysize = ybot - ytop + 1;
01476 
01477 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01478     initialSize = bestSize = table->keys - table->isolated;
01479 #endif
01480     
01481     for (i = 1; i <= ysize; i++) {
01482         for (j = 1; j <= xsize; j++) {
01483             size = cuddSwapInPlace(table,x,y);
01484             if (size == 0) goto ddGroupMoveOutOfMem;
01485 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01486             if (size < bestSize)
01487                 bestSize = size;
01488 #endif
01489             swapx = x; swapy = y;
01490             y = x;
01491             x = cuddNextLow(table,y);
01492         }
01493         y = ytop + i;
01494         x = cuddNextLow(table,y);
01495     }
01496 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01497     if ((bestSize < initialSize) && (bestSize < size))
01498         (void) fprintf(table->out,"Missed local minimum: initialSize:%d  bestSize:%d  finalSize:%d\n",initialSize,bestSize,size);
01499 #endif
01500 
01501     
01502     y = xtop; 
01503     for (i = 0; i < ysize - 1; i++) {
01504         table->subtables[y].next = cuddNextHigh(table,y);
01505         y = cuddNextHigh(table,y);
01506     }
01507     table->subtables[y].next = xtop; 
01508                                     
01509     x = cuddNextHigh(table,y);
01510     newxtop = x;
01511     for (i = 0; i < xsize - 1; i++) {
01512         table->subtables[x].next = cuddNextHigh(table,x);
01513         x = cuddNextHigh(table,x);
01514     }
01515     table->subtables[x].next = newxtop; 
01516                                     
01517 #ifdef DD_DEBUG
01518     if (pr > 0) (void) fprintf(table->out,"ddGroupMove:\n");
01519 #endif
01520 
01521     
01522     move = (Move *) cuddDynamicAllocNode(table);
01523     if (move == NULL) goto ddGroupMoveOutOfMem;
01524     move->x = swapx;
01525     move->y = swapy;
01526     move->flags = MTR_DEFAULT;
01527     move->size = table->keys - table->isolated;
01528     move->next = *moves;
01529     *moves = move;
01530 
01531     return(table->keys - table->isolated);
01532 
01533 ddGroupMoveOutOfMem:
01534     while (*moves != NULL) {
01535         move = (*moves)->next;
01536         cuddDeallocNode(table, (DdNode *) *moves);
01537         *moves = move;
01538     }
01539     return(0);
01540 
01541 } 
01542 
01543 
01554 static int
01555 ddGroupMoveBackward(
01556   DdManager * table,
01557   int  x,
01558   int  y)
01559 {
01560     int size;
01561     int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
01562 
01563 
01564 #if DD_DEBUG
01565     
01566     assert(x < y);
01567 #endif
01568 
01569     
01570     xbot = x;
01571     xtop = table->subtables[x].next;
01572     xsize = xbot - xtop + 1;
01573     ybot = y;
01574     while ((unsigned) ybot < table->subtables[ybot].next)
01575         ybot = table->subtables[ybot].next;
01576     ytop = y;
01577     ysize = ybot - ytop + 1;
01578 
01579     
01580     for (i = 1; i <= ysize; i++) {
01581         for (j = 1; j <= xsize; j++) {
01582             size = cuddSwapInPlace(table,x,y);
01583             if (size == 0)
01584                 return(0);
01585             y = x;
01586             x = cuddNextLow(table,y);
01587         }
01588         y = ytop + i;
01589         x = cuddNextLow(table,y);
01590     }
01591 
01592     
01593     y = xtop;
01594     for (i = 0; i < ysize - 1; i++) {
01595         table->subtables[y].next = cuddNextHigh(table,y);
01596         y = cuddNextHigh(table,y);
01597     }
01598     table->subtables[y].next = xtop; 
01599                                     
01600     x = cuddNextHigh(table,y);
01601     newxtop = x;
01602     for (i = 0; i < xsize - 1; i++) {
01603         table->subtables[x].next = cuddNextHigh(table,x);
01604         x = cuddNextHigh(table,x);
01605     }
01606     table->subtables[x].next = newxtop; 
01607                                     
01608 #ifdef DD_DEBUG
01609     if (pr > 0) (void) fprintf(table->out,"ddGroupMoveBackward:\n");
01610 #endif
01611 
01612     return(1);
01613 
01614 } 
01615 
01616 
01628 static int
01629 ddGroupSiftingBackward(
01630   DdManager * table,
01631   Move * moves,
01632   int  size,
01633   int  upFlag, 
01634   int  lazyFlag)
01635 {
01636     Move *move;
01637     int  res;
01638     Move *end_move;
01639     int diff, tmp_diff;
01640     int index, pairlev;
01641 
01642     if (lazyFlag) {
01643         end_move = NULL;
01644 
01645         
01646 
01647         for (move = moves; move != NULL; move = move->next) {
01648             if (move->size < size) {
01649                 size = move->size;
01650                 end_move = move;
01651             } else if (move->size == size) {
01652                 if (end_move == NULL) end_move = move;
01653             } 
01654         }
01655 
01656         
01657 
01658         if (moves != NULL) {
01659             diff = Cudd_ReadSize(table) + 1;
01660             index = (upFlag == 1) ? 
01661                     table->invperm[moves->x] : table->invperm[moves->y];
01662             pairlev = table->perm[Cudd_bddReadPairIndex(table, index)];
01663 
01664             for (move = moves; move != NULL; move = move->next) {
01665                 if (move->size == size) {
01666                     if (upFlag == 1) {
01667                         tmp_diff = (move->x > pairlev) ? 
01668                                     move->x - pairlev : pairlev - move->x;
01669                     } else {
01670                         tmp_diff = (move->y > pairlev) ?
01671                                     move->y - pairlev : pairlev - move->y;
01672                     }
01673                     if (tmp_diff < diff) {
01674                         diff = tmp_diff;
01675                         end_move = move;
01676                     } 
01677                 }
01678             }
01679         }
01680     } else {
01681         
01682         for (move = moves; move != NULL; move = move->next) {
01683             if (move->size < size) {
01684                 size = move->size;
01685             } 
01686         }
01687     }
01688 
01689     
01690 
01691 
01692     for (move = moves; move != NULL; move = move->next) {
01693         if (lazyFlag) {
01694             if (move == end_move) return(1);
01695         } else {
01696             if (move->size == size) return(1);
01697         }
01698         if ((table->subtables[move->x].next == move->x) &&
01699         (table->subtables[move->y].next == move->y)) {
01700             res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
01701             if (!res) return(0);
01702 #ifdef DD_DEBUG
01703             if (pr > 0) (void) fprintf(table->out,"ddGroupSiftingBackward:\n");
01704             assert(table->subtables[move->x].next == move->x);
01705             assert(table->subtables[move->y].next == move->y);
01706 #endif
01707         } else { 
01708             if (move->flags == MTR_NEWNODE) {
01709                 ddDissolveGroup(table,(int)move->x,(int)move->y);
01710             } else {
01711                 res = ddGroupMoveBackward(table,(int)move->x,(int)move->y);
01712                 if (!res) return(0);
01713             }
01714         }
01715 
01716     }
01717 
01718     return(1);
01719 
01720 } 
01721 
01722 
01733 static void
01734 ddMergeGroups(
01735   DdManager * table,
01736   MtrNode * treenode,
01737   int  low,
01738   int  high)
01739 {
01740     int i;
01741     MtrNode *auxnode;
01742     int saveindex;
01743     int newindex;
01744 
01745     
01746 
01747 
01748     if (treenode != table->tree) {
01749         for (i = low; i < high; i++)
01750             table->subtables[i].next = i+1;
01751         table->subtables[high].next = low;
01752     }
01753 
01754     
01755 
01756     saveindex = treenode->index;
01757     newindex = table->invperm[low];
01758     auxnode = treenode;
01759     do {
01760         auxnode->index = newindex;
01761         if (auxnode->parent == NULL ||
01762                 (int) auxnode->parent->index != saveindex)
01763             break;
01764         auxnode = auxnode->parent;
01765     } while (1);
01766     return;
01767 
01768 } 
01769 
01770 
01781 static void
01782 ddDissolveGroup(
01783   DdManager * table,
01784   int  x,
01785   int  y)
01786 {
01787     int topx;
01788     int boty;
01789 
01790     
01791     boty = y;
01792     while ((unsigned) boty < table->subtables[boty].next)
01793         boty = table->subtables[boty].next;
01794     
01795     topx = table->subtables[boty].next;
01796 
01797     table->subtables[boty].next = y;
01798     table->subtables[x].next = topx;
01799 
01800     return;
01801 
01802 } 
01803 
01804 
01815 static int
01816 ddNoCheck(
01817   DdManager * table,
01818   int  x,
01819   int  y)
01820 {
01821     return(0);
01822 
01823 } 
01824 
01825 
01839 static int
01840 ddSecDiffCheck(
01841   DdManager * table,
01842   int  x,
01843   int  y)
01844 {
01845     double Nx,Nx_1;
01846     double Sx;
01847     double threshold;
01848     int    xindex,yindex;
01849 
01850     if (x==0) return(0);
01851 
01852 #ifdef DD_STATS
01853     secdiffcalls++;
01854 #endif
01855     Nx = (double) table->subtables[x].keys;
01856     Nx_1 = (double) table->subtables[x-1].keys;
01857     Sx = (table->subtables[y].keys/Nx) - (Nx/Nx_1);
01858 
01859     threshold = table->recomb / 100.0;
01860     if (Sx < threshold) {
01861         xindex = table->invperm[x];
01862         yindex = table->invperm[y];
01863         if (cuddTestInteract(table,xindex,yindex)) {
01864 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
01865             (void) fprintf(table->out,
01866                            "Second difference for %d = %g Pos(%d)\n",
01867                            table->invperm[x],Sx,x);
01868 #endif
01869 #ifdef DD_STATS
01870             secdiff++;
01871 #endif
01872             return(1);
01873         } else {
01874 #ifdef DD_STATS
01875             secdiffmisfire++;
01876 #endif
01877             return(0);
01878         }
01879 
01880     }
01881     return(0);
01882 
01883 } 
01884 
01885 
01896 static int
01897 ddExtSymmCheck(
01898   DdManager * table,
01899   int  x,
01900   int  y)
01901 {
01902     DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10;
01903     DdNode *one;
01904     int comple;         
01905     int notproj;        
01906     int arccount;       
01907     int TotalRefCount;  
01908     int counter;        
01909                         
01910     int arccounter;     
01911                         
01912     int i;
01913     int xindex;
01914     int yindex;
01915     int res;
01916     int slots;
01917     DdNodePtr *list;
01918     DdNode *sentinel = &(table->sentinel);
01919 
01920     xindex = table->invperm[x];
01921     yindex = table->invperm[y];
01922 
01923     
01924     if (!cuddTestInteract(table,xindex,yindex))
01925         return(0);
01926 
01927 #ifdef DD_DEBUG
01928     
01929 
01930 
01931 
01932 
01933     if (table->subtables[x].keys == 1) {
01934         assert(table->vars[xindex]->ref != 1);
01935     }
01936     if (table->subtables[y].keys == 1) {
01937         assert(table->vars[yindex]->ref != 1);
01938     }
01939 #endif
01940 
01941 #ifdef DD_STATS
01942     extsymmcalls++;
01943 #endif
01944 
01945     arccount = 0;
01946     counter = (int) (table->subtables[x].keys *
01947               (table->symmviolation/100.0) + 0.5);
01948     one = DD_ONE(table);
01949 
01950     slots = table->subtables[x].slots;
01951     list = table->subtables[x].nodelist;
01952     for (i = 0; i < slots; i++) {
01953         f = list[i];
01954         while (f != sentinel) {
01955             
01956             f1 = cuddT(f);
01957             f0 = Cudd_Regular(cuddE(f));
01958             comple = Cudd_IsComplement(cuddE(f));
01959             notproj = f1 != one || f0 != one || f->ref != (DdHalfWord) 1;
01960             if (f1->index == yindex) {
01961                 arccount++;
01962                 f11 = cuddT(f1); f10 = cuddE(f1);
01963             } else {
01964                 if ((int) f0->index != yindex) {
01965                     
01966 
01967 
01968                     if (notproj) {
01969                         if (counter == 0)
01970                             return(0);
01971                         counter--; 
01972                     }
01973                 }
01974                 f11 = f10 = f1;
01975             }
01976             if ((int) f0->index == yindex) {
01977                 arccount++;
01978                 f01 = cuddT(f0); f00 = cuddE(f0);
01979             } else {
01980                 f01 = f00 = f0;
01981             }
01982             if (comple) {
01983                 f01 = Cudd_Not(f01);
01984                 f00 = Cudd_Not(f00);
01985             }
01986 
01987             
01988 
01989 
01990 
01991             if (notproj) {
01992                 if (f01 != f10 && f11 != f00) {
01993                     if (counter == 0)
01994                         return(0);
01995                     counter--;
01996                 }
01997             }
01998 
01999             f = f->next;
02000         } 
02001     } 
02002 
02003     
02004     TotalRefCount = -1; 
02005     slots = table->subtables[y].slots;
02006     list = table->subtables[y].nodelist;
02007     for (i = 0; i < slots; i++) {
02008         f = list[i];
02009         while (f != sentinel) {
02010             TotalRefCount += f->ref;
02011             f = f->next;
02012         }
02013     }
02014 
02015     arccounter = (int) (table->subtables[y].keys *
02016                  (table->arcviolation/100.0) + 0.5);
02017     res = arccount >= TotalRefCount - arccounter;
02018 
02019 #if defined(DD_DEBUG) && defined(DD_VERBOSE)
02020     if (res) {
02021         (void) fprintf(table->out,
02022                        "Found extended symmetry! x = %d\ty = %d\tPos(%d,%d)\n",
02023                        xindex,yindex,x,y);
02024     }
02025 #endif
02026 
02027 #ifdef DD_STATS
02028     if (res)
02029         extsymm++;
02030 #endif
02031     return(res);
02032 
02033 } 
02034 
02035 
02046 static int
02047 ddVarGroupCheck(
02048   DdManager * table,
02049   int x,
02050   int y)
02051 {
02052     int xindex = table->invperm[x];
02053     int yindex = table->invperm[y];
02054 
02055     if (Cudd_bddIsVarToBeUngrouped(table, xindex)) return(0);
02056 
02057     if (Cudd_bddReadPairIndex(table, xindex) == yindex) {
02058         if (ddIsVarHandled(table, xindex) ||
02059             ddIsVarHandled(table, yindex)) {
02060             if (Cudd_bddIsVarToBeGrouped(table, xindex) ||
02061                 Cudd_bddIsVarToBeGrouped(table, yindex) ) {
02062                 if (table->keys - table->isolated <= originalSize) {
02063                     return(1);
02064                 }
02065             }
02066         }
02067     }
02068 
02069     return(0);
02070 
02071 } 
02072 
02073 
02086 static int
02087 ddSetVarHandled(
02088   DdManager *dd,
02089   int index)
02090 {
02091     if (index >= dd->size || index < 0) return(0);
02092     dd->subtables[dd->perm[index]].varHandled = 1;
02093     return(1);
02094 
02095 } 
02096 
02097 
02110 static int
02111 ddResetVarHandled(
02112   DdManager *dd,
02113   int index)
02114 {
02115     if (index >= dd->size || index < 0) return(0);
02116     dd->subtables[dd->perm[index]].varHandled = 0;
02117     return(1);
02118 
02119 } 
02120 
02121 
02134 static int
02135 ddIsVarHandled(
02136   DdManager *dd,
02137   int index)
02138 {
02139     if (index >= dd->size || index < 0) return(-1);
02140     return dd->subtables[dd->perm[index]].varHandled;
02141 
02142 }