/**Function******************************************************************** Synopsis [This function is for jumping down.] Description [This is a simplified version of ddSiftingDown. 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 * ddJumpingDown( DdManager * table, int x, int x_high, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; moves = NULL; y = cuddNextHigh(table,x); while (y <= x_high) { size = cuddSwapInPlace(table,x,y); if (size == 0) goto ddJumpingDownOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddJumpingDownOutOfMem; move->x = x; move->y = y; 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 = cuddNextHigh(table,x); } return(moves); ddJumpingDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(NULL); } /* end of ddJumpingDown */
/**Function******************************************************************** Synopsis [Sifts a variable down and applies the XOR transformation.] Description [Sifts a variable down. Moves x down until either it reaches the bound (xHigh) or the size of the ZDD heap increases too much. Returns the set of moves in case of success; NULL if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * cuddZddLinearDown( DdManager * table, int x, int xHigh, Move * prevMoves) { Move *moves; Move *move; int y; int size, newsize; int limitSize; moves = prevMoves; limitSize = table->keysZ; y = cuddZddNextHigh(table, x); while (y <= xHigh) { size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto cuddZddLinearDownOutOfMem; newsize = cuddZddLinearInPlace(table, x, y); if (newsize == 0) goto cuddZddLinearDownOutOfMem; move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto cuddZddLinearDownOutOfMem; move->x = x; move->y = y; move->next = moves; moves = move; move->flags = CUDD_SWAP_MOVE; if (newsize > size) { /* Undo transformation. The transformation we apply is ** its own inverse. Hence, we just apply the transformation ** again. */ newsize = cuddZddLinearInPlace(table,x,y); if (newsize == 0) goto cuddZddLinearDownOutOfMem; if (newsize != size) { (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize); } } else { size = newsize; move->flags = CUDD_LINEAR_TRANSFORM_MOVE; } move->size = size; if ((double)size > (double)limitSize * table->maxGrowth) break; if (size < limitSize) limitSize = size; x = y; y = cuddZddNextHigh(table, x); } return(moves); cuddZddLinearDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return((Move *) CUDD_OUT_OF_MEM); } /* end of cuddZddLinearDown */
/**Function******************************************************************** Synopsis [Given xLow <= x <= xHigh moves x up and down between the boundaries.] Description [Given xLow <= x <= xHigh moves x up and down between the boundaries. Finds the best position and does the required changes. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddLinearAux( DdManager * table, int x, int xLow, int xHigh) { Move *move; Move *moveUp; /* list of up move */ Move *moveDown; /* list of down move */ int initial_size; int result; initial_size = table->keysZ; #ifdef DD_DEBUG assert(table->subtableZ[x].keys > 0); #endif moveDown = NULL; moveUp = NULL; if (x == xLow) { moveDown = cuddZddLinearDown(table, x, xHigh, NULL); /* At this point x --> xHigh. */ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; /* Move backward and stop at best position. */ result = cuddZddLinearBackward(table, initial_size, moveDown); if (!result) goto cuddZddLinearAuxOutOfMem; } else if (x == xHigh) { moveUp = cuddZddLinearUp(table, x, xLow, NULL); /* At this point x --> xLow. */ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; /* Move backward and stop at best position. */ result = cuddZddLinearBackward(table, initial_size, moveUp); if (!result) goto cuddZddLinearAuxOutOfMem; } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */ moveDown = cuddZddLinearDown(table, x, xHigh, NULL); /* At this point x --> xHigh. */ if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; moveUp = cuddZddUndoMoves(table,moveDown); #ifdef DD_DEBUG assert(moveUp == NULL || moveUp->x == x); #endif moveUp = cuddZddLinearUp(table, x, xLow, moveUp); if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; /* Move backward and stop at best position. */ result = cuddZddLinearBackward(table, initial_size, moveUp); if (!result) goto cuddZddLinearAuxOutOfMem; } else { moveUp = cuddZddLinearUp(table, x, xLow, NULL); /* At this point x --> xHigh. */ if (moveUp == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; /* Then move up. */ moveDown = cuddZddUndoMoves(table,moveUp); #ifdef DD_DEBUG assert(moveDown == NULL || moveDown->y == x); #endif moveDown = cuddZddLinearDown(table, x, xHigh, moveDown); if (moveDown == (Move *) CUDD_OUT_OF_MEM) goto cuddZddLinearAuxOutOfMem; /* Move backward and stop at best position. */ result = cuddZddLinearBackward(table, initial_size, moveDown); if (!result) goto cuddZddLinearAuxOutOfMem; } while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } return(1); cuddZddLinearAuxOutOfMem: if (moveDown != (Move *) CUDD_OUT_OF_MEM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } } if (moveUp != (Move *) CUDD_OUT_OF_MEM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } } return(0); } /* end of cuddZddLinearAux */
/**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; cuddDeallocMove(table, moves); moves = move; } return(1); ddExchangeOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(0); } /* end of ddExchange */
/**Function******************************************************************** Synopsis [Given xLow <= x <= xHigh moves x up and down between the boundaries.] Description [Given xLow <= x <= xHigh moves x up and down between the boundaries. Finds the best position and does the required changes. Assumes that x is either an isolated variable, or it is the bottom of a symmetry group. All symmetries may not have been found, because of exceeded growth limit. Returns 1 if successful; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddSymmSiftingConvAux( DdManager * table, int x, int xLow, int xHigh) { Move *move; Move *moveUp; /* list of up moves */ Move *moveDown; /* list of down moves */ int initialSize; int result; int i; int initGroupSize, finalGroupSize; initialSize = table->keys - table->isolated; moveDown = NULL; moveUp = NULL; if (x == xLow) { /* Sift down */ #ifdef DD_DEBUG /* x is bottom of symmetry group */ assert((unsigned) x >= table->subtables[x].next); #endif i = table->subtables[x].next; initGroupSize = x - i + 1; moveDown = ddSymmSiftingDown(table,x,xHigh); /* at this point x == xHigh, unless early term */ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveDown == NULL) return(1); x = moveDown->y; i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } #ifdef DD_DEBUG /* x should be the top of the symmetric group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif finalGroupSize = i - x + 1; if (initGroupSize == finalGroupSize) { /* No new symmetries detected, go back to best position */ result = ddSymmSiftingBackward(table,moveDown,initialSize); } else { initialSize = table->keys - table->isolated; moveUp = ddSymmSiftingUp(table,x,xLow); result = ddSymmSiftingBackward(table,moveUp,initialSize); } if (!result) goto ddSymmSiftingConvAuxOutOfMem; } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */ /* Find top of x's symm group */ while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; i = x; /* bottom */ x = table->subtables[x].next; /* top */ if (x == xLow) return(1); initGroupSize = i - x + 1; moveUp = ddSymmSiftingUp(table,x,xLow); /* at this point x == xLow, unless early term */ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveUp == NULL) return(1); x = moveUp->x; i = table->subtables[x].next; #ifdef DD_DEBUG /* x should be the bottom of the symmetry group and i the top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif finalGroupSize = x - i + 1; if (initGroupSize == finalGroupSize) { /* No new symmetry groups detected, return to best position */ result = ddSymmSiftingBackward(table,moveUp,initialSize); } else { initialSize = table->keys - table->isolated; moveDown = ddSymmSiftingDown(table,x,xHigh); result = ddSymmSiftingBackward(table,moveDown,initialSize); } if (!result) goto ddSymmSiftingConvAuxOutOfMem; } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */ moveDown = ddSymmSiftingDown(table,x,xHigh); /* at this point x == xHigh, unless early term */ if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveDown != NULL) { x = moveDown->y; i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } } else { while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; i = x; x = table->subtables[x].next; } #ifdef DD_DEBUG /* x should be the top of the symmetry group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif initGroupSize = i - x + 1; moveUp = ddSymmSiftingUp(table,x,xLow); if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveUp != NULL) { x = moveUp->x; i = table->subtables[x].next; } else { i = x; while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; } #ifdef DD_DEBUG /* x should be the bottom of the symmetry group and i the top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif finalGroupSize = x - i + 1; if (initGroupSize == finalGroupSize) { /* No new symmetry groups detected, return to best position */ result = ddSymmSiftingBackward(table,moveUp,initialSize); } else { while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } initialSize = table->keys - table->isolated; moveDown = ddSymmSiftingDown(table,x,xHigh); result = ddSymmSiftingBackward(table,moveDown,initialSize); } if (!result) goto ddSymmSiftingConvAuxOutOfMem; } else { /* moving up first: shorter */ /* Find top of x's symmetry group */ x = table->subtables[x].next; moveUp = ddSymmSiftingUp(table,x,xLow); /* at this point x == xHigh, unless early term */ if (moveUp == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveUp != NULL) { x = moveUp->x; i = table->subtables[x].next; } else { i = x; while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; } #ifdef DD_DEBUG /* x is bottom of the symmetry group and i is top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif initGroupSize = x - i + 1; moveDown = ddSymmSiftingDown(table,x,xHigh); if (moveDown == MV_OOM) goto ddSymmSiftingConvAuxOutOfMem; if (moveDown != NULL) { x = moveDown->y; i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } } else { i = x; x = table->subtables[x].next; } #ifdef DD_DEBUG /* x should be the top of the symmetry group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif finalGroupSize = i - x + 1; if (initGroupSize == finalGroupSize) { /* No new symmetries detected, go back to best position */ result = ddSymmSiftingBackward(table,moveDown,initialSize); } else { while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } initialSize = table->keys - table->isolated; moveUp = ddSymmSiftingUp(table,x,xLow); result = ddSymmSiftingBackward(table,moveUp,initialSize); } if (!result) goto ddSymmSiftingConvAuxOutOfMem; } while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } return(1); ddSymmSiftingConvAuxOutOfMem: if (moveDown != MV_OOM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } } if (moveUp != MV_OOM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } } return(0); } /* end of ddSymmSiftingConvAux */
/**Function******************************************************************** Synopsis [Given xLow <= x <= xHigh moves x up and down between the boundaries.] Description [Given xLow <= x <= xHigh moves x up and down between the boundaries. Finds the best position and does the required changes. Assumes that x is not part of a symmetry group. Returns 1 if successful; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddSymmSiftingAux( DdManager * table, int x, int xLow, int xHigh) { Move *move; Move *moveUp; /* list of up moves */ Move *moveDown; /* list of down moves */ int initialSize; int result; int i; int topbot; /* index to either top or bottom of symmetry group */ int initGroupSize, finalGroupSize; #ifdef DD_DEBUG /* check for previously detected symmetry */ assert(table->subtables[x].next == (unsigned) x); #endif initialSize = table->keys - table->isolated; moveDown = NULL; moveUp = NULL; if ((x - xLow) > (xHigh - x)) { /* Will go down first, unless x == xHigh: ** Look for consecutive symmetries above x. */ for (i = x; i > xLow; i--) { if (!cuddSymmCheck(table,i-1,i)) break; topbot = table->subtables[i-1].next; /* find top of i-1's group */ table->subtables[i-1].next = i; table->subtables[x].next = topbot; /* x is bottom of group so its */ /* next is top of i-1's group */ i = topbot + 1; /* add 1 for i--; new i is top of symm group */ } } else { /* Will go up first unless x == xlow: ** Look for consecutive symmetries below x. */ for (i = x; i < xHigh; i++) { if (!cuddSymmCheck(table,i,i+1)) break; /* find bottom of i+1's symm group */ topbot = i + 1; while ((unsigned) topbot < table->subtables[topbot].next) { topbot = table->subtables[topbot].next; } table->subtables[topbot].next = table->subtables[i].next; table->subtables[i].next = i + 1; i = topbot - 1; /* subtract 1 for i++; new i is bottom of group */ } } /* Now x may be in the middle of a symmetry group. ** Find bottom of x's symm group. */ while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; if (x == xLow) { /* Sift down */ #ifdef DD_DEBUG /* x must be a singleton */ assert((unsigned) x == table->subtables[x].next); #endif if (x == xHigh) return(1); /* just one variable */ initGroupSize = 1; moveDown = ddSymmSiftingDown(table,x,xHigh); /* after this point x --> xHigh, unless early term */ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveDown == NULL) return(1); x = moveDown->y; /* Find bottom of x's group */ i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } #ifdef DD_DEBUG /* x should be the top of the symmetry group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif finalGroupSize = i - x + 1; if (initGroupSize == finalGroupSize) { /* No new symmetry groups detected, return to best position */ result = ddSymmSiftingBackward(table,moveDown,initialSize); } else { initialSize = table->keys - table->isolated; moveUp = ddSymmSiftingUp(table,x,xLow); result = ddSymmSiftingBackward(table,moveUp,initialSize); } if (!result) goto ddSymmSiftingAuxOutOfMem; } else if (cuddNextHigh(table,x) > xHigh) { /* Sift up */ /* Find top of x's symm group */ i = x; /* bottom */ x = table->subtables[x].next; /* top */ if (x == xLow) return(1); /* just one big group */ initGroupSize = i - x + 1; moveUp = ddSymmSiftingUp(table,x,xLow); /* after this point x --> xLow, unless early term */ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveUp == NULL) return(1); x = moveUp->x; /* Find top of x's group */ i = table->subtables[x].next; #ifdef DD_DEBUG /* x should be the bottom of the symmetry group and i the top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif finalGroupSize = x - i + 1; if (initGroupSize == finalGroupSize) { /* No new symmetry groups detected, return to best position */ result = ddSymmSiftingBackward(table,moveUp,initialSize); } else { initialSize = table->keys - table->isolated; moveDown = ddSymmSiftingDown(table,x,xHigh); result = ddSymmSiftingBackward(table,moveDown,initialSize); } if (!result) goto ddSymmSiftingAuxOutOfMem; } else if ((x - xLow) > (xHigh - x)) { /* must go down first: shorter */ moveDown = ddSymmSiftingDown(table,x,xHigh); /* at this point x == xHigh, unless early term */ if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveDown != NULL) { x = moveDown->y; /* x is top here */ i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } } else { i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } x = table->subtables[i].next; } #ifdef DD_DEBUG /* x should be the top of the symmetry group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif initGroupSize = i - x + 1; moveUp = ddSymmSiftingUp(table,x,xLow); if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveUp != NULL) { x = moveUp->x; i = table->subtables[x].next; } else { i = x; while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; } #ifdef DD_DEBUG /* x should be the bottom of the symmetry group and i the top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif finalGroupSize = x - i + 1; if (initGroupSize == finalGroupSize) { /* No new symmetry groups detected, return to best position */ result = ddSymmSiftingBackward(table,moveUp,initialSize); } else { while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } initialSize = table->keys - table->isolated; moveDown = ddSymmSiftingDown(table,x,xHigh); result = ddSymmSiftingBackward(table,moveDown,initialSize); } if (!result) goto ddSymmSiftingAuxOutOfMem; } else { /* moving up first: shorter */ /* Find top of x's symmetry group */ x = table->subtables[x].next; moveUp = ddSymmSiftingUp(table,x,xLow); /* at this point x == xHigh, unless early term */ if (moveUp == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveUp != NULL) { x = moveUp->x; i = table->subtables[x].next; } else { while ((unsigned) x < table->subtables[x].next) x = table->subtables[x].next; i = table->subtables[x].next; } #ifdef DD_DEBUG /* x is bottom of the symmetry group and i is top */ assert((unsigned) x >= table->subtables[x].next); assert((unsigned) i == table->subtables[x].next); #endif initGroupSize = x - i + 1; moveDown = ddSymmSiftingDown(table,x,xHigh); if (moveDown == MV_OOM) goto ddSymmSiftingAuxOutOfMem; if (moveDown != NULL) { x = moveDown->y; i = x; while ((unsigned) i < table->subtables[i].next) { i = table->subtables[i].next; } } else { i = x; x = table->subtables[x].next; } #ifdef DD_DEBUG /* x should be the top of the symmetry group and i the bottom */ assert((unsigned) i >= table->subtables[i].next); assert((unsigned) x == table->subtables[i].next); #endif finalGroupSize = i - x + 1; if (initGroupSize == finalGroupSize) { /* No new symmetries detected, go back to best position */ result = ddSymmSiftingBackward(table,moveDown,initialSize); } else { while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } initialSize = table->keys - table->isolated; moveUp = ddSymmSiftingUp(table,x,xLow); result = ddSymmSiftingBackward(table,moveUp,initialSize); } if (!result) goto ddSymmSiftingAuxOutOfMem; } while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } return(1); ddSymmSiftingAuxOutOfMem: if (moveDown != MV_OOM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } } if (moveUp != MV_OOM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } } return(0); } /* end of ddSymmSiftingAux */
/**Function******************************************************************** Synopsis [Sifts one variable up and down until it has taken all positions. Checks for aggregation.] Description [Sifts one variable up and down until it has taken all positions. Checks for aggregation. There may be at most two sweeps, even if the group grows. Assumes that x is either an isolated variable, or it is the bottom of a group. All groups may not have been found. The variable being moved is returned to the best position seen during sifting. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupSiftingAux( DdManager * table, int x, int xLow, int xHigh) { Move *move; Move *moves; /* list of moves */ int initialSize; int result; #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingAux from %d to %d\n",xLow,xHigh); assert((unsigned) x >= table->subtableZ[x].next); /* x is bottom of group */ #endif initialSize = table->keysZ; moves = NULL; if (x == xLow) { /* Sift down */ #ifdef DD_DEBUG /* x must be a singleton */ assert((unsigned) x == table->subtableZ[x].next); #endif if (x == xHigh) return(1); /* just one variable */ if (!zddGroupSiftingDown(table,x,xHigh,&moves)) goto zddGroupSiftingAuxOutOfMem; /* at this point x == xHigh, unless early term */ /* move backward and stop at best position */ result = zddGroupSiftingBackward(table,moves,initialSize); #ifdef DD_DEBUG assert(table->keysZ <= (unsigned) initialSize); #endif if (!result) goto zddGroupSiftingAuxOutOfMem; } else if (cuddZddNextHigh(table,x) > xHigh) { /* Sift up */ #ifdef DD_DEBUG /* x is bottom of group */ assert((unsigned) x >= table->subtableZ[x].next); #endif /* Find top of x's group */ x = table->subtableZ[x].next; if (!zddGroupSiftingUp(table,x,xLow,&moves)) goto zddGroupSiftingAuxOutOfMem; /* at this point x == xLow, unless early term */ /* move backward and stop at best position */ result = zddGroupSiftingBackward(table,moves,initialSize); #ifdef DD_DEBUG assert(table->keysZ <= (unsigned) initialSize); #endif if (!result) goto zddGroupSiftingAuxOutOfMem; } else if (x - xLow > xHigh - x) { /* must go down first: shorter */ if (!zddGroupSiftingDown(table,x,xHigh,&moves)) goto zddGroupSiftingAuxOutOfMem; /* at this point x == xHigh, unless early term */ /* Find top of group */ if (moves) { x = moves->y; } while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; #ifdef DD_DEBUG /* x should be the top of a group */ assert((unsigned) x <= table->subtableZ[x].next); #endif if (!zddGroupSiftingUp(table,x,xLow,&moves)) goto zddGroupSiftingAuxOutOfMem; /* move backward and stop at best position */ result = zddGroupSiftingBackward(table,moves,initialSize); #ifdef DD_DEBUG assert(table->keysZ <= (unsigned) initialSize); #endif if (!result) goto zddGroupSiftingAuxOutOfMem; } else { /* moving up first: shorter */ /* Find top of x's group */ x = table->subtableZ[x].next; if (!zddGroupSiftingUp(table,x,xLow,&moves)) goto zddGroupSiftingAuxOutOfMem; /* at this point x == xHigh, unless early term */ if (moves) { x = moves->x; } while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; #ifdef DD_DEBUG /* x is bottom of a group */ assert((unsigned) x >= table->subtableZ[x].next); #endif if (!zddGroupSiftingDown(table,x,xHigh,&moves)) goto zddGroupSiftingAuxOutOfMem; /* move backward and stop at best position */ result = zddGroupSiftingBackward(table,moves,initialSize); #ifdef DD_DEBUG assert(table->keysZ <= (unsigned) initialSize); #endif if (!result) goto zddGroupSiftingAuxOutOfMem; } while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(1); zddGroupSiftingAuxOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(0); } /* end of zddGroupSiftingAux */
/**Function******************************************************************** Synopsis [Given x_low <= x <= x_high moves x up and down between the boundaries.] Description [Given x_low <= x <= x_high moves x up and down between the boundaries. Finds the best position and does the required changes. Assumes that x is not part of a symmetry group. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddSymmSiftingAux( DdManager * table, int x, int x_low, int x_high) { Move *move; Move *move_up; /* list of up move */ Move *move_down; /* list of down move */ int initial_size; int result; int i; int topbot; /* index to either top or bottom of symmetry group */ int init_group_size, final_group_size; initial_size = table->keysZ; move_down = NULL; move_up = NULL; /* Look for consecutive symmetries above x. */ for (i = x; i > x_low; i--) { if (!cuddZddSymmCheck(table, i - 1, i)) break; /* find top of i-1's symmetry */ topbot = table->subtableZ[i - 1].next; table->subtableZ[i - 1].next = i; table->subtableZ[x].next = topbot; /* x is bottom of group so its symmetry is top of i-1's group */ i = topbot + 1; /* add 1 for i--, new i is top of symm group */ } /* Look for consecutive symmetries below x. */ for (i = x; i < x_high; i++) { if (!cuddZddSymmCheck(table, i, i + 1)) break; /* find bottom of i+1's symm group */ topbot = i + 1; while ((unsigned) topbot < table->subtableZ[topbot].next) topbot = table->subtableZ[topbot].next; table->subtableZ[topbot].next = table->subtableZ[i].next; table->subtableZ[i].next = i + 1; i = topbot - 1; /* add 1 for i++, new i is bottom of symm group */ } /* Now x maybe in the middle of a symmetry group. */ if (x == x_low) { /* Sift down */ /* Find bottom of x's symm group */ while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; i = table->subtableZ[x].next; init_group_size = x - i + 1; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); /* after that point x --> x_high, unless early term */ if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_down == NULL || table->subtableZ[move_down->y].next != move_down->y) { /* symmetry detected may have to make another complete pass */ if (move_down != NULL) x = move_down->y; else x = table->subtableZ[x].next; i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } final_group_size = i - x + 1; if (init_group_size == final_group_size) { /* No new symmetry groups detected, return to best position */ result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } else { initial_size = table->keysZ; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_down, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingAuxOutOfMem; } else if (x == x_high) { /* Sift up */ /* Find top of x's symm group */ while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } init_group_size = i - x + 1; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); /* after that point x --> x_low, unless early term */ if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_up == NULL || table->subtableZ[move_up->x].next != move_up->x) { /* symmetry detected may have to make another complete pass */ if (move_up != NULL) x = move_up->x; else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; final_group_size = x - i + 1; if (init_group_size == final_group_size) { /* No new symmetry groups detected, return to best position */ result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } else { initial_size = table->keysZ; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_up, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingAuxOutOfMem; } else if ((x - x_low) > (x_high - x)) { /* must go down first: shorter */ /* Find bottom of x's symm group */ while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); /* after that point x --> x_high, unless early term */ if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_down != NULL) { x = move_down->y; } else { x = table->subtableZ[x].next; } i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } init_group_size = i - x + 1; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_up == NULL || table->subtableZ[move_up->x].next != move_up->x) { /* symmetry detected may have to make another complete pass */ if (move_up != NULL) { x = move_up->x; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; final_group_size = x - i + 1; if (init_group_size == final_group_size) { /* No new symmetry groups detected, return to best position */ result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } else { while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } initial_size = table->keysZ; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_up, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingAuxOutOfMem; } else { /* moving up first:shorter */ /* Find top of x's symmetry group */ while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); /* after that point x --> x_high, unless early term */ if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_up != NULL) { x = move_up->x; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; init_group_size = x - i + 1; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingAuxOutOfMem; if (move_down == NULL || table->subtableZ[move_down->y].next != move_down->y) { /* symmetry detected may have to make another complete pass */ if (move_down != NULL) { x = move_down->y; } else { x = table->subtableZ[x].next; } i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } final_group_size = i - x + 1; if (init_group_size == final_group_size) { /* No new symmetries detected, go back to best position */ result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } else { while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } initial_size = table->keysZ; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_down, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingAuxOutOfMem; } while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } return(1); cuddZddSymmSiftingAuxOutOfMem: if (move_down != ZDD_MV_OOM) { while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } } if (move_up != ZDD_MV_OOM) { while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } } return(0); } /* end of cuddZddSymmSiftingAux */
/**Function******************************************************************** Synopsis [Reorders variables by a sequence of (non-adjacent) swaps.] Description [Implementation of Plessier's algorithm that reorders variables by a sequence of (non-adjacent) swaps. <ol> <li> Select two variables (RANDOM or HEURISTIC). <li> Permute these variables. <li> If the nodes have decreased accept the permutation. <li> Otherwise reconstruct the original heap. <li> Loop. </ol> Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddSwapping( DdManager * table, int lower, int upper, Cudd_ReorderingType heuristic) { int i, j; int max, keys; int nvars; int x, y; int iterate; int previousSize; Move *moves, *move; int pivot; int modulo; int result; #ifdef DD_DEBUG /* Sanity check */ assert(lower >= 0 && upper < table->sizeZ && lower <= upper); #endif nvars = upper - lower + 1; iterate = nvars; for (i = 0; i < iterate; i++) { if (heuristic == CUDD_REORDER_RANDOM_PIVOT) { /* Find pivot <= id with maximum keys. */ for (max = -1, j = lower; j <= upper; j++) { if ((keys = table->subtableZ[j].keys) > max) { max = keys; pivot = j; } } modulo = upper - pivot; if (modulo == 0) { y = pivot; /* y = nvars-1 */ } else { /* y = random # from {pivot+1 .. nvars-1} */ y = pivot + 1 + (int) (Cudd_Random() % modulo); } modulo = pivot - lower - 1; if (modulo < 1) { /* if pivot = 1 or 0 */ x = lower; } else { do { /* x = random # from {0 .. pivot-2} */ x = (int) Cudd_Random() % modulo; } while (x == y); /* Is this condition really needed, since x and y are in regions separated by pivot? */ } } else { x = (int) (Cudd_Random() % nvars) + lower; do { y = (int) (Cudd_Random() % nvars) + lower; } while (x == y); } previousSize = table->keysZ; moves = zddSwapAny(table, x, y); if (moves == NULL) goto cuddZddSwappingOutOfMem; result = cuddZddSiftingBackward(table, moves, previousSize); if (!result) goto cuddZddSwappingOutOfMem; while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } return(1); cuddZddSwappingOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(0); } /* end of cuddZddSwapping */
/**Function******************************************************************** Synopsis [Swaps any two variables.] Description [Swaps any two variables. Returns the set of moves.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * zddSwapAny( DdManager * table, int x, int y) { Move *move, *moves; int tmp, size; int x_ref, y_ref; int x_next, y_next; int limit_size; if (x > y) { /* make x precede y */ tmp = x; x = y; y = tmp; } x_ref = x; y_ref = y; x_next = cuddZddNextHigh(table, x); y_next = cuddZddNextLow(table, y); moves = NULL; limit_size = table->keysZ; for (;;) { if (x_next == y_next) { /* x < x_next = y_next < y */ size = cuddZddSwapInPlace(table, x, x_next); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; size = cuddZddSwapInPlace(table, y_next, y); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; size = cuddZddSwapInPlace(table, x, x_next); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; 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) { /* x = y_next < y = x_next */ size = cuddZddSwapInPlace(table, x, x_next); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; tmp = x; x = y; y = tmp; } else { size = cuddZddSwapInPlace(table, x, x_next); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = x; move->y = x_next; move->size = size; move->next = moves; moves = move; size = cuddZddSwapInPlace(table, y_next, y); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; x = x_next; y = y_next; } x_next = cuddZddNextHigh(table, x); y_next = cuddZddNextLow(table, y); if (x_next > y_ref) break; /* if x == y_ref */ if ((double) size > table->maxGrowth * (double) limit_size) break; if (size < limit_size) limit_size = size; } if (y_next >= x_ref) { size = cuddZddSwapInPlace(table, y_next, y); if (size == 0) goto zddSwapAnyOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddSwapAnyOutOfMem; move->x = y_next; move->y = y; move->size = size; move->next = moves; moves = move; } return(moves); zddSwapAnyOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(NULL); } /* end of zddSwapAny */
/**Function******************************************************************** Synopsis [Given xLow <= x <= xHigh moves x up and down between the boundaries.] Description [Given xLow <= x <= xHigh moves x up and down between the boundaries. Finds the best position and does the required changes. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddSiftingAux( DdManager * table, int x, int x_low, int x_high) { Move *move; Move *moveUp; /* list of up move */ Move *moveDown; /* list of down move */ int initial_size; int result; initial_size = table->keysZ; #ifdef DD_DEBUG assert(table->subtableZ[x].keys > 0); #endif moveDown = NULL; moveUp = NULL; if (x == x_low) { moveDown = cuddZddSiftingDown(table, x, x_high, initial_size); /* after that point x --> x_high */ if (moveDown == NULL) goto cuddZddSiftingAuxOutOfMem; result = cuddZddSiftingBackward(table, moveDown, initial_size); /* move backward and stop at best position */ if (!result) goto cuddZddSiftingAuxOutOfMem; } else if (x == x_high) { moveUp = cuddZddSiftingUp(table, x, x_low, initial_size); /* after that point x --> x_low */ if (moveUp == NULL) goto cuddZddSiftingAuxOutOfMem; result = cuddZddSiftingBackward(table, moveUp, initial_size); /* move backward and stop at best position */ if (!result) goto cuddZddSiftingAuxOutOfMem; } else if ((x - x_low) > (x_high - x)) { /* must go down first:shorter */ moveDown = cuddZddSiftingDown(table, x, x_high, initial_size); /* after that point x --> x_high */ if (moveDown == NULL) goto cuddZddSiftingAuxOutOfMem; moveUp = cuddZddSiftingUp(table, moveDown->y, x_low, initial_size); if (moveUp == NULL) goto cuddZddSiftingAuxOutOfMem; result = cuddZddSiftingBackward(table, moveUp, initial_size); /* move backward and stop at best position */ if (!result) goto cuddZddSiftingAuxOutOfMem; } else { moveUp = cuddZddSiftingUp(table, x, x_low, initial_size); /* after that point x --> x_high */ if (moveUp == NULL) goto cuddZddSiftingAuxOutOfMem; moveDown = cuddZddSiftingDown(table, moveUp->x, x_high, initial_size); /* then move up */ if (moveDown == NULL) goto cuddZddSiftingAuxOutOfMem; result = cuddZddSiftingBackward(table, moveDown, initial_size); /* move backward and stop at best position */ if (!result) goto cuddZddSiftingAuxOutOfMem; } while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } return(1); cuddZddSiftingAuxOutOfMem: while (moveDown != NULL) { move = moveDown->next; cuddDeallocMove(table, moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocMove(table, moveUp); moveUp = move; } return(0); } /* end of cuddZddSiftingAux */
/**Function******************************************************************** Synopsis [Sifts down a variable until it reaches position xHigh.] Description [Sifts down a variable until it reaches position xHigh. Assumes that x is the bottom of a group (or a singleton). Records all the moves. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupSiftingDown( DdManager * table, int x, int xHigh, Move ** moves) { Move *move; int y; int size; int limitSize; int gybot; /* Initialize R */ limitSize = size = table->keysZ; y = cuddZddNextHigh(table,x); while (y <= xHigh) { /* Find bottom of y group. */ gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; if (table->subtableZ[x].next == (unsigned) x && table->subtableZ[y].next == (unsigned) y) { /* x and y are self groups */ size = cuddZddSwapInPlace(table,x,y); #ifdef DD_DEBUG assert(table->subtableZ[x].next == (unsigned) x); assert(table->subtableZ[y].next == (unsigned) y); #endif if (size == 0) goto zddGroupSiftingDownOutOfMem; /* Record move. */ move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto zddGroupSiftingDownOutOfMem; move->x = x; move->y = y; move->flags = MTR_DEFAULT; move->size = size; move->next = *moves; *moves = move; #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingDown (2 single groups):\n"); #endif if ((double) size > (double) limitSize * table->maxGrowth) return(1); if (size < limitSize) limitSize = size; x = y; y = cuddZddNextHigh(table,x); } else { /* Group move */ size = zddGroupMove(table,x,y,moves); if (size == 0) goto zddGroupSiftingDownOutOfMem; if ((double) size > (double) limitSize * table->maxGrowth) return(1); if (size < limitSize) limitSize = size; } x = gybot; y = cuddZddNextHigh(table,x); } return(1); zddGroupSiftingDownOutOfMem: while (*moves != NULL) { move = (*moves)->next; cuddDeallocMove(table, *moves); *moves = move; } return(0); } /* end of zddGroupSiftingDown */
/**Function******************************************************************** Synopsis [Sifts up a variable until either it reaches position xLow or the size of the DD heap increases too much.] Description [Sifts up a variable until either it reaches position xLow or the size of the DD heap increases too much. Assumes that y is the top of a group (or a singleton). Checks y for aggregation to the adjacent variables. Records all the moves that are appended to the list of moves received as input and returned as a side effect. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupSiftingUp( DdManager * table, int y, int xLow, Move ** moves) { Move *move; int x; int size; int gxtop; int limitSize; limitSize = table->keysZ; x = cuddZddNextLow(table,y); while (x >= xLow) { gxtop = table->subtableZ[x].next; if (table->subtableZ[x].next == (unsigned) x && table->subtableZ[y].next == (unsigned) y) { /* x and y are self groups */ size = cuddZddSwapInPlace(table,x,y); #ifdef DD_DEBUG assert(table->subtableZ[x].next == (unsigned) x); assert(table->subtableZ[y].next == (unsigned) y); #endif if (size == 0) goto zddGroupSiftingUpOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zddGroupSiftingUpOutOfMem; move->x = x; move->y = y; move->flags = MTR_DEFAULT; move->size = size; move->next = *moves; *moves = move; #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingUp (2 single groups):\n"); #endif if ((double) size > (double) limitSize * table->maxGrowth) return(1); if (size < limitSize) limitSize = size; } else { /* group move */ size = zddGroupMove(table,x,y,moves); if (size == 0) goto zddGroupSiftingUpOutOfMem; if ((double) size > (double) limitSize * table->maxGrowth) return(1); if (size < limitSize) limitSize = size; } y = gxtop; x = cuddZddNextLow(table,y); } return(1); zddGroupSiftingUpOutOfMem: while (*moves != NULL) { move = (*moves)->next; cuddDeallocMove(table, *moves); *moves = move; } return(0); } /* end of zddGroupSiftingUp */
/**Function******************************************************************** Synopsis [Moves x down until either it reaches the bound (x_high) or the size of the ZDD heap increases too much.] Description [Moves x down until either it reaches the bound (x_high) or the size of the ZDD heap increases too much. Assumes that x is the bottom 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; ZDD_MV_OOM if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * cuddZddSymmSifting_down( DdManager * table, int x, int x_high, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; int i, gxtop, gybot; moves = NULL; y = cuddZddNextHigh(table, x); while (y <= x_high) { gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; if (cuddZddSymmCheck(table, x, y)) { /* Symmetry found, attach symm groups */ gxtop = table->subtableZ[x].next; table->subtableZ[x].next = y; i = table->subtableZ[y].next; while (table->subtableZ[i].next != (unsigned) y) i = table->subtableZ[i].next; table->subtableZ[i].next = gxtop; } else if ((table->subtableZ[x].next == (unsigned) x) && (table->subtableZ[y].next == (unsigned) y)) { /* x and y have self symmetry */ size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto cuddZddSymmSifting_downOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto cuddZddSymmSifting_downOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double)size > (double)limit_size * table->maxGrowth) return(moves); if (size < limit_size) limit_size = size; x = y; y = cuddZddNextHigh(table, x); } else { /* Group move */ size = zdd_group_move(table, x, y, &moves); if ((double)size > (double)limit_size * table->maxGrowth) return(moves); if (size < limit_size) limit_size = size; } x = gybot; y = cuddZddNextHigh(table, x); } return(moves); cuddZddSymmSifting_downOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(ZDD_MV_OOM); } /* end of cuddZddSymmSifting_down */
/**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 */
/**Function******************************************************************** Synopsis [Swaps two groups.] Description [Swaps two groups. x is assumed to be the bottom variable of the first group. y is assumed to be the top variable of the second group. Updates the list of moves. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zdd_group_move( DdManager * table, int x, int y, Move ** moves) { Move *move; int size; int i, temp, gxtop, gxbot, gybot, yprev; int swapx, swapy; /* NuSMV: add begin */ swapy = 0; swapx = 0; /* NuSMV: add end */ #ifdef DD_DEBUG assert(x < y); /* we assume that x < y */ #endif /* Find top and bottom for the two groups. */ gxtop = table->subtableZ[x].next; gxbot = x; gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; yprev = gybot; while (x <= y) { while (y > gxtop) { /* Set correct symmetries. */ temp = table->subtableZ[x].next; if (temp == x) temp = y; i = gxtop; for (;;) { if (table->subtableZ[i].next == (unsigned) x) { table->subtableZ[i].next = y; break; } else { i = table->subtableZ[i].next; } } if (table->subtableZ[y].next != (unsigned) y) { table->subtableZ[x].next = table->subtableZ[y].next; } else { table->subtableZ[x].next = x; } if (yprev != y) { table->subtableZ[yprev].next = x; } else { yprev = x; } table->subtableZ[y].next = temp; size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto zdd_group_moveOutOfMem; swapx = x; swapy = y; y = x; x--; } /* while y > gxtop */ /* Trying to find the next y. */ if (table->subtableZ[y].next <= (unsigned) y) { gybot = y; } else { y = table->subtableZ[y].next; } yprev = gxtop; gxtop++; gxbot++; x = gxbot; } /* while x <= y, end of group movement */ move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zdd_group_moveOutOfMem; move->x = swapx; move->y = swapy; move->size = table->keysZ; move->next = *moves; *moves = move; return(table->keysZ); zdd_group_moveOutOfMem: while (*moves != NULL) { move = (*moves)->next; cuddDeallocMove(table, *moves); *moves = move; } return(0); } /* end of zdd_group_move */
/**Function******************************************************************** Synopsis [Moves x down until either it reaches the bound (xHigh) or the size of the DD heap increases too much.] Description [Moves x down until either it reaches the bound (xHigh) or the size of the DD heap increases too much. Assumes that x is the bottom 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 * ddSymmSiftingDown( DdManager * table, int x, int xHigh) { Move *moves; Move *move; int y; int size; int limitSize; int gxtop,gybot; int R; /* upper bound on node decrease */ int xindex, yindex; int isolated; int z; int zindex; #ifdef DD_DEBUG int checkR; #endif moves = NULL; /* Initialize R */ xindex = table->invperm[x]; gxtop = table->subtables[x].next; limitSize = size = table->keys - table->isolated; R = 0; for (z = xHigh; z > gxtop; z--) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R += table->subtables[z].keys - isolated; } } y = cuddNextHigh(table,x); while (y <= xHigh && size - R < limitSize) { #ifdef DD_DEBUG gxtop = table->subtables[x].next; checkR = 0; for (z = xHigh; z > gxtop; z--) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; checkR += table->subtables[z].keys - isolated; } } assert(R == checkR); #endif gybot = table->subtables[y].next; while (table->subtables[gybot].next != (unsigned) y) gybot = table->subtables[gybot].next; if (cuddSymmCheck(table,x,y)) { /* Symmetry found, attach symm groups */ gxtop = table->subtables[x].next; table->subtables[x].next = y; table->subtables[gybot].next = gxtop; } else if (table->subtables[x].next == (unsigned) x && table->subtables[y].next == (unsigned) y) { /* x and y have self symmetry */ /* Update upper bound on node decrease. */ yindex = table->invperm[y]; if (cuddTestInteract(table,xindex,yindex)) { isolated = table->vars[yindex]->ref == 1; R -= table->subtables[y].keys - isolated; } 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 ddSymmSiftingDownOutOfMem; move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto ddSymmSiftingDownOutOfMem; 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 */ /* Update upper bound on node decrease: first phase. */ gxtop = table->subtables[x].next; z = gxtop + 1; do { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R -= table->subtables[z].keys - isolated; } z++; } while (z <= gybot); size = ddSymmGroupMove(table,x,y,&moves); if (size == 0) goto ddSymmSiftingDownOutOfMem; if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; /* Update upper bound on node decrease: second phase. */ gxtop = table->subtables[gybot].next; for (z = gxtop + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R += table->subtables[z].keys - isolated; } } } x = gybot; y = cuddNextHigh(table,x); } return(moves); ddSymmSiftingDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingDown */
/**Function******************************************************************** Synopsis [Given x_low <= x <= x_high moves x up and down between the boundaries.] Description [Given x_low <= x <= x_high moves x up and down between the boundaries. Finds the best position and does the required changes. Assumes that x is either an isolated variable, or it is the bottom of a symmetry group. All symmetries may not have been found, because of exceeded growth limit. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddSymmSiftingConvAux( DdManager * table, int x, int x_low, int x_high) { Move *move; Move *move_up; /* list of up move */ Move *move_down; /* list of down move */ int initial_size; int result; int i; int init_group_size, final_group_size; initial_size = table->keysZ; move_down = NULL; move_up = NULL; if (x == x_low) { /* Sift down */ i = table->subtableZ[x].next; init_group_size = x - i + 1; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); /* after that point x --> x_high, unless early term */ if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_down == NULL || table->subtableZ[move_down->y].next != move_down->y) { /* symmetry detected may have to make another complete pass */ if (move_down != NULL) x = move_down->y; else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; } i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } final_group_size = i - x + 1; if (init_group_size == final_group_size) { /* No new symmetries detected, go back to best position */ result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } else { initial_size = table->keysZ; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_down, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingConvAuxOutOfMem; } else if (x == x_high) { /* Sift up */ /* Find top of x's symm group */ while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } init_group_size = i - x + 1; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); /* after that point x --> x_low, unless early term */ if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_up == NULL || table->subtableZ[move_up->x].next != move_up->x) { /* symmetry detected may have to make another complete pass */ if (move_up != NULL) x = move_up->x; else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; final_group_size = x - i + 1; if (init_group_size == final_group_size) { /* No new symmetry groups detected, return to best position */ result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } else { initial_size = table->keysZ; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_up, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingConvAuxOutOfMem; } else if ((x - x_low) > (x_high - x)) { /* must go down first: shorter */ move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); /* after that point x --> x_high */ if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_down != NULL) { x = move_down->y; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; } i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } init_group_size = i - x + 1; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_up == NULL || table->subtableZ[move_up->x].next != move_up->x) { /* symmetry detected may have to make another complete pass */ if (move_up != NULL) { x = move_up->x; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; final_group_size = x - i + 1; if (init_group_size == final_group_size) { /* No new symmetry groups detected, return to best position */ result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } else { while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } initial_size = table->keysZ; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_up, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingConvAuxOutOfMem; } else { /* moving up first:shorter */ /* Find top of x's symmetry group */ x = table->subtableZ[x].next; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); /* after that point x --> x_high, unless early term */ if (move_up == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_up != NULL) { x = move_up->x; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; } i = table->subtableZ[x].next; init_group_size = x - i + 1; move_down = cuddZddSymmSifting_down(table, x, x_high, initial_size); if (move_down == ZDD_MV_OOM) goto cuddZddSymmSiftingConvAuxOutOfMem; if (move_down == NULL || table->subtableZ[move_down->y].next != move_down->y) { /* symmetry detected may have to make another complete pass */ if (move_down != NULL) { x = move_down->y; } else { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; x = table->subtableZ[x].next; } i = x; while ((unsigned) i < table->subtableZ[i].next) { i = table->subtableZ[i].next; } final_group_size = i - x + 1; if (init_group_size == final_group_size) { /* No new symmetries detected, go back to best position */ result = cuddZddSymmSiftingBackward(table, move_down, initial_size); } else { while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } initial_size = table->keysZ; move_up = cuddZddSymmSifting_up(table, x, x_low, initial_size); result = cuddZddSymmSiftingBackward(table, move_up, initial_size); } } else { result = cuddZddSymmSiftingBackward(table, move_down, initial_size); /* move backward and stop at best position */ } if (!result) goto cuddZddSymmSiftingConvAuxOutOfMem; } while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } return(1); cuddZddSymmSiftingConvAuxOutOfMem: if (move_down != ZDD_MV_OOM) { while (move_down != NULL) { move = move_down->next; cuddDeallocMove(table, move_down); move_down = move; } } if (move_up != ZDD_MV_OOM) { while (move_up != NULL) { move = move_up->next; cuddDeallocMove(table, move_up); move_up = move; } } return(0); } /* end of cuddZddSymmSiftingConvAux */
/**Function******************************************************************** Synopsis [Swaps two groups and records the move.] Description [Swaps two groups and records the move. Returns the number of keys in the DD table in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupMove( DdManager * table, int x, int y, Move ** moves) { Move *move; int size; int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop; int swapx,swapy; #if defined(DD_DEBUG) && defined(DD_VERBOSE) int initialSize,bestSize; #endif #ifdef DD_DEBUG /* We assume that x < y */ assert(x < y); #endif /* Find top, bottom, and size for the two groups. */ xbot = x; xtop = table->subtableZ[x].next; xsize = xbot - xtop + 1; ybot = y; while ((unsigned) ybot < table->subtableZ[ybot].next) ybot = table->subtableZ[ybot].next; ytop = y; ysize = ybot - ytop + 1; #if defined(DD_DEBUG) && defined(DD_VERBOSE) initialSize = bestSize = table->keysZ; #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 = cuddZddSwapInPlace(table,x,y); if (size == 0) goto zddGroupMoveOutOfMem; #if defined(DD_DEBUG) && defined(DD_VERBOSE) if (size < bestSize) bestSize = size; #endif swapx = x; swapy = y; y = x; x = cuddZddNextLow(table,y); } y = ytop + i; x = cuddZddNextLow(table,y); } #if defined(DD_DEBUG) && defined(DD_VERBOSE) if ((bestSize < initialSize) && (bestSize < size)) (void) fprintf(table->out,"Missed local minimum: initialSize:%d bestSize:%d finalSize:%d\n",initialSize,bestSize,size); #endif /* fix groups */ y = xtop; /* ytop is now where xtop used to be */ for (i = 0; i < ysize - 1; i++) { table->subtableZ[y].next = cuddZddNextHigh(table,y); y = cuddZddNextHigh(table,y); } table->subtableZ[y].next = xtop; /* y is bottom of its group, join */ /* it to top of its group */ x = cuddZddNextHigh(table,y); newxtop = x; for (i = 0; i < xsize - 1; i++) { table->subtableZ[x].next = cuddZddNextHigh(table,x); x = cuddZddNextHigh(table,x); } table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */ /* it to top of its group */ #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupMove:\n"); #endif /* Store group move */ move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto zddGroupMoveOutOfMem; move->x = swapx; move->y = swapy; move->flags = MTR_DEFAULT; move->size = table->keysZ; move->next = *moves; *moves = move; return(table->keysZ); zddGroupMoveOutOfMem: while (*moves != NULL) { move = (*moves)->next; cuddDeallocMove(table, *moves); *moves = move; } return(0); } /* end of zddGroupMove */