/**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 [Given a set of moves, returns the ZDD heap to the order in effect before the moves.] Description [Given a set of moves, returns the ZDD heap to the order in effect before the moves. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static Move* cuddZddUndoMoves( DdManager * table, Move * moves) { Move *invmoves = NULL; Move *move; Move *invmove; int size; for (move = moves; move != NULL; move = move->next) { invmove = (Move *) cuddDynamicAllocNode(table); if (invmove == NULL) goto cuddZddUndoMovesOutOfMem; invmove->x = move->x; invmove->y = move->y; invmove->next = invmoves; invmoves = invmove; if (move->flags == CUDD_SWAP_MOVE) { invmove->flags = CUDD_SWAP_MOVE; size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y); if (!size) goto cuddZddUndoMovesOutOfMem; } else if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) { invmove->flags = CUDD_INVERSE_TRANSFORM_MOVE; size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y); if (!size) goto cuddZddUndoMovesOutOfMem; size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y); if (!size) goto cuddZddUndoMovesOutOfMem; } else { /* must be CUDD_INVERSE_TRANSFORM_MOVE */ #ifdef DD_DEBUG (void) fprintf(table->err,"Unforseen event in ddUndoMoves!\n"); #endif invmove->flags = CUDD_LINEAR_TRANSFORM_MOVE; size = cuddZddSwapInPlace(table,(int)move->x,(int)move->y); if (!size) goto cuddZddUndoMovesOutOfMem; size = cuddZddLinearInPlace(table,(int)move->x,(int)move->y); if (!size) goto cuddZddUndoMovesOutOfMem; } invmove->size = size; } return(invmoves); cuddZddUndoMovesOutOfMem: while (invmoves != NULL) { move = invmoves->next; cuddDeallocNode(table, (DdNode *) invmoves); invmoves = move; } return((Move *) CUDD_OUT_OF_MEM); } /* end of cuddZddUndoMoves */
/**Function******************************************************************** Synopsis [Sifts a variable down.] Description [Sifts a variable down. Moves x down until either it reaches the bound (x_high) 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 * cuddZddSiftingDown( 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 = cuddZddNextHigh(table, x); while (y <= x_high) { size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto cuddZddSiftingDownOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto cuddZddSiftingDownOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double)size > (double)limit_size * table->maxGrowth) break; if (size < limit_size) limit_size = size; x = y; y = cuddZddNextHigh(table, x); } return(moves); cuddZddSiftingDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *)moves); moves = move; } return(NULL); } /* end of cuddZddSiftingDown */
/**Function******************************************************************** Synopsis [This function is for jumping up.] Description [This is a simplified version of ddSiftingUp. It does not use lower bounding. Returns the set of moves in case of success; NULL if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * ddJumpingUp( DdManager * table, int x, int x_low, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; moves = NULL; y = cuddNextLow(table,x); while (y >= x_low) { size = cuddSwapInPlace(table,y,x); if (size == 0) goto ddJumpingUpOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddJumpingUpOutOfMem; move->x = y; move->y = x; move->size = size; move->next = moves; moves = move; if ((double) size > table->maxGrowth * (double) limit_size) { break; } else if (size < limit_size) { limit_size = size; } x = y; y = cuddNextLow(table,x); } return(moves); ddJumpingUpOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(NULL); } /* end of ddJumpingUp */
/**Function******************************************************************** Synopsis [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; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(0); } /* end of cuddZddSwapping */
/**Function******************************************************************** Synopsis [Swaps two adjacent variables.] Description [Swaps two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddSwapInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddSwapInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *next; DdNodePtr g, *lastP, *previousP; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberSwapping++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer that don't depend on y directly ** will stay there; the others are put in a chain. ** The chain is handled as a FIFO; g points to the beginning and ** last points to the end. */ g = NULL; lastP = &g; for (i = 0; i < xslots; i++) { previousP = &(xlist[i]); f = *previousP; while (f != NULL) { next = f->next; f1 = cuddT(f); f0 = cuddE(f); if ((f1->index != (DdHalfWord) yindex) && (f0->index != (DdHalfWord) yindex)) { /* stays */ newxkeys++; *previousP = f; previousP = &(f->next); } else { f->index = yindex; *lastP = f; lastP = &(f->next); } f = next; } /* while there are elements in the collision chain */ *previousP = NULL; } /* for each slot of the x subtable */ *lastP = NULL; #ifdef DD_COUNT table->swapSteps += oldxkeys - newxkeys; #endif /* Take care of the x nodes that must be re-expressed. ** They form a linked list pointed by g. Their index has been ** changed to yindex already. */ f = g; while (f != NULL) { next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Decrease ref count of f1. */ cuddSatDec(f1->ref); /* Create the new T child. */ if (f11 == empty) { if (f01 != empty) { newf1 = f01; cuddSatInc(newf1->ref); } /* else case was already handled when finding nodes ** with both children below level y */ } else { /* Check xlist for triple (xindex, f11, f01). */ posn = ddHash(f11, f01, xshift); /* For each element newf1 in collision list xlist[posn]. */ newf1 = xlist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f11 && cuddE(newf1) == f01) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = xindex; newf1->ref = 1; cuddT(newf1) = f11; cuddE(newf1) = f01; /* Insert newf1 in the collision list xlist[pos]; ** increase the ref counts of f11 and f01 */ newxkeys++; newf1->next = xlist[posn]; xlist[posn] = newf1; cuddSatInc(f11->ref); cuddSatInc(f01->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Decrease ref count of f0. */ cuddSatDec(f0->ref); /* Create the new E child. */ if (f10 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check xlist for triple (xindex, f10, f00). */ posn = ddHash(f10, f00, xshift); /* For each element newf0 in collision list xlist[posn]. */ newf0 = xlist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f10 && cuddE(newf0) == f00) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = xindex; newf0->ref = 1; cuddT(newf0) = f10; cuddE(newf0) = f00; /* Insert newf0 in the collision list xlist[posn]; ** increase the ref counts of f10 and f00. */ newxkeys++; newf0->next = xlist[posn]; xlist[posn] = newf0; cuddSatInc(f10->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Insert the modified f in ylist. ** The modified f does not already exists in ylist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, yshift); newykeys++; f->next = ylist[posn]; ylist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previousP = &(ylist[i]); f = *previousP; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; } else { *previousP = f; previousP = &(f->next); } f = next; } /* while f */ *previousP = NULL; } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].nodelist = ylist; table->subtableZ[x].slots = yslots; table->subtableZ[x].shift = yshift; table->subtableZ[x].keys = newykeys; table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY; table->subtableZ[y].nodelist = xlist; table->subtableZ[y].slots = xslots; table->subtableZ[y].shift = xshift; table->subtableZ[y].keys = newxkeys; table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY; table->permZ[xindex] = y; table->permZ[yindex] = x; table->invpermZ[x] = yindex; table->invpermZ[y] = xindex; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddSwapInPlace */
/**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; cuddDeallocNode(table, (DdNode *)moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *)moveUp); moveUp = move; } return(1); cuddZddSiftingAuxOutOfMem: while (moveDown != NULL) { move = moveDown->next; cuddDeallocNode(table, (DdNode *)moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *)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 gxtop,gybot; int xindex; /* Initialize R */ xindex = table->invpermZ[x]; gxtop = table->subtableZ[x].next; 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; cuddDeallocNode(table, (DdNode *) *moves); *moves = move; } return(0); } /* end of zddGroupSiftingDown */
/**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; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingDown */
/**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 = x, swapy = y; #if defined(DD_DEBUG) && defined(DD_VERBOSE) int initialSize,bestSize; #endif #if 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; cuddDeallocNode(table, (DdNode *) *moves); *moves = move; } return(0); } /* end of zddGroupMove */
/**Function******************************************************************** Synopsis [Linearly combines two adjacent variables.] Description [Linearly combines two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddLinearInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddSwapInPlace cuddLinearInPlace] ******************************************************************************/ static int cuddZddLinearInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *g, *next, *previous; DdNode *special; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberLinearTr++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; /* Get parameters of y subtable. */ yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer are put in two chains. The chain ** pointed by g holds the normal nodes. When re-expressed they stay ** in the x list. The chain pointed by special holds the elements ** that will move to the y list. */ g = special = NULL; for (i = 0; i < xslots; i++) { f = xlist[i]; if (f == NULL) continue; xlist[i] = NULL; while (f != NULL) { next = f->next; f1 = cuddT(f); /* if (f1->index == yindex) */ cuddSatDec(f1->ref); f0 = cuddE(f); /* if (f0->index == yindex) */ cuddSatDec(f0->ref); if ((int) f1->index == yindex && cuddE(f1) == empty && (int) f0->index != yindex) { f->next = special; special = f; } else { f->next = g; g = f; } f = next; } /* while there are elements in the collision chain */ } /* for each slot of the x subtable */ /* Mark y nodes with pointers from above x. We mark them by ** changing their index to x. */ for (i = 0; i < yslots; i++) { f = ylist[i]; while (f != NULL) { if (f->ref != 0) { f->index = xindex; } f = f->next; } /* while there are elements in the collision chain */ } /* for each slot of the y subtable */ /* Move special nodes to the y list. */ f = special; while (f != NULL) { next = f->next; f1 = cuddT(f); f11 = cuddT(f1); cuddT(f) = f11; cuddSatInc(f11->ref); f0 = cuddE(f); cuddSatInc(f0->ref); f->index = yindex; /* Insert at the beginning of the list so that it will be ** found first if there is a duplicate. The duplicate will ** eventually be moved or garbage collected. No node ** re-expression will add a pointer to it. */ posn = ddHash(f11, f0, yshift); f->next = ylist[posn]; ylist[posn] = f; newykeys++; f = next; } /* Take care of the remaining x nodes that must be re-expressed. ** They form a linked list pointed by g. */ f = g; while (f != NULL) { #ifdef DD_COUNT table->swapSteps++; #endif next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex || (int) f1->index == xindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex || (int) f0->index == xindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Create the new T child. */ if (f01 == empty) { newf1 = f10; cuddSatInc(newf1->ref); } else { /* Check ylist for triple (yindex, f01, f10). */ posn = ddHash(f01, f10, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; /* Search the collision chain skipping the marked nodes. */ while (newf1 != NULL) { if (cuddT(newf1) == f01 && cuddE(newf1) == f10 && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f01; cuddE(newf1) = f10; /* Insert newf1 in the collision list ylist[pos]; ** increase the ref counts of f01 and f10 */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; cuddSatInc(f01->ref); cuddSatInc(f10->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Create the new E child. */ if (f11 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check ylist for triple (yindex, f11, f00). */ posn = ddHash(f11, f00, yshift); /* For each element newf0 in collision list ylist[posn]. */ newf0 = ylist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f11 && cuddE(newf0) == f00 && (int) newf0->index == yindex) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = yindex; newf0->ref = 1; cuddT(newf0) = f11; cuddE(newf0) = f00; /* Insert newf0 in the collision list ylist[posn]; ** increase the ref counts of f11 and f00. */ newykeys++; newf0->next = ylist[posn]; ylist[posn] = newf0; cuddSatInc(f11->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Re-insert the modified f in xlist. ** The modified f does not already exists in xlist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, xshift); newxkeys++; f->next = xlist[posn]; xlist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer and move the marked nodes to the x list. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previous = NULL; f = ylist[i]; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; if (previous == NULL) ylist[i] = next; else previous->next = next; } else if ((int) f->index == xindex) { /* move marked node */ if (previous == NULL) ylist[i] = next; else previous->next = next; f1 = cuddT(f); cuddSatDec(f1->ref); /* Check ylist for triple (yindex, f1, empty). */ posn = ddHash(f1, empty, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f1 && cuddE(newf1) == empty && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f1; cuddE(newf1) = empty; /* Insert newf1 in the collision list ylist[posn]; ** increase the ref counts of f1 and empty. */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; if (posn == i && previous == NULL) previous = newf1; cuddSatInc(f1->ref); cuddSatInc(empty->ref); } cuddT(f) = newf1; f0 = cuddE(f); /* Insert f in x list. */ posn = ddHash(newf1, f0, xshift); newxkeys++; newykeys--; f->next = xlist[posn]; xlist[posn] = f; } else { previous = f; } f = next; } /* while f */ } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].keys = newxkeys; table->subtableZ[y].keys = newykeys; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); #if 0 (void) fprintf(table->out,"x = %d y = %d\n", x, y); (void) Cudd_DebugCheck(table); (void) Cudd_CheckKeys(table); #endif return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddLinearInPlace */
/**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; cuddDeallocNode(table, (DdNode *)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; cuddDeallocNode(table, (DdNode *)moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *)moveUp); moveUp = move; } return(1); cuddZddLinearAuxOutOfMem: if (moveDown != (Move *) CUDD_OUT_OF_MEM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocNode(table, (DdNode *)moveDown); moveDown = move; } } if (moveUp != (Move *) CUDD_OUT_OF_MEM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *)moveUp); moveUp = move; } } return(0); } /* end of cuddZddLinearAux */
/**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; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *) moveUp); moveUp = move; } return(1); ddSymmSiftingConvAuxOutOfMem: if (moveDown != MV_OOM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocNode(table, (DdNode *) moveDown); moveDown = move; } } if (moveUp != MV_OOM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) 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; cuddDeallocNode(table, (DdNode *) moveDown); moveDown = move; } while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *) moveUp); moveUp = move; } return(1); ddSymmSiftingAuxOutOfMem: if (moveDown != MV_OOM) { while (moveDown != NULL) { move = moveDown->next; cuddDeallocNode(table, (DdNode *) moveDown); moveDown = move; } } if (moveUp != MV_OOM) { while (moveUp != NULL) { move = moveUp->next; cuddDeallocNode(table, (DdNode *) moveUp); moveUp = move; } } return(0); } /* end of ddSymmSiftingAux */
/**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; cuddDeallocNode(table, (DdNode *)moves); moves = move; } return(NULL); } /* end of zddSwapAny */
/**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 [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; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(1); zddGroupSiftingAuxOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(0); } /* end of zddGroupSiftingAux */
/**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; int xindex, yindex; yindex = table->invpermZ[y]; 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 */ xindex = table->invpermZ[x]; 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; cuddDeallocNode(table, (DdNode *) *moves); *moves = move; } return(0); } /* end of zddGroupSiftingUp */
/**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; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingUp */