1 /**CFile***********************************************************************
3 FileName [cuddAnneal.c]
7 Synopsis [Reordering of DDs based on simulated annealing]
9 Description [Internal procedures included in this file:
13 Static procedures included in this file:
15 <li> stopping_criterion()
16 <li> random_generator()
21 <li> siftBackwardProb()
29 Author [Jae-Young Jang, Jorgen Sivesind]
31 Copyright [Copyright (c) 1995-2004, Regents of the University of Colorado
35 Redistribution and use in source and binary forms, with or without
36 modification, are permitted provided that the following conditions
39 Redistributions of source code must retain the above copyright
40 notice, this list of conditions and the following disclaimer.
42 Redistributions in binary form must reproduce the above copyright
43 notice, this list of conditions and the following disclaimer in the
44 documentation and/or other materials provided with the distribution.
46 Neither the name of the University of Colorado nor the names of its
47 contributors may be used to endorse or promote products derived from
48 this software without specific prior written permission.
50 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
53 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
54 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
55 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
56 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
58 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
60 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 POSSIBILITY OF SUCH DAMAGE.]
63 ******************************************************************************/
68 /*---------------------------------------------------------------------------*/
69 /* Constant declarations */
70 /*---------------------------------------------------------------------------*/
72 /* Annealing parameters */
76 #define JUMP_UP_PROB 0.36
77 #define MAXGEN_RATIO 15.0
80 /*---------------------------------------------------------------------------*/
81 /* Stucture declarations */
82 /*---------------------------------------------------------------------------*/
85 /*---------------------------------------------------------------------------*/
86 /* Type declarations */
87 /*---------------------------------------------------------------------------*/
90 /*---------------------------------------------------------------------------*/
91 /* Variable declarations */
92 /*---------------------------------------------------------------------------*/
95 static char rcsid
[] DD_UNUSED
= "$Id: cuddAnneal.c,v 1.14 2004/08/13 18:04:46 fabio Exp $";
99 extern int ddTotalNumberSwapping
;
100 extern int ddTotalNISwaps
;
102 static int acceptances
;
105 /*---------------------------------------------------------------------------*/
106 /* Macro declarations */
107 /*---------------------------------------------------------------------------*/
110 /**AutomaticStart*************************************************************/
112 /*---------------------------------------------------------------------------*/
113 /* Static function prototypes */
114 /*---------------------------------------------------------------------------*/
116 static int stopping_criterion (int c1
, int c2
, int c3
, int c4
, double temp
);
117 static double random_generator (void);
118 static int ddExchange (DdManager
*table
, int x
, int y
, double temp
);
119 static int ddJumpingAux (DdManager
*table
, int x
, int x_low
, int x_high
, double temp
);
120 static Move
* ddJumpingUp (DdManager
*table
, int x
, int x_low
, int initial_size
);
121 static Move
* ddJumpingDown (DdManager
*table
, int x
, int x_high
, int initial_size
);
122 static int siftBackwardProb (DdManager
*table
, Move
*moves
, int size
, double temp
);
123 static void copyOrder (DdManager
*table
, int *array
, int lower
, int upper
);
124 static int restoreOrder (DdManager
*table
, int *array
, int lower
, int upper
);
126 /**AutomaticEnd***************************************************************/
129 /*---------------------------------------------------------------------------*/
130 /* Definition of exported functions */
131 /*---------------------------------------------------------------------------*/
133 /*---------------------------------------------------------------------------*/
134 /* Definition of internal functions */
135 /*---------------------------------------------------------------------------*/
138 /**Function********************************************************************
140 Synopsis [Get new variable-order by simulated annealing algorithm.]
142 Description [Get x, y by random selection. Choose either
143 exchange or jump randomly. In case of jump, choose between jump_up
144 and jump_down randomly. Do exchange or jump and get optimal case.
145 Loop until there is no improvement or temperature reaches
146 minimum. Returns 1 in case of success; 0 otherwise.]
152 ******************************************************************************/
166 double NewTemp
, temp
;
168 int innerloop
, maxGen
;
169 int ecount
, ucount
, dcount
;
171 nvars
= upper
- lower
+ 1;
173 result
= cuddSifting(table
,lower
,upper
);
175 (void) fprintf(table
->out
,"\n");
177 if (result
== 0) return(0);
179 size
= table
->keys
- table
->isolated
;
181 /* Keep track of the best order. */
183 BestOrder
= ALLOC(int,nvars
);
184 if (BestOrder
== NULL
) {
185 table
->errorCode
= CUDD_MEMORY_OUT
;
188 copyOrder(table
,BestOrder
,lower
,upper
);
191 maxGen
= (int) (MAXGEN_RATIO
* nvars
);
197 ecount
= ucount
= dcount
= 0;
199 while (!stopping_criterion(c1
, c2
, c3
, c4
, temp
)) {
201 (void) fprintf(table
->out
,"temp=%f\tsize=%d\tgen=%d\t",
203 tosses
= acceptances
= 0;
205 for (innerloop
= 0; innerloop
< maxGen
; innerloop
++) {
206 /* Choose x, y randomly. */
207 x
= (int) Cudd_Random() % nvars
;
209 y
= (int) Cudd_Random() % nvars
;
219 /* Choose move with roulette wheel. */
220 rand1
= random_generator();
221 if (rand1
< EXC_PROB
) {
222 result
= ddExchange(table
,x
,y
,temp
); /* exchange */
225 (void) fprintf(table
->out
,
226 "Exchange of %d and %d: size = %d\n",
227 x
,y
,table
->keys
- table
->isolated
);
229 } else if (rand1
< EXC_PROB
+ JUMP_UP_PROB
) {
230 result
= ddJumpingAux(table
,y
,x
,y
,temp
); /* jumping_up */
233 (void) fprintf(table
->out
,
234 "Jump up of %d to %d: size = %d\n",
235 y
,x
,table
->keys
- table
->isolated
);
238 result
= ddJumpingAux(table
,x
,x
,y
,temp
); /* jumping_down */
241 (void) fprintf(table
->out
,
242 "Jump down of %d to %d: size = %d\n",
243 x
,y
,table
->keys
- table
->isolated
);
252 size
= table
->keys
- table
->isolated
; /* keep current size */
253 if (size
< BestCost
) { /* update best order */
255 copyOrder(table
,BestOrder
,lower
,upper
);
262 NewTemp
= ALPHA
* temp
;
263 if (NewTemp
>= 1.0) {
264 maxGen
= (int)(log(NewTemp
) / log(temp
) * maxGen
);
266 temp
= NewTemp
; /* control variable */
268 (void) fprintf(table
->out
,"uphill = %d\taccepted = %d\n",
274 result
= restoreOrder(table
,BestOrder
,lower
,upper
);
276 if (!result
) return(0);
278 fprintf(table
->out
,"#:N_EXCHANGE %8d : total exchanges\n",ecount
);
279 fprintf(table
->out
,"#:N_JUMPUP %8d : total jumps up\n",ucount
);
280 fprintf(table
->out
,"#:N_JUMPDOWN %8d : total jumps down",dcount
);
284 } /* end of cuddAnnealing */
287 /*---------------------------------------------------------------------------*/
288 /* Definition of static functions */
289 /*---------------------------------------------------------------------------*/
291 /**Function********************************************************************
293 Synopsis [Checks termination condition.]
295 Description [If temperature is STOP_TEMP or there is no improvement
296 then terminates. Returns 1 if the termination criterion is met; 0
303 ******************************************************************************/
312 if (STOP_TEMP
< temp
) {
314 } else if ((c1
== c2
) && (c1
== c3
) && (c1
== c4
)) {
320 } /* end of stopping_criterion */
323 /**Function********************************************************************
325 Synopsis [Random number generator.]
327 Description [Returns a double precision value between 0.0 and 1.0.]
333 ******************************************************************************/
335 random_generator(void)
337 return((double)(Cudd_Random() / 2147483561.0));
339 } /* end of random_generator */
342 /**Function********************************************************************
344 Synopsis [This function is for exchanging two variables, x and y.]
346 Description [This is the same funcion as ddSwapping except for
347 comparison expression. Use probability function, exp(-size_change/temp).]
353 ******************************************************************************/
366 int initial_size
, limit_size
;
371 x_next
= cuddNextHigh(table
,x
);
372 y_next
= cuddNextLow(table
,y
);
374 initial_size
= limit_size
= table
->keys
- table
->isolated
;
377 if (x_next
== y_next
) {
378 size
= cuddSwapInPlace(table
,x
,x_next
);
379 if (size
== 0) goto ddExchangeOutOfMem
;
380 move
= (Move
*)cuddDynamicAllocNode(table
);
381 if (move
== NULL
) goto ddExchangeOutOfMem
;
387 size
= cuddSwapInPlace(table
,y_next
,y
);
388 if (size
== 0) goto ddExchangeOutOfMem
;
389 move
= (Move
*)cuddDynamicAllocNode(table
);
390 if (move
== NULL
) goto ddExchangeOutOfMem
;
396 size
= cuddSwapInPlace(table
,x
,x_next
);
397 if (size
== 0) goto ddExchangeOutOfMem
;
398 move
= (Move
*)cuddDynamicAllocNode(table
);
399 if (move
== NULL
) goto ddExchangeOutOfMem
;
409 } else if (x
== y_next
) {
410 size
= cuddSwapInPlace(table
,x
,x_next
);
411 if (size
== 0) goto ddExchangeOutOfMem
;
412 move
= (Move
*)cuddDynamicAllocNode(table
);
413 if (move
== NULL
) goto ddExchangeOutOfMem
;
423 size
= cuddSwapInPlace(table
,x
,x_next
);
424 if (size
== 0) goto ddExchangeOutOfMem
;
425 move
= (Move
*)cuddDynamicAllocNode(table
);
426 if (move
== NULL
) goto ddExchangeOutOfMem
;
432 size
= cuddSwapInPlace(table
,y_next
,y
);
433 if (size
== 0) goto ddExchangeOutOfMem
;
434 move
= (Move
*)cuddDynamicAllocNode(table
);
435 if (move
== NULL
) goto ddExchangeOutOfMem
;
445 x_next
= cuddNextHigh(table
,x
);
446 y_next
= cuddNextLow(table
,y
);
447 if (x_next
> y_ref
) break;
449 if ((double) size
> DD_MAX_REORDER_GROWTH
* (double) limit_size
) {
451 } else if (size
< limit_size
) {
457 size
= cuddSwapInPlace(table
,y_next
,y
);
458 if (size
== 0) goto ddExchangeOutOfMem
;
459 move
= (Move
*)cuddDynamicAllocNode(table
);
460 if (move
== NULL
) goto ddExchangeOutOfMem
;
468 /* move backward and stop at best position or accept uphill move */
469 result
= siftBackwardProb(table
,moves
,initial_size
,temp
);
470 if (!result
) goto ddExchangeOutOfMem
;
472 while (moves
!= NULL
) {
474 cuddDeallocMove(table
, moves
);
480 while (moves
!= NULL
) {
482 cuddDeallocMove(table
, moves
);
487 } /* end of ddExchange */
490 /**Function********************************************************************
492 Synopsis [Moves a variable to a specified position.]
494 Description [If x==x_low, it executes jumping_down. If x==x_high, it
495 executes jumping_up. This funcion is similar to ddSiftingAux. Returns
496 1 in case of success; 0 otherwise.]
502 ******************************************************************************/
512 Move
*moves
; /* list of moves */
516 initial_size
= table
->keys
- table
->isolated
;
519 assert(table
->subtables
[x
].keys
> 0);
524 if (cuddNextLow(table
,x
) < x_low
) {
525 if (cuddNextHigh(table
,x
) > x_high
) return(1);
526 moves
= ddJumpingDown(table
,x
,x_high
,initial_size
);
527 /* after that point x --> x_high unless early termination */
528 if (moves
== NULL
) goto ddJumpingAuxOutOfMem
;
529 /* move backward and stop at best position or accept uphill move */
530 result
= siftBackwardProb(table
,moves
,initial_size
,temp
);
531 if (!result
) goto ddJumpingAuxOutOfMem
;
532 } else if (cuddNextHigh(table
,x
) > x_high
) {
533 moves
= ddJumpingUp(table
,x
,x_low
,initial_size
);
534 /* after that point x --> x_low unless early termination */
535 if (moves
== NULL
) goto ddJumpingAuxOutOfMem
;
536 /* move backward and stop at best position or accept uphill move */
537 result
= siftBackwardProb(table
,moves
,initial_size
,temp
);
538 if (!result
) goto ddJumpingAuxOutOfMem
;
540 (void) fprintf(table
->err
,"Unexpected condition in ddJumping\n");
541 goto ddJumpingAuxOutOfMem
;
543 while (moves
!= NULL
) {
545 cuddDeallocMove(table
, moves
);
550 ddJumpingAuxOutOfMem
:
551 while (moves
!= NULL
) {
553 cuddDeallocMove(table
, moves
);
558 } /* end of ddJumpingAux */
561 /**Function********************************************************************
563 Synopsis [This function is for jumping up.]
565 Description [This is a simplified version of ddSiftingUp. It does not
566 use lower bounding. Returns the set of moves in case of success; NULL
573 ******************************************************************************/
585 int limit_size
= initial_size
;
588 y
= cuddNextLow(table
,x
);
590 size
= cuddSwapInPlace(table
,y
,x
);
591 if (size
== 0) goto ddJumpingUpOutOfMem
;
592 move
= (Move
*)cuddDynamicAllocNode(table
);
593 if (move
== NULL
) goto ddJumpingUpOutOfMem
;
599 if ((double) size
> table
->maxGrowth
* (double) limit_size
) {
601 } else if (size
< limit_size
) {
605 y
= cuddNextLow(table
,x
);
610 while (moves
!= NULL
) {
612 cuddDeallocMove(table
, moves
);
617 } /* end of ddJumpingUp */
620 /**Function********************************************************************
622 Synopsis [This function is for jumping down.]
624 Description [This is a simplified version of ddSiftingDown. It does not
625 use lower bounding. Returns the set of moves in case of success; NULL
632 ******************************************************************************/
644 int limit_size
= initial_size
;
647 y
= cuddNextHigh(table
,x
);
648 while (y
<= x_high
) {
649 size
= cuddSwapInPlace(table
,x
,y
);
650 if (size
== 0) goto ddJumpingDownOutOfMem
;
651 move
= (Move
*)cuddDynamicAllocNode(table
);
652 if (move
== NULL
) goto ddJumpingDownOutOfMem
;
658 if ((double) size
> table
->maxGrowth
* (double) limit_size
) {
660 } else if (size
< limit_size
) {
664 y
= cuddNextHigh(table
,x
);
668 ddJumpingDownOutOfMem
:
669 while (moves
!= NULL
) {
671 cuddDeallocMove(table
, moves
);
676 } /* end of ddJumpingDown */
679 /**Function********************************************************************
681 Synopsis [Returns the DD to the best position encountered during
682 sifting if there was improvement.]
684 Description [Otherwise, "tosses a coin" to decide whether to keep
685 the current configuration or return the DD to the original
686 one. Returns 1 in case of success; 0 otherwise.]
692 ******************************************************************************/
702 int best_size
= size
;
703 double coin
, threshold
;
705 /* Look for best size during the last sifting */
706 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
707 if (move
->size
< best_size
) {
708 best_size
= move
->size
;
712 /* If best_size equals size, the last sifting did not produce any
713 ** improvement. We now toss a coin to decide whether to retain
714 ** this change or not.
716 if (best_size
== size
) {
717 coin
= random_generator();
721 threshold
= exp(-((double)(table
->keys
- table
->isolated
- size
))/temp
);
722 if (coin
< threshold
) {
730 /* Either there was improvement, or we have decided not to
731 ** accept the uphill move. Go to best position.
733 res
= table
->keys
- table
->isolated
;
734 for (move
= moves
; move
!= NULL
; move
= move
->next
) {
735 if (res
== best_size
) return(1);
736 res
= cuddSwapInPlace(table
,(int)move
->x
,(int)move
->y
);
742 } /* end of sift_backward_prob */
745 /**Function********************************************************************
747 Synopsis [Copies the current variable order to array.]
749 Description [Copies the current variable order to array.
750 At the same time inverts the permutation.]
756 ******************************************************************************/
767 nvars
= upper
- lower
+ 1;
768 for (i
= 0; i
< nvars
; i
++) {
769 array
[i
] = table
->invperm
[i
+lower
];
772 } /* end of copyOrder */
775 /**Function********************************************************************
777 Synopsis [Restores the variable order in array by a series of sifts up.]
779 Description [Restores the variable order in array by a series of sifts up.
780 Returns 1 in case of success; 0 otherwise.]
786 ******************************************************************************/
795 int nvars
= upper
- lower
+ 1;
797 for (i
= 0; i
< nvars
; i
++) {
798 x
= table
->perm
[array
[i
]];
800 assert(x
>= lower
&& x
<= upper
);
802 y
= cuddNextLow(table
,x
);
803 while (y
>= i
+ lower
) {
804 size
= cuddSwapInPlace(table
,y
,x
);
805 if (size
== 0) return(0);
807 y
= cuddNextLow(table
,x
);
813 } /* end of restoreOrder */