00001
00043 #include "util_hack.h"
00044 #include "cuddInt.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #ifndef lint
00064 static char rcsid[] DD_UNUSED = "$Id: cuddExact.c,v 1.1.1.1 2003/02/24 22:23:52 wjiang Exp $";
00065 #endif
00066
00067 #ifdef DD_STATS
00068 static int ddTotalShuffles;
00069 #endif
00070
00071
00072
00073
00074
00077
00078
00079
00080
00081 static int getMaxBinomial ARGS((int n));
00082 static int gcd ARGS((int x, int y));
00083 static DdHalfWord ** getMatrix ARGS((int rows, int cols));
00084 static void freeMatrix ARGS((DdHalfWord **matrix));
00085 static int getLevelKeys ARGS((DdManager *table, int l));
00086 static int ddShuffle ARGS((DdManager *table, DdHalfWord *permutation, int lower, int upper));
00087 static int ddSiftUp ARGS((DdManager *table, int x, int xLow));
00088 static int updateUB ARGS((DdManager *table, int oldBound, DdHalfWord *bestOrder, int lower, int upper));
00089 static int ddCountRoots ARGS((DdManager *table, int lower, int upper));
00090 static void ddClearGlobal ARGS((DdManager *table, int lower, int maxlevel));
00091 static int computeLB ARGS((DdManager *table, DdHalfWord *order, int roots, int cost, int lower, int upper, int level));
00092 static int updateEntry ARGS((DdManager *table, DdHalfWord *order, int level, int cost, DdHalfWord **orders, int *costs, int subsets, char *mask, int lower, int upper));
00093 static void pushDown ARGS((DdHalfWord *order, int j, int level));
00094 static DdHalfWord * initSymmInfo ARGS((DdManager *table, int lower, int upper));
00095 static int checkSymmInfo ARGS((DdManager *table, DdHalfWord *symmInfo, int index, int level));
00096
00100
00101
00102
00103
00104
00105
00106
00107
00108
00122 int
00123 cuddExact(
00124 DdManager * table,
00125 int lower,
00126 int upper)
00127 {
00128 int k, i, j;
00129 int maxBinomial, oldSubsets, newSubsets;
00130 int subsetCost;
00131 int size;
00132 int unused, nvars, level, result;
00133 int upperBound, lowerBound, cost;
00134 int roots;
00135 char *mask = NULL;
00136 DdHalfWord *symmInfo = NULL;
00137 DdHalfWord **newOrder = NULL;
00138 DdHalfWord **oldOrder = NULL;
00139 int *newCost = NULL;
00140 int *oldCost = NULL;
00141 DdHalfWord **tmpOrder;
00142 int *tmpCost;
00143 DdHalfWord *bestOrder = NULL;
00144 DdHalfWord *order;
00145 #ifdef DD_STATS
00146 int ddTotalSubsets;
00147 #endif
00148
00149
00150
00151 while (table->subtables[lower].keys == 1 &&
00152 table->vars[table->invperm[lower]]->ref == 1 &&
00153 lower < upper)
00154 lower++;
00155 while (table->subtables[upper].keys == 1 &&
00156 table->vars[table->invperm[upper]]->ref == 1 &&
00157 lower < upper)
00158 upper--;
00159 if (lower == upper) return(1);
00160
00161
00162
00163 result = cuddSymmSiftingConv(table,lower,upper);
00164 if (result == 0) goto cuddExactOutOfMem;
00165
00166 #ifdef DD_STATS
00167 (void) fprintf(table->out,"\n");
00168 ddTotalShuffles = 0;
00169 ddTotalSubsets = 0;
00170 #endif
00171
00172
00173 nvars = table->size;
00174 size = upper - lower + 1;
00175
00176
00177 unused = 0;
00178 for (i = lower + 1; i < upper; i++) {
00179 if (table->subtables[i].keys == 1 &&
00180 table->vars[table->invperm[i]]->ref == 1)
00181 unused++;
00182 }
00183
00184
00185 maxBinomial = getMaxBinomial(size - unused);
00186 if (maxBinomial == -1) goto cuddExactOutOfMem;
00187
00188 newOrder = getMatrix(maxBinomial, size);
00189 if (newOrder == NULL) goto cuddExactOutOfMem;
00190
00191 newCost = ALLOC(int, maxBinomial);
00192 if (newCost == NULL) goto cuddExactOutOfMem;
00193
00194 oldOrder = getMatrix(maxBinomial, size);
00195 if (oldOrder == NULL) goto cuddExactOutOfMem;
00196
00197 oldCost = ALLOC(int, maxBinomial);
00198 if (oldCost == NULL) goto cuddExactOutOfMem;
00199
00200 bestOrder = ALLOC(DdHalfWord, size);
00201 if (bestOrder == NULL) goto cuddExactOutOfMem;
00202
00203 mask = ALLOC(char, nvars);
00204 if (mask == NULL) goto cuddExactOutOfMem;
00205
00206 symmInfo = initSymmInfo(table, lower, upper);
00207 if (symmInfo == NULL) goto cuddExactOutOfMem;
00208
00209 roots = ddCountRoots(table, lower, upper);
00210
00211
00212
00213
00214
00215
00216 oldSubsets = 1;
00217 for (i = 0; i < size; i++) {
00218 oldOrder[0][i] = bestOrder[i] = (DdHalfWord) table->invperm[i+lower];
00219 }
00220 subsetCost = table->constants.keys;
00221 for (i = upper + 1; i < nvars; i++)
00222 subsetCost += getLevelKeys(table,i);
00223 oldCost[0] = subsetCost;
00224
00225 upperBound = table->keys - table->isolated;
00226
00227
00228 for (k = 1; k <= size; k++) {
00229 #if DD_STATS
00230 (void) fprintf(table->out,"Processing subsets of size %d\n", k);
00231 fflush(table->out);
00232 #endif
00233 newSubsets = 0;
00234 level = size - k;
00235
00236 for (i = 0; i < oldSubsets; i++) {
00237 order = oldOrder[i];
00238 cost = oldCost[i];
00239 lowerBound = computeLB(table, order, roots, cost, lower, upper,
00240 level);
00241 if (lowerBound >= upperBound)
00242 continue;
00243
00244 result = ddShuffle(table, order, lower, upper);
00245 if (result == 0) goto cuddExactOutOfMem;
00246 upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
00247
00248 for (j = level; j >= 0; j--) {
00249
00250 if (table->subtables[j+lower-1].keys == 1 &&
00251 table->vars[table->invperm[j+lower-1]]->ref == 1) continue;
00252
00253 subsetCost = cost + getLevelKeys(table, lower + level);
00254 newSubsets = updateEntry(table, order, level, subsetCost,
00255 newOrder, newCost, newSubsets, mask,
00256 lower, upper);
00257 if (j == 0)
00258 break;
00259 if (checkSymmInfo(table, symmInfo, order[j-1], level) == 0)
00260 continue;
00261 pushDown(order,j-1,level);
00262
00263 result = ddShuffle(table, order, lower, upper);
00264 if (result == 0) goto cuddExactOutOfMem;
00265 upperBound = updateUB(table,upperBound,bestOrder,lower,upper);
00266 }
00267 }
00268
00269
00270 tmpOrder = oldOrder; tmpCost = oldCost;
00271 oldOrder = newOrder; oldCost = newCost;
00272 newOrder = tmpOrder; newCost = tmpCost;
00273 #ifdef DD_STATS
00274 ddTotalSubsets += newSubsets;
00275 #endif
00276 oldSubsets = newSubsets;
00277 }
00278 result = ddShuffle(table, bestOrder, lower, upper);
00279 if (result == 0) goto cuddExactOutOfMem;
00280 #ifdef DD_STATS
00281 #ifdef DD_VERBOSE
00282 (void) fprintf(table->out,"\n");
00283 #endif
00284 (void) fprintf(table->out,"#:S_EXACT %8d: total subsets\n",
00285 ddTotalSubsets);
00286 (void) fprintf(table->out,"#:H_EXACT %8d: total shuffles",
00287 ddTotalShuffles);
00288 #endif
00289
00290 freeMatrix(newOrder);
00291 freeMatrix(oldOrder);
00292 FREE(bestOrder);
00293 FREE(oldCost);
00294 FREE(newCost);
00295 FREE(symmInfo);
00296 FREE(mask);
00297 return(1);
00298
00299 cuddExactOutOfMem:
00300
00301 if (newOrder != NULL) freeMatrix(newOrder);
00302 if (oldOrder != NULL) freeMatrix(oldOrder);
00303 if (bestOrder != NULL) FREE(bestOrder);
00304 if (oldCost != NULL) FREE(oldCost);
00305 if (newCost != NULL) FREE(newCost);
00306 if (symmInfo != NULL) FREE(symmInfo);
00307 if (mask != NULL) FREE(mask);
00308 table->errorCode = CUDD_MEMORY_OUT;
00309 return(0);
00310
00311 }
00312
00313
00329 static int
00330 getMaxBinomial(
00331 int n)
00332 {
00333 int *numerator;
00334 int i, j, k, y, g, result;
00335
00336 k = (n & ~1) >> 1;
00337
00338 numerator = ALLOC(int,k);
00339 if (numerator == NULL) return(-1);
00340
00341 for (i = 0; i < k; i++)
00342 numerator[i] = n - i;
00343
00344 for (i = k; i > 1; i--) {
00345 y = i;
00346 for (j = 0; j < k; j++) {
00347 if (numerator[j] == 1) continue;
00348 g = gcd(numerator[j], y);
00349 if (g != 1) {
00350 numerator[j] /= g;
00351 if (y == g) break;
00352 y /= g;
00353 }
00354 }
00355 }
00356
00357 result = 1;
00358 for (i = 0; i < k; i++)
00359 result *= numerator[i];
00360
00361 FREE(numerator);
00362 return(result);
00363
00364 }
00365
00366
00379 static int
00380 gcd(
00381 int x,
00382 int y)
00383 {
00384 int a;
00385 int b;
00386 int lsbMask;
00387
00388
00389 if (x == 0) return(y);
00390 if (y == 0) return(x);
00391
00392 a = x; b = y; lsbMask = 1;
00393
00394
00395
00396
00397 while (a != b) {
00398 if (a & lsbMask) {
00399 if (b & lsbMask) {
00400 if (a < b) {
00401 b = (b - a) >> 1;
00402 } else {
00403 a = (a - b) >> 1;
00404 }
00405 } else {
00406 b >>= 1;
00407 }
00408 } else {
00409 if (b & lsbMask) {
00410 a >>= 1;
00411 } else {
00412 lsbMask <<= 1;
00413 }
00414 }
00415 }
00416
00417 return(a);
00418
00419 }
00420
00421
00434 static DdHalfWord **
00435 getMatrix(
00436 int rows ,
00437 int cols )
00438 {
00439 DdHalfWord **matrix;
00440 int i;
00441
00442 if (cols*rows == 0) return(NULL);
00443 matrix = ALLOC(DdHalfWord *, rows);
00444 if (matrix == NULL) return(NULL);
00445 matrix[0] = ALLOC(DdHalfWord, cols*rows);
00446 if (matrix[0] == NULL) return(NULL);
00447 for (i = 1; i < rows; i++) {
00448 matrix[i] = matrix[i-1] + cols;
00449 }
00450 return(matrix);
00451
00452 }
00453
00454
00466 static void
00467 freeMatrix(
00468 DdHalfWord ** matrix)
00469 {
00470 FREE(matrix[0]);
00471 FREE(matrix);
00472 return;
00473
00474 }
00475
00476
00489 static int
00490 getLevelKeys(
00491 DdManager * table,
00492 int l)
00493 {
00494 int isolated;
00495 int x;
00496
00497 x = table->invperm[l];
00498 isolated = table->vars[x]->ref == 1;
00499
00500 return(table->subtables[l].keys - isolated);
00501
00502 }
00503
00504
00521 static int
00522 ddShuffle(
00523 DdManager * table,
00524 DdHalfWord * permutation,
00525 int lower,
00526 int upper)
00527 {
00528 DdHalfWord index;
00529 int level;
00530 int position;
00531 int numvars;
00532 int result;
00533 #ifdef DD_STATS
00534 long localTime;
00535 int initialSize;
00536 #ifdef DD_VERBOSE
00537 int finalSize;
00538 #endif
00539 int previousSize;
00540 #endif
00541
00542 #ifdef DD_STATS
00543 localTime = util_cpu_time();
00544 initialSize = table->keys - table->isolated;
00545 #endif
00546
00547 numvars = table->size;
00548
00549 #if 0
00550 (void) fprintf(table->out,"%d:", ddTotalShuffles);
00551 for (level = 0; level < numvars; level++) {
00552 (void) fprintf(table->out," %d", table->invperm[level]);
00553 }
00554 (void) fprintf(table->out,"\n");
00555 #endif
00556
00557 for (level = 0; level <= upper - lower; level++) {
00558 index = permutation[level];
00559 position = table->perm[index];
00560 #ifdef DD_STATS
00561 previousSize = table->keys - table->isolated;
00562 #endif
00563 result = ddSiftUp(table,position,level+lower);
00564 if (!result) return(0);
00565 }
00566
00567 #ifdef DD_STATS
00568 ddTotalShuffles++;
00569 #ifdef DD_VERBOSE
00570 finalSize = table->keys - table->isolated;
00571 if (finalSize < initialSize) {
00572 (void) fprintf(table->out,"-");
00573 } else if (finalSize > initialSize) {
00574 (void) fprintf(table->out,"+");
00575 } else {
00576 (void) fprintf(table->out,"=");
00577 }
00578 if ((ddTotalShuffles & 63) == 0) (void) fprintf(table->out,"\n");
00579 fflush(table->out);
00580 #endif
00581 #endif
00582
00583 return(1);
00584
00585 }
00586
00587
00601 static int
00602 ddSiftUp(
00603 DdManager * table,
00604 int x,
00605 int xLow)
00606 {
00607 int y;
00608 int size;
00609
00610 y = cuddNextLow(table,x);
00611 while (y >= xLow) {
00612 size = cuddSwapInPlace(table,y,x);
00613 if (size == 0) {
00614 return(0);
00615 }
00616 x = y;
00617 y = cuddNextLow(table,x);
00618 }
00619 return(1);
00620
00621 }
00622
00623
00636 static int
00637 updateUB(
00638 DdManager * table,
00639 int oldBound,
00640 DdHalfWord * bestOrder,
00641 int lower,
00642 int upper)
00643 {
00644 int i;
00645 int newBound = table->keys - table->isolated;
00646
00647 if (newBound < oldBound) {
00648 #ifdef DD_STATS
00649 (void) fprintf(table->out,"New upper bound = %d\n", newBound);
00650 fflush(table->out);
00651 #endif
00652 for (i = lower; i <= upper; i++)
00653 bestOrder[i-lower] = (DdHalfWord) table->invperm[i];
00654 return(newBound);
00655 } else {
00656 return(oldBound);
00657 }
00658
00659 }
00660
00661
00678 static int
00679 ddCountRoots(
00680 DdManager * table,
00681 int lower,
00682 int upper)
00683 {
00684 int i,j;
00685 DdNode *f;
00686 DdNodePtr *nodelist;
00687 DdNode *sentinel = &(table->sentinel);
00688 int slots;
00689 int roots = 0;
00690 int maxlevel = lower;
00691
00692 for (i = lower; i <= upper; i++) {
00693 nodelist = table->subtables[i].nodelist;
00694 slots = table->subtables[i].slots;
00695 for (j = 0; j < slots; j++) {
00696 f = nodelist[j];
00697 while (f != sentinel) {
00698
00699
00700
00701
00702
00703
00704 if (!Cudd_IsComplement(f->next)) {
00705 if (f != table->vars[f->index]) {
00706 roots++;
00707 }
00708 }
00709 if (!Cudd_IsConstant(cuddT(f))) {
00710 cuddT(f)->next = Cudd_Complement(cuddT(f)->next);
00711 if (table->perm[cuddT(f)->index] > maxlevel)
00712 maxlevel = table->perm[cuddT(f)->index];
00713 }
00714 if (!Cudd_IsConstant(cuddE(f))) {
00715 Cudd_Regular(cuddE(f))->next =
00716 Cudd_Complement(Cudd_Regular(cuddE(f))->next);
00717 if (table->perm[Cudd_Regular(cuddE(f))->index] > maxlevel)
00718 maxlevel = table->perm[Cudd_Regular(cuddE(f))->index];
00719 }
00720 f = Cudd_Regular(f->next);
00721 }
00722 }
00723 }
00724 ddClearGlobal(table, lower, maxlevel);
00725
00726 return(roots);
00727
00728 }
00729
00730
00745 static void
00746 ddClearGlobal(
00747 DdManager * table,
00748 int lower,
00749 int maxlevel)
00750 {
00751 int i,j;
00752 DdNode *f;
00753 DdNodePtr *nodelist;
00754 DdNode *sentinel = &(table->sentinel);
00755 int slots;
00756
00757 for (i = lower; i <= maxlevel; i++) {
00758 nodelist = table->subtables[i].nodelist;
00759 slots = table->subtables[i].slots;
00760 for (j = 0; j < slots; j++) {
00761 f = nodelist[j];
00762 while (f != sentinel) {
00763 f->next = Cudd_Regular(f->next);
00764 f = f->next;
00765 }
00766 }
00767 }
00768
00769 }
00770
00771
00791 static int
00792 computeLB(
00793 DdManager * table ,
00794 DdHalfWord * order ,
00795 int roots ,
00796 int cost ,
00797 int lower ,
00798 int upper ,
00799 int level
00800 )
00801 {
00802 int i;
00803 int lb = cost;
00804 int lb1 = 0;
00805 int lb2;
00806 int support;
00807 DdHalfWord ref;
00808
00809
00810
00811
00812 for (i = 0; i < lower; i++) {
00813 lb += getLevelKeys(table,i);
00814 }
00815
00816
00817
00818 for (i = lower; i <= lower+level; i++) {
00819 support = table->subtables[i].keys > 1 ||
00820 table->vars[order[i-lower]]->ref > 1;
00821 lb1 += support;
00822 }
00823
00824
00825
00826 if (lower+level+1 < table->size) {
00827 if (lower+level < upper)
00828 ref = table->vars[order[level+1]]->ref;
00829 else
00830 ref = table->vars[table->invperm[upper+1]]->ref;
00831 lb2 = table->subtables[lower+level+1].keys -
00832 (ref > (DdHalfWord) 1) - roots;
00833 } else {
00834 lb2 = 0;
00835 }
00836
00837 lb += lb1 > lb2 ? lb1 : lb2;
00838
00839 return(lb);
00840
00841 }
00842
00843
00858 static int
00859 updateEntry(
00860 DdManager * table,
00861 DdHalfWord * order,
00862 int level,
00863 int cost,
00864 DdHalfWord ** orders,
00865 int * costs,
00866 int subsets,
00867 char * mask,
00868 int lower,
00869 int upper)
00870 {
00871 int i, j;
00872 int size = upper - lower + 1;
00873
00874
00875 for (i = lower; i <= upper; i++)
00876 mask[table->invperm[i]] = 0;
00877 for (i = level; i < size; i++)
00878 mask[order[i]] = 1;
00879
00880
00881 for (i = 0; i < subsets; i++) {
00882 DdHalfWord *subset = orders[i];
00883 for (j = level; j < size; j++) {
00884 if (mask[subset[j]] == 0)
00885 break;
00886 }
00887 if (j == size)
00888 break;
00889 }
00890 if (i == subsets || cost < costs[i]) {
00891 for (j = 0; j < size; j++)
00892 orders[i][j] = order[j];
00893 costs[i] = cost;
00894 subsets += (i == subsets);
00895 }
00896 return(subsets);
00897
00898 }
00899
00900
00912 static void
00913 pushDown(
00914 DdHalfWord * order,
00915 int j,
00916 int level)
00917 {
00918 int i;
00919 DdHalfWord tmp;
00920
00921 tmp = order[j];
00922 for (i = j; i < level; i++) {
00923 order[i] = order[i+1];
00924 }
00925 order[level] = tmp;
00926 return;
00927
00928 }
00929
00930
00950 static DdHalfWord *
00951 initSymmInfo(
00952 DdManager * table,
00953 int lower,
00954 int upper)
00955 {
00956 int level, index, next, nextindex;
00957 DdHalfWord *symmInfo;
00958
00959 symmInfo = ALLOC(DdHalfWord, table->size);
00960 if (symmInfo == NULL) return(NULL);
00961
00962 for (level = lower; level <= upper; level++) {
00963 index = table->invperm[level];
00964 next = table->subtables[level].next;
00965 nextindex = table->invperm[next];
00966 symmInfo[index] = nextindex;
00967 }
00968 return(symmInfo);
00969
00970 }
00971
00972
00986 static int
00987 checkSymmInfo(
00988 DdManager * table,
00989 DdHalfWord * symmInfo,
00990 int index,
00991 int level)
00992 {
00993 int i;
00994
00995 i = symmInfo[index];
00996 while (i != index) {
00997 if (index < i && table->perm[i] <= level)
00998 return(0);
00999 i = symmInfo[i];
01000 }
01001 return(1);
01002
01003 }
01004