/**Function******************************************************************** Synopsis [Restores the variable order in array by a series of sifts up.] Description [Restores the variable order in array by a series of sifts up. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int restoreOrder( DdManager * table, int * array, int lower, int upper) { int i, x, y, size; int nvars = upper - lower + 1; for (i = 0; i < nvars; i++) { x = table->perm[array[i]]; #ifdef DD_DEBUG assert(x >= lower && x <= upper); #endif y = cuddNextLow(table,x); while (y >= i + lower) { size = cuddSwapInPlace(table,y,x); if (size == 0) return(0); x = y; y = cuddNextLow(table,x); } } return(1); } /* end of restoreOrder */
/** @brief Undoes the swap of two groups. @details x is assumed to be the bottom variable of the first group. y is assumed to be the top variable of the second group. @return the number of keys in the table if successful; 0 otherwise. @sideeffect None */ static int ddSymmGroupMoveBackward( DdManager * table, int x, int y) { int size = (int) (table->keys - table->isolated); int i,j; int xtop,xbot,xsize,ytop,ybot,ysize,newxtop; #ifdef DD_DEBUG assert(x < y); /* We assume that x < y */ #endif /* Find top, bottom, and size for the two groups. */ xbot = x; xtop = table->subtables[x].next; xsize = xbot - xtop + 1; ybot = y; while ((unsigned) ybot < table->subtables[ybot].next) ybot = table->subtables[ybot].next; ytop = y; ysize = ybot - ytop + 1; #ifdef DD_DEBUG assert(xsize > 0); assert(ysize > 0); #endif /* Sift the variables of the second group up through the first group. */ for (i = 1; i <= ysize; i++) { for (j = 1; j <= xsize; j++) { size = cuddSwapInPlace(table,x,y); if (size == 0) return(0); y = x; x = cuddNextLow(table,y); } y = ytop + i; x = y - 1; } /* Fix symmetries. */ y = xtop; for (i = 0; i < ysize-1 ; i++) { table->subtables[y].next = y + 1; y = y + 1; } table->subtables[y].next = xtop; /* y is bottom of its group, join */ /* its symmetry to top of its group */ x = y + 1; newxtop = x; for (i = 0; i < xsize-1 ; i++) { table->subtables[x].next = x + 1; x = x + 1; } table->subtables[x].next = newxtop; /* x is bottom of its group, join */ /* its symmetry to top of its group */ return(size); } /* end of ddSymmGroupMoveBackward */
/**Function******************************************************************** Synopsis [This function is for jumping up.] Description [This is a simplified version of ddSiftingUp. It does not use lower bounding. Returns the set of moves in case of success; NULL if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * ddJumpingUp( DdManager * table, int x, int x_low, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; moves = NULL; y = cuddNextLow(table,x); while (y >= x_low) { size = cuddSwapInPlace(table,y,x); if (size == 0) goto ddJumpingUpOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddJumpingUpOutOfMem; move->x = y; move->y = x; move->size = size; move->next = moves; moves = move; if ((double) size > table->maxGrowth * (double) limit_size) { break; } else if (size < limit_size) { limit_size = size; } x = y; y = cuddNextLow(table,x); } return(moves); ddJumpingUpOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(NULL); } /* end of ddJumpingUp */
/**Function******************************************************************** Synopsis [Moves a variable to a specified position.] Description [If x==x_low, it executes jumping_down. If x==x_high, it executes jumping_up. This funcion is similar to ddSiftingAux. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int ddJumpingAux( DdManager * table, int x, int x_low, int x_high, double temp) { Move *move; Move *moves; /* list of moves */ int initial_size; int result; initial_size = table->keys - table->isolated; #ifdef DD_DEBUG assert(table->subtables[x].keys > 0); #endif moves = NULL; if (cuddNextLow(table,x) < x_low) { if (cuddNextHigh(table,x) > x_high) return(1); moves = ddJumpingDown(table,x,x_high,initial_size); /* after that point x --> x_high unless early termination */ if (moves == NULL) goto ddJumpingAuxOutOfMem; /* move backward and stop at best position or accept uphill move */ result = siftBackwardProb(table,moves,initial_size,temp); if (!result) goto ddJumpingAuxOutOfMem; } else if (cuddNextHigh(table,x) > x_high) { moves = ddJumpingUp(table,x,x_low,initial_size); /* after that point x --> x_low unless early termination */ if (moves == NULL) goto ddJumpingAuxOutOfMem; /* move backward and stop at best position or accept uphill move */ result = siftBackwardProb(table,moves,initial_size,temp); if (!result) goto ddJumpingAuxOutOfMem; } else { (void) fprintf(table->err,"Unexpected condition in ddJumping\n"); goto ddJumpingAuxOutOfMem; } while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(1); ddJumpingAuxOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(0); } /* end of ddJumpingAux */
/**Function******************************************************************** Synopsis [Moves one variable up.] Description [Takes a variable from position x and sifts it up to position x_low; x_low should be less than x. Returns 1 if successful; 0 otherwise] SideEffects [None] SeeAlso [] ******************************************************************************/ static int sift_up( DdManager * table, int x, int x_low) { int y; int size; y = cuddNextLow(table,x); while (y >= x_low) { size = cuddSwapInPlace(table,y,x); if (size == 0) { return(0); } x = y; y = cuddNextLow(table,x); } return(1); } /* end of sift_up */
/**Function******************************************************************** Synopsis [This function is for exchanging two variables, x and y.] Description [This is the same funcion as ddSwapping except for comparison expression. Use probability function, exp(-size_change/temp).] SideEffects [None] SeeAlso [] ******************************************************************************/ static int ddExchange( DdManager * table, int x, int y, double temp) { Move *move,*moves; int tmp; int x_ref,y_ref; int x_next,y_next; int size, result; int initial_size, limit_size; x_ref = x; y_ref = y; x_next = cuddNextHigh(table,x); y_next = cuddNextLow(table,y); moves = NULL; initial_size = limit_size = table->keys - table->isolated; for (;;) { if (x_next == y_next) { size = cuddSwapInPlace(table,x,x_next); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; size = cuddSwapInPlace(table,y_next,y); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; size = cuddSwapInPlace(table,x,x_next); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; tmp = x; x = y; y = tmp; } else if (x == y_next) { size = cuddSwapInPlace(table,x,x_next); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; tmp = x; x = y; y = tmp; } else { size = cuddSwapInPlace(table,x,x_next); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; size = cuddSwapInPlace(table,y_next,y); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; x = x_next; y = y_next; } x_next = cuddNextHigh(table,x); y_next = cuddNextLow(table,y); if (x_next > y_ref) break; if ((double) size > DD_MAX_REORDER_GROWTH * (double) limit_size) { break; } else if (size < limit_size) { limit_size = size; } } if (y_next>=x_ref) { size = cuddSwapInPlace(table,y_next,y); if (size == 0) goto ddExchangeOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddExchangeOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; } /* move backward and stop at best position or accept uphill move */ result = siftBackwardProb(table,moves,initial_size,temp); if (!result) goto ddExchangeOutOfMem; while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(1); ddExchangeOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table,(DdNode *) moves); moves = move; } return(0); } /* end of ddExchange */
/**Function******************************************************************** Synopsis [Moves x up until either it reaches the bound (xLow) or the size of the DD heap increases too much.] Description [Moves x up until either it reaches the bound (xLow) or the size of the DD heap increases too much. Assumes that x is the top of a symmetry group. Checks x for symmetry to the adjacent variables. If symmetry is found, the symmetry group of x is merged with the symmetry group of the other variable. Returns the set of moves in case of success; MV_OOM if memory is full.] SideEffects [None] ******************************************************************************/ static Move * ddSymmSiftingUp( DdManager * table, int y, int xLow) { Move *moves; Move *move; int x; int size; int i; int gxtop,gybot; int limitSize; int xindex, yindex; int zindex; int z; int isolated; int L; /* lower bound on DD size */ #ifdef DD_DEBUG int checkL; #endif moves = NULL; yindex = table->invperm[y]; /* Initialize the lower bound. ** The part of the DD below the bottom of y' group will not change. ** The part of the DD above y that does not interact with y will not ** change. The rest may vanish in the best case, except for ** the nodes at level xLow, which will not vanish, regardless. */ limitSize = L = table->keys - table->isolated; gybot = y; while ((unsigned) gybot < table->subtables[gybot].next) gybot = table->subtables[gybot].next; for (z = xLow + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; L -= table->subtables[z].keys - isolated; } } x = cuddNextLow(table,y); while (x >= xLow && L <= limitSize) { #ifdef DD_DEBUG gybot = y; while ((unsigned) gybot < table->subtables[gybot].next) gybot = table->subtables[gybot].next; checkL = table->keys - table->isolated; for (z = xLow + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; checkL -= table->subtables[z].keys - isolated; } } assert(L == checkL); #endif gxtop = table->subtables[x].next; if (cuddSymmCheck(table,x,y)) { /* Symmetry found, attach symm groups */ table->subtables[x].next = y; i = table->subtables[y].next; while (table->subtables[i].next != (unsigned) y) i = table->subtables[i].next; table->subtables[i].next = gxtop; } else if (table->subtables[x].next == (unsigned) x && table->subtables[y].next == (unsigned) y) { /* x and y have self symmetry */ xindex = table->invperm[x]; size = cuddSwapInPlace(table,x,y); #ifdef DD_DEBUG assert(table->subtables[x].next == (unsigned) x); assert(table->subtables[y].next == (unsigned) y); #endif if (size == 0) goto ddSymmSiftingUpOutOfMem; /* Update the lower bound. */ if (cuddTestInteract(table,xindex,yindex)) { isolated = table->vars[xindex]->ref == 1; L += table->subtables[y].keys - isolated; } move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto ddSymmSiftingUpOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; } else { /* Group move */ size = ddSymmGroupMove(table,x,y,&moves); if (size == 0) goto ddSymmSiftingUpOutOfMem; /* Update the lower bound. */ z = moves->y; do { zindex = table->invperm[z]; if (cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; L += table->subtables[z].keys - isolated; } z = table->subtables[z].next; } while (z != (int) moves->y); if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; } y = gxtop; x = cuddNextLow(table,y); } return(moves); ddSymmSiftingUpOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingUp */