/**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 [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; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(NULL); } /* end of ddJumpingDown */
/**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 [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 [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 */