00001
00065 #include "util.h"
00066 #include "cuddInt.h"
00067
00068
00069
00070
00071
00072
00073 #define BETA 0.6
00074 #define ALPHA 0.90
00075 #define EXC_PROB 0.4
00076 #define JUMP_UP_PROB 0.36
00077 #define MAXGEN_RATIO 15.0
00078 #define STOP_TEMP 1.0
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 #ifndef lint
00095 static char rcsid[] DD_UNUSED = "$Id: cuddAnneal.c,v 1.14 2004/08/13 18:04:46 fabio Exp $";
00096 #endif
00097
00098 #ifdef DD_STATS
00099 extern int ddTotalNumberSwapping;
00100 extern int ddTotalNISwaps;
00101 static int tosses;
00102 static int acceptances;
00103 #endif
00104
00105
00106
00107
00108
00109
00112
00113
00114
00115
00116 static int stopping_criterion (int c1, int c2, int c3, int c4, double temp);
00117 static double random_generator (void);
00118 static int ddExchange (DdManager *table, int x, int y, double temp);
00119 static int ddJumpingAux (DdManager *table, int x, int x_low, int x_high, double temp);
00120 static Move * ddJumpingUp (DdManager *table, int x, int x_low, int initial_size);
00121 static Move * ddJumpingDown (DdManager *table, int x, int x_high, int initial_size);
00122 static int siftBackwardProb (DdManager *table, Move *moves, int size, double temp);
00123 static void copyOrder (DdManager *table, int *array, int lower, int upper);
00124 static int restoreOrder (DdManager *table, int *array, int lower, int upper);
00125
00129
00130
00131
00132
00133
00134
00135
00136
00137
00153 int
00154 cuddAnnealing(
00155 DdManager * table,
00156 int lower,
00157 int upper)
00158 {
00159 int nvars;
00160 int size;
00161 int x,y;
00162 int result;
00163 int c1, c2, c3, c4;
00164 int BestCost;
00165 int *BestOrder;
00166 double NewTemp, temp;
00167 double rand1;
00168 int innerloop, maxGen;
00169 int ecount, ucount, dcount;
00170
00171 nvars = upper - lower + 1;
00172
00173 result = cuddSifting(table,lower,upper);
00174 #ifdef DD_STATS
00175 (void) fprintf(table->out,"\n");
00176 #endif
00177 if (result == 0) return(0);
00178
00179 size = table->keys - table->isolated;
00180
00181
00182 BestCost = size;
00183 BestOrder = ALLOC(int,nvars);
00184 if (BestOrder == NULL) {
00185 table->errorCode = CUDD_MEMORY_OUT;
00186 return(0);
00187 }
00188 copyOrder(table,BestOrder,lower,upper);
00189
00190 temp = BETA * size;
00191 maxGen = (int) (MAXGEN_RATIO * nvars);
00192
00193 c1 = size + 10;
00194 c2 = c1 + 10;
00195 c3 = size;
00196 c4 = c2 + 10;
00197 ecount = ucount = dcount = 0;
00198
00199 while (!stopping_criterion(c1, c2, c3, c4, temp)) {
00200 #ifdef DD_STATS
00201 (void) fprintf(table->out,"temp=%f\tsize=%d\tgen=%d\t",
00202 temp,size,maxGen);
00203 tosses = acceptances = 0;
00204 #endif
00205 for (innerloop = 0; innerloop < maxGen; innerloop++) {
00206
00207 x = (int) Cudd_Random() % nvars;
00208 do {
00209 y = (int) Cudd_Random() % nvars;
00210 } while (x == y);
00211 x += lower;
00212 y += lower;
00213 if (x > y) {
00214 int tmp = x;
00215 x = y;
00216 y = tmp;
00217 }
00218
00219
00220 rand1 = random_generator();
00221 if (rand1 < EXC_PROB) {
00222 result = ddExchange(table,x,y,temp);
00223 ecount++;
00224 #if 0
00225 (void) fprintf(table->out,
00226 "Exchange of %d and %d: size = %d\n",
00227 x,y,table->keys - table->isolated);
00228 #endif
00229 } else if (rand1 < EXC_PROB + JUMP_UP_PROB) {
00230 result = ddJumpingAux(table,y,x,y,temp);
00231 ucount++;
00232 #if 0
00233 (void) fprintf(table->out,
00234 "Jump up of %d to %d: size = %d\n",
00235 y,x,table->keys - table->isolated);
00236 #endif
00237 } else {
00238 result = ddJumpingAux(table,x,x,y,temp);
00239 dcount++;
00240 #if 0
00241 (void) fprintf(table->out,
00242 "Jump down of %d to %d: size = %d\n",
00243 x,y,table->keys - table->isolated);
00244 #endif
00245 }
00246
00247 if (!result) {
00248 FREE(BestOrder);
00249 return(0);
00250 }
00251
00252 size = table->keys - table->isolated;
00253 if (size < BestCost) {
00254 BestCost = size;
00255 copyOrder(table,BestOrder,lower,upper);
00256 }
00257 }
00258 c1 = c2;
00259 c2 = c3;
00260 c3 = c4;
00261 c4 = size;
00262 NewTemp = ALPHA * temp;
00263 if (NewTemp >= 1.0) {
00264 maxGen = (int)(log(NewTemp) / log(temp) * maxGen);
00265 }
00266 temp = NewTemp;
00267 #ifdef DD_STATS
00268 (void) fprintf(table->out,"uphill = %d\taccepted = %d\n",
00269 tosses,acceptances);
00270 fflush(table->out);
00271 #endif
00272 }
00273
00274 result = restoreOrder(table,BestOrder,lower,upper);
00275 FREE(BestOrder);
00276 if (!result) return(0);
00277 #ifdef DD_STATS
00278 fprintf(table->out,"#:N_EXCHANGE %8d : total exchanges\n",ecount);
00279 fprintf(table->out,"#:N_JUMPUP %8d : total jumps up\n",ucount);
00280 fprintf(table->out,"#:N_JUMPDOWN %8d : total jumps down",dcount);
00281 #endif
00282 return(1);
00283
00284 }
00285
00286
00287
00288
00289
00290
00304 static int
00305 stopping_criterion(
00306 int c1,
00307 int c2,
00308 int c3,
00309 int c4,
00310 double temp)
00311 {
00312 if (STOP_TEMP < temp) {
00313 return(0);
00314 } else if ((c1 == c2) && (c1 == c3) && (c1 == c4)) {
00315 return(1);
00316 } else {
00317 return(0);
00318 }
00319
00320 }
00321
00322
00334 static double
00335 random_generator(void)
00336 {
00337 return((double)(Cudd_Random() / 2147483561.0));
00338
00339 }
00340
00341
00354 static int
00355 ddExchange(
00356 DdManager * table,
00357 int x,
00358 int y,
00359 double temp)
00360 {
00361 Move *move,*moves;
00362 int tmp;
00363 int x_ref,y_ref;
00364 int x_next,y_next;
00365 int size, result;
00366 int initial_size, limit_size;
00367
00368 x_ref = x;
00369 y_ref = y;
00370
00371 x_next = cuddNextHigh(table,x);
00372 y_next = cuddNextLow(table,y);
00373 moves = NULL;
00374 initial_size = limit_size = table->keys - table->isolated;
00375
00376 for (;;) {
00377 if (x_next == y_next) {
00378 size = cuddSwapInPlace(table,x,x_next);
00379 if (size == 0) goto ddExchangeOutOfMem;
00380 move = (Move *)cuddDynamicAllocNode(table);
00381 if (move == NULL) goto ddExchangeOutOfMem;
00382 move->x = x;
00383 move->y = x_next;
00384 move->size = size;
00385 move->next = moves;
00386 moves = move;
00387 size = cuddSwapInPlace(table,y_next,y);
00388 if (size == 0) goto ddExchangeOutOfMem;
00389 move = (Move *)cuddDynamicAllocNode(table);
00390 if (move == NULL) goto ddExchangeOutOfMem;
00391 move->x = y_next;
00392 move->y = y;
00393 move->size = size;
00394 move->next = moves;
00395 moves = move;
00396 size = cuddSwapInPlace(table,x,x_next);
00397 if (size == 0) goto ddExchangeOutOfMem;
00398 move = (Move *)cuddDynamicAllocNode(table);
00399 if (move == NULL) goto ddExchangeOutOfMem;
00400 move->x = x;
00401 move->y = x_next;
00402 move->size = size;
00403 move->next = moves;
00404 moves = move;
00405
00406 tmp = x;
00407 x = y;
00408 y = tmp;
00409 } else if (x == y_next) {
00410 size = cuddSwapInPlace(table,x,x_next);
00411 if (size == 0) goto ddExchangeOutOfMem;
00412 move = (Move *)cuddDynamicAllocNode(table);
00413 if (move == NULL) goto ddExchangeOutOfMem;
00414 move->x = x;
00415 move->y = x_next;
00416 move->size = size;
00417 move->next = moves;
00418 moves = move;
00419 tmp = x;
00420 x = y;
00421 y = tmp;
00422 } else {
00423 size = cuddSwapInPlace(table,x,x_next);
00424 if (size == 0) goto ddExchangeOutOfMem;
00425 move = (Move *)cuddDynamicAllocNode(table);
00426 if (move == NULL) goto ddExchangeOutOfMem;
00427 move->x = x;
00428 move->y = x_next;
00429 move->size = size;
00430 move->next = moves;
00431 moves = move;
00432 size = cuddSwapInPlace(table,y_next,y);
00433 if (size == 0) goto ddExchangeOutOfMem;
00434 move = (Move *)cuddDynamicAllocNode(table);
00435 if (move == NULL) goto ddExchangeOutOfMem;
00436 move->x = y_next;
00437 move->y = y;
00438 move->size = size;
00439 move->next = moves;
00440 moves = move;
00441 x = x_next;
00442 y = y_next;
00443 }
00444
00445 x_next = cuddNextHigh(table,x);
00446 y_next = cuddNextLow(table,y);
00447 if (x_next > y_ref) break;
00448
00449 if ((double) size > DD_MAX_REORDER_GROWTH * (double) limit_size) {
00450 break;
00451 } else if (size < limit_size) {
00452 limit_size = size;
00453 }
00454 }
00455
00456 if (y_next>=x_ref) {
00457 size = cuddSwapInPlace(table,y_next,y);
00458 if (size == 0) goto ddExchangeOutOfMem;
00459 move = (Move *)cuddDynamicAllocNode(table);
00460 if (move == NULL) goto ddExchangeOutOfMem;
00461 move->x = y_next;
00462 move->y = y;
00463 move->size = size;
00464 move->next = moves;
00465 moves = move;
00466 }
00467
00468
00469 result = siftBackwardProb(table,moves,initial_size,temp);
00470 if (!result) goto ddExchangeOutOfMem;
00471
00472 while (moves != NULL) {
00473 move = moves->next;
00474 cuddDeallocMove(table, moves);
00475 moves = move;
00476 }
00477 return(1);
00478
00479 ddExchangeOutOfMem:
00480 while (moves != NULL) {
00481 move = moves->next;
00482 cuddDeallocMove(table, moves);
00483 moves = move;
00484 }
00485 return(0);
00486
00487 }
00488
00489
00503 static int
00504 ddJumpingAux(
00505 DdManager * table,
00506 int x,
00507 int x_low,
00508 int x_high,
00509 double temp)
00510 {
00511 Move *move;
00512 Move *moves;
00513 int initial_size;
00514 int result;
00515
00516 initial_size = table->keys - table->isolated;
00517
00518 #ifdef DD_DEBUG
00519 assert(table->subtables[x].keys > 0);
00520 #endif
00521
00522 moves = NULL;
00523
00524 if (cuddNextLow(table,x) < x_low) {
00525 if (cuddNextHigh(table,x) > x_high) return(1);
00526 moves = ddJumpingDown(table,x,x_high,initial_size);
00527
00528 if (moves == NULL) goto ddJumpingAuxOutOfMem;
00529
00530 result = siftBackwardProb(table,moves,initial_size,temp);
00531 if (!result) goto ddJumpingAuxOutOfMem;
00532 } else if (cuddNextHigh(table,x) > x_high) {
00533 moves = ddJumpingUp(table,x,x_low,initial_size);
00534
00535 if (moves == NULL) goto ddJumpingAuxOutOfMem;
00536
00537 result = siftBackwardProb(table,moves,initial_size,temp);
00538 if (!result) goto ddJumpingAuxOutOfMem;
00539 } else {
00540 (void) fprintf(table->err,"Unexpected condition in ddJumping\n");
00541 goto ddJumpingAuxOutOfMem;
00542 }
00543 while (moves != NULL) {
00544 move = moves->next;
00545 cuddDeallocMove(table, moves);
00546 moves = move;
00547 }
00548 return(1);
00549
00550 ddJumpingAuxOutOfMem:
00551 while (moves != NULL) {
00552 move = moves->next;
00553 cuddDeallocMove(table, moves);
00554 moves = move;
00555 }
00556 return(0);
00557
00558 }
00559
00560
00574 static Move *
00575 ddJumpingUp(
00576 DdManager * table,
00577 int x,
00578 int x_low,
00579 int initial_size)
00580 {
00581 Move *moves;
00582 Move *move;
00583 int y;
00584 int size;
00585 int limit_size = initial_size;
00586
00587 moves = NULL;
00588 y = cuddNextLow(table,x);
00589 while (y >= x_low) {
00590 size = cuddSwapInPlace(table,y,x);
00591 if (size == 0) goto ddJumpingUpOutOfMem;
00592 move = (Move *)cuddDynamicAllocNode(table);
00593 if (move == NULL) goto ddJumpingUpOutOfMem;
00594 move->x = y;
00595 move->y = x;
00596 move->size = size;
00597 move->next = moves;
00598 moves = move;
00599 if ((double) size > table->maxGrowth * (double) limit_size) {
00600 break;
00601 } else if (size < limit_size) {
00602 limit_size = size;
00603 }
00604 x = y;
00605 y = cuddNextLow(table,x);
00606 }
00607 return(moves);
00608
00609 ddJumpingUpOutOfMem:
00610 while (moves != NULL) {
00611 move = moves->next;
00612 cuddDeallocMove(table, moves);
00613 moves = move;
00614 }
00615 return(NULL);
00616
00617 }
00618
00619
00633 static Move *
00634 ddJumpingDown(
00635 DdManager * table,
00636 int x,
00637 int x_high,
00638 int initial_size)
00639 {
00640 Move *moves;
00641 Move *move;
00642 int y;
00643 int size;
00644 int limit_size = initial_size;
00645
00646 moves = NULL;
00647 y = cuddNextHigh(table,x);
00648 while (y <= x_high) {
00649 size = cuddSwapInPlace(table,x,y);
00650 if (size == 0) goto ddJumpingDownOutOfMem;
00651 move = (Move *)cuddDynamicAllocNode(table);
00652 if (move == NULL) goto ddJumpingDownOutOfMem;
00653 move->x = x;
00654 move->y = y;
00655 move->size = size;
00656 move->next = moves;
00657 moves = move;
00658 if ((double) size > table->maxGrowth * (double) limit_size) {
00659 break;
00660 } else if (size < limit_size) {
00661 limit_size = size;
00662 }
00663 x = y;
00664 y = cuddNextHigh(table,x);
00665 }
00666 return(moves);
00667
00668 ddJumpingDownOutOfMem:
00669 while (moves != NULL) {
00670 move = moves->next;
00671 cuddDeallocMove(table, moves);
00672 moves = move;
00673 }
00674 return(NULL);
00675
00676 }
00677
00678
00693 static int
00694 siftBackwardProb(
00695 DdManager * table,
00696 Move * moves,
00697 int size,
00698 double temp)
00699 {
00700 Move *move;
00701 int res;
00702 int best_size = size;
00703 double coin, threshold;
00704
00705
00706 for (move = moves; move != NULL; move = move->next) {
00707 if (move->size < best_size) {
00708 best_size = move->size;
00709 }
00710 }
00711
00712
00713
00714
00715
00716 if (best_size == size) {
00717 coin = random_generator();
00718 #ifdef DD_STATS
00719 tosses++;
00720 #endif
00721 threshold = exp(-((double)(table->keys - table->isolated - size))/temp);
00722 if (coin < threshold) {
00723 #ifdef DD_STATS
00724 acceptances++;
00725 #endif
00726 return(1);
00727 }
00728 }
00729
00730
00731
00732
00733 res = table->keys - table->isolated;
00734 for (move = moves; move != NULL; move = move->next) {
00735 if (res == best_size) return(1);
00736 res = cuddSwapInPlace(table,(int)move->x,(int)move->y);
00737 if (!res) return(0);
00738 }
00739
00740 return(1);
00741
00742 }
00743
00744
00757 static void
00758 copyOrder(
00759 DdManager * table,
00760 int * array,
00761 int lower,
00762 int upper)
00763 {
00764 int i;
00765 int nvars;
00766
00767 nvars = upper - lower + 1;
00768 for (i = 0; i < nvars; i++) {
00769 array[i] = table->invperm[i+lower];
00770 }
00771
00772 }
00773
00774
00787 static int
00788 restoreOrder(
00789 DdManager * table,
00790 int * array,
00791 int lower,
00792 int upper)
00793 {
00794 int i, x, y, size;
00795 int nvars = upper - lower + 1;
00796
00797 for (i = 0; i < nvars; i++) {
00798 x = table->perm[array[i]];
00799 #ifdef DD_DEBUG
00800 assert(x >= lower && x <= upper);
00801 #endif
00802 y = cuddNextLow(table,x);
00803 while (y >= i + lower) {
00804 size = cuddSwapInPlace(table,y,x);
00805 if (size == 0) return(0);
00806 x = y;
00807 y = cuddNextLow(table,x);
00808 }
00809 }
00810
00811 return(1);
00812
00813 }
00814