/**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; cuddDeallocMove(table, invmoves); invmoves = move; } return((Move *) CUDD_OUT_OF_MEM); } /* end of cuddZddUndoMoves */
/**Function******************************************************************** Synopsis [Given a set of moves, returns the ZDD heap to the position giving the minimum size.] Description [Given a set of moves, returns the ZDD heap to the position giving the minimum size. In case of ties, returns to the closest position giving the minimum size. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddSiftingBackward( DdManager * table, Move * moves, int size) { int i; int i_best; Move *move; int res; /* Find the minimum size among moves. */ i_best = -1; for (move = moves, i = 0; move != NULL; move = move->next, i++) { if (move->size < size) { i_best = i; size = move->size; } } for (move = moves, i = 0; move != NULL; move = move->next, i++) { if (i == i_best) break; res = cuddZddSwapInPlace(table, move->x, move->y); if (!res) return(0); if (i_best == -1 && res == size) break; } return(1); } /* end of cuddZddSiftingBackward */
/**Function******************************************************************** Synopsis [Given a set of moves, returns the ZDD heap to the position giving the minimum size.] Description [Given a set of moves, returns the ZDD heap to the position giving the minimum size. In case of ties, returns to the closest position giving the minimum size. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddLinearBackward( DdManager * table, int size, Move * moves) { Move *move; int res; /* Find the minimum size among moves. */ for (move = moves; move != NULL; move = move->next) { if (move->size < size) { size = move->size; } } for (move = moves; move != NULL; move = move->next) { if (move->size == size) return(1); if (move->flags == CUDD_LINEAR_TRANSFORM_MOVE) { res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y); if (!res) return(0); } res = cuddZddSwapInPlace(table, move->x, move->y); if (!res) return(0); if (move->flags == CUDD_INVERSE_TRANSFORM_MOVE) { res = cuddZddLinearInPlace(table,(int)move->x,(int)move->y); if (!res) return(0); } } return(1); } /* end of cuddZddLinearBackward */
/**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 [Moves one ZDD variable up.] Description [Takes a ZDD variable from position x and sifts it up to position xLow; xLow should be less than or equal to x. Returns 1 if successful; 0 otherwise] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zddSiftUp( DdManager * table, int x, int xLow) { int y; int size; y = cuddZddNextLow(table,x); while (y >= xLow) { size = cuddZddSwapInPlace(table,y,x); if (size == 0) { return(0); } x = y; y = cuddZddNextLow(table,x); } return(1); } /* end of zddSiftUp */
/** @brief Determines the best position for a variables and returns it there. @return 1 in case of success; 0 otherwise. @sideeffect None */ static int zddGroupSiftingBackward( DdManager * table, Move * moves, int size) { Move *move; int res; for (move = moves; move != NULL; move = move->next) { if (move->size < size) { size = move->size; } } for (move = moves; move != NULL; move = move->next) { if (move->size == size) return(1); if ((table->subtableZ[move->x].next == move->x) && (table->subtableZ[move->y].next == move->y)) { res = cuddZddSwapInPlace(table,(int)move->x,(int)move->y); if (!res) return(0); #ifdef DD_DEBUG if (table->enableExtraDebug > 0) (void) fprintf(table->out,"zddGroupSiftingBackward:\n"); assert(table->subtableZ[move->x].next == move->x); assert(table->subtableZ[move->y].next == move->y); #endif } else { /* Group move necessary */ res = zddGroupMoveBackward(table,(int)move->x,(int)move->y); if (!res) return(0); } } return(1); } /* end of zddGroupSiftingBackward */
/**Function******************************************************************** Synopsis [Given a set of moves, returns the ZDD heap to the position giving the minimum size.] Description [Given a set of moves, returns the ZDD heap to the position giving the minimum size. In case of ties, returns to the closest position giving the minimum size. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int cuddZddSymmSiftingBackward( DdManager * table, Move * moves, int size) { int i; int i_best; Move *move; int res; i_best = -1; for (move = moves, i = 0; move != NULL; move = move->next, i++) { if (move->size < size) { i_best = i; size = move->size; } } for (move = moves, i = 0; move != NULL; move = move->next, i++) { if (i == i_best) break; if ((table->subtableZ[move->x].next == move->x) && (table->subtableZ[move->y].next == move->y)) { res = cuddZddSwapInPlace(table, move->x, move->y); if (!res) return(0); } else { /* Group move necessary */ res = zdd_group_move_backward(table, move->x, move->y); } if (i_best == -1 && res == size) break; } return(1); } /* end of cuddZddSymmSiftingBackward */
/**Function******************************************************************** Synopsis [Undoes the swap of two groups.] Description [Undoes the swap of two groups. x is assumed to be the bottom variable of the first group. y is assumed to be the top variable of the second group. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zdd_group_move_backward( DdManager * table, int x, int y) { int size; int i, temp, gxtop, gxbot, gybot, yprev; /* NuSMV: add begin */ size = 0; /* NuSMV: add end */ #ifdef DD_DEBUG assert(x < y); /* we assume that x < y */ #endif /* Find top and bottom of the two groups. */ gxtop = table->subtableZ[x].next; gxbot = x; gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; yprev = gybot; while (x <= y) { while (y > gxtop) { /* Set correct symmetries. */ temp = table->subtableZ[x].next; if (temp == x) temp = y; i = gxtop; for (;;) { if (table->subtableZ[i].next == (unsigned) x) { table->subtableZ[i].next = y; break; } else { i = table->subtableZ[i].next; } } if (table->subtableZ[y].next != (unsigned) y) { table->subtableZ[x].next = table->subtableZ[y].next; } else { table->subtableZ[x].next = x; } if (yprev != y) { table->subtableZ[yprev].next = x; } else { yprev = x; } table->subtableZ[y].next = temp; size = cuddZddSwapInPlace(table, x, y); if (size == 0) return(0); y = x; x--; } /* while y > gxtop */ /* Trying to find the next y. */ if (table->subtableZ[y].next <= (unsigned) y) { gybot = y; } else { y = table->subtableZ[y].next; } yprev = gxtop; gxtop++; gxbot++; x = gxbot; } /* while x <= y, end of group movement backward */ return(size); } /* end of zdd_group_move_backward */
/**Function******************************************************************** Synopsis [Swaps two groups.] Description [Swaps two groups. x is assumed to be the bottom variable of the first group. y is assumed to be the top variable of the second group. Updates the list of moves. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zdd_group_move( DdManager * table, int x, int y, Move ** moves) { Move *move; int size; int i, temp, gxtop, gxbot, gybot, yprev; int swapx, swapy; /* NuSMV: add begin */ swapy = 0; swapx = 0; /* NuSMV: add end */ #ifdef DD_DEBUG assert(x < y); /* we assume that x < y */ #endif /* Find top and bottom for the two groups. */ gxtop = table->subtableZ[x].next; gxbot = x; gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; yprev = gybot; while (x <= y) { while (y > gxtop) { /* Set correct symmetries. */ temp = table->subtableZ[x].next; if (temp == x) temp = y; i = gxtop; for (;;) { if (table->subtableZ[i].next == (unsigned) x) { table->subtableZ[i].next = y; break; } else { i = table->subtableZ[i].next; } } if (table->subtableZ[y].next != (unsigned) y) { table->subtableZ[x].next = table->subtableZ[y].next; } else { table->subtableZ[x].next = x; } if (yprev != y) { table->subtableZ[yprev].next = x; } else { yprev = x; } table->subtableZ[y].next = temp; size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto zdd_group_moveOutOfMem; swapx = x; swapy = y; y = x; x--; } /* while y > gxtop */ /* Trying to find the next y. */ if (table->subtableZ[y].next <= (unsigned) y) { gybot = y; } else { y = table->subtableZ[y].next; } yprev = gxtop; gxtop++; gxbot++; x = gxbot; } /* while x <= y, end of group movement */ move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto zdd_group_moveOutOfMem; move->x = swapx; move->y = swapy; move->size = table->keysZ; move->next = *moves; *moves = move; return(table->keysZ); zdd_group_moveOutOfMem: while (*moves != NULL) { move = (*moves)->next; cuddDeallocMove(table, *moves); *moves = move; } return(0); } /* end of zdd_group_move */
/**Function******************************************************************** Synopsis [Moves x down until either it reaches the bound (x_high) or the size of the ZDD heap increases too much.] Description [Moves x down until either it reaches the bound (x_high) or the size of the ZDD heap increases too much. Assumes that x is the bottom of a symmetry group. Checks x for symmetry to the adjacent variables. If symmetry is found, the symmetry group of x is merged with the symmetry group of the other variable. Returns the set of moves in case of success; ZDD_MV_OOM if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * cuddZddSymmSifting_down( DdManager * table, int x, int x_high, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; int i, gxtop, gybot; moves = NULL; y = cuddZddNextHigh(table, x); while (y <= x_high) { gybot = table->subtableZ[y].next; while (table->subtableZ[gybot].next != (unsigned) y) gybot = table->subtableZ[gybot].next; if (cuddZddSymmCheck(table, x, y)) { /* Symmetry found, attach symm groups */ gxtop = table->subtableZ[x].next; table->subtableZ[x].next = y; i = table->subtableZ[y].next; while (table->subtableZ[i].next != (unsigned) y) i = table->subtableZ[i].next; table->subtableZ[i].next = gxtop; } else if ((table->subtableZ[x].next == (unsigned) x) && (table->subtableZ[y].next == (unsigned) y)) { /* x and y have self symmetry */ size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto cuddZddSymmSifting_downOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto cuddZddSymmSifting_downOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double)size > (double)limit_size * table->maxGrowth) return(moves); if (size < limit_size) limit_size = size; x = y; y = cuddZddNextHigh(table, x); } else { /* Group move */ size = zdd_group_move(table, x, y, &moves); if ((double)size > (double)limit_size * table->maxGrowth) return(moves); if (size < limit_size) limit_size = size; } x = gybot; y = cuddZddNextHigh(table, x); } return(moves); cuddZddSymmSifting_downOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(ZDD_MV_OOM); } /* end of cuddZddSymmSifting_down */
/**Function******************************************************************** Synopsis [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 [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 [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 [Undoes the swap two groups.] Description [Undoes the swap two groups. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupMoveBackward( DdManager * table, int x, int y) { int size; int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop; #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; /* 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) return(0); y = x; x = cuddZddNextLow(table,y); } y = ytop + i; x = cuddZddNextLow(table,y); } /* fix groups */ y = xtop; 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 */ /* to its top */ 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 */ /* to its top */ #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupMoveBackward:\n"); #endif return(1); } /* end of zddGroupMoveBackward */
/**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 [Sifts a variable down and applies the XOR transformation.] Description [Sifts a variable down. Moves x down until either it reaches the bound (xHigh) or the size of the ZDD heap increases too much. Returns the set of moves in case of success; NULL if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * cuddZddLinearDown( DdManager * table, int x, int xHigh, Move * prevMoves) { Move *moves; Move *move; int y; int size, newsize; int limitSize; moves = prevMoves; limitSize = table->keysZ; y = cuddZddNextHigh(table, x); while (y <= xHigh) { size = cuddZddSwapInPlace(table, x, y); if (size == 0) goto cuddZddLinearDownOutOfMem; newsize = cuddZddLinearInPlace(table, x, y); if (newsize == 0) goto cuddZddLinearDownOutOfMem; move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto cuddZddLinearDownOutOfMem; move->x = x; move->y = y; move->next = moves; moves = move; move->flags = CUDD_SWAP_MOVE; if (newsize > size) { /* Undo transformation. The transformation we apply is ** its own inverse. Hence, we just apply the transformation ** again. */ newsize = cuddZddLinearInPlace(table,x,y); if (newsize == 0) goto cuddZddLinearDownOutOfMem; if (newsize != size) { (void) fprintf(table->err,"Change in size after identity transformation! From %d to %d\n",size,newsize); } } else { size = newsize; move->flags = CUDD_LINEAR_TRANSFORM_MOVE; } move->size = size; if ((double)size > (double)limitSize * table->maxGrowth) break; if (size < limitSize) limitSize = size; x = y; y = cuddZddNextHigh(table, x); } return(moves); cuddZddLinearDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return((Move *) CUDD_OUT_OF_MEM); } /* end of cuddZddLinearDown */