/**Function******************************************************************** Synopsis [Restores the variable order in array by a series of sifts up.] Description [Restores the variable order in array by a series of sifts up. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int restoreOrder( DdManager * table, int * array, int lower, int upper) { int i, x, y, size; int nvars = upper - lower + 1; for (i = 0; i < nvars; i++) { x = table->perm[array[i]]; #ifdef DD_DEBUG assert(x >= lower && x <= upper); #endif y = cuddNextLow(table,x); while (y >= i + lower) { size = cuddSwapInPlace(table,y,x); if (size == 0) return(0); x = y; y = cuddNextLow(table,x); } } return(1); } /* end of restoreOrder */
/**Function******************************************************************** Synopsis [Given a set of moves, returns the DD heap to the position giving the minimum size.] Description [Given a set of moves, returns the DD 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] ******************************************************************************/ static int ddSymmSiftingBackward( 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->subtables[move->x].next == move->x && table->subtables[move->y].next == move->y) { res = cuddSwapInPlace(table,(int)move->x,(int)move->y); #ifdef DD_DEBUG assert(table->subtables[move->x].next == move->x); assert(table->subtables[move->y].next == move->y); #endif } else { /* Group move necessary */ res = ddSymmGroupMoveBackward(table,(int)move->x,(int)move->y); } if (!res) return(0); } return(1); } /* end of ddSymmSiftingBackward */
/** @brief Undoes the swap of two groups. @details x is assumed to be the bottom variable of the first group. y is assumed to be the top variable of the second group. @return the number of keys in the table if successful; 0 otherwise. @sideeffect None */ static int ddSymmGroupMoveBackward( DdManager * table, int x, int y) { int size = (int) (table->keys - table->isolated); int i,j; int xtop,xbot,xsize,ytop,ybot,ysize,newxtop; #ifdef DD_DEBUG assert(x < y); /* We assume that x < y */ #endif /* Find top, bottom, and size for the two groups. */ xbot = x; xtop = table->subtables[x].next; xsize = xbot - xtop + 1; ybot = y; while ((unsigned) ybot < table->subtables[ybot].next) ybot = table->subtables[ybot].next; ytop = y; ysize = ybot - ytop + 1; #ifdef DD_DEBUG assert(xsize > 0); assert(ysize > 0); #endif /* Sift the variables of the second group up through the first group. */ for (i = 1; i <= ysize; i++) { for (j = 1; j <= xsize; j++) { size = cuddSwapInPlace(table,x,y); if (size == 0) return(0); y = x; x = cuddNextLow(table,y); } y = ytop + i; x = y - 1; } /* Fix symmetries. */ y = xtop; for (i = 0; i < ysize-1 ; i++) { table->subtables[y].next = y + 1; y = y + 1; } table->subtables[y].next = xtop; /* y is bottom of its group, join */ /* its symmetry to top of its group */ x = y + 1; newxtop = x; for (i = 0; i < xsize-1 ; i++) { table->subtables[x].next = x + 1; x = x + 1; } table->subtables[x].next = newxtop; /* x is bottom of its group, join */ /* its symmetry to top of its group */ return(size); } /* end of ddSymmGroupMoveBackward */
/**Function******************************************************************** Synopsis [Reorders by applying a sliding window of width 2.] Description [Reorders by applying a sliding window of width 2. Tries both permutations of the variables in a window that slides from low to high. Assumes that no dead nodes are present. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddWindow2( DdManager * table, int low, int high) { int x; int res; int size; #ifdef DD_DEBUG assert(low >= 0 && high < table->size); #endif if (high-low < 1) return(0); res = table->keys - table->isolated; for (x = low; x < high; x++) { size = res; res = cuddSwapInPlace(table,x,x+1); if (res == 0) return(0); if (res >= size) { /* no improvement: undo permutation */ res = cuddSwapInPlace(table,x,x+1); if (res == 0) return(0); } #ifdef DD_STATS if (res < size) { (void) fprintf(table->out,"-"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } return(1); } /* end of ddWindow2 */
/**Function******************************************************************** Synopsis [Returns the DD to the best position encountered during sifting if there was improvement.] Description [Otherwise, "tosses a coin" to decide whether to keep the current configuration or return the DD to the original one. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int siftBackwardProb( DdManager * table, Move * moves, int size, double temp) { Move *move; int res; int best_size = size; double coin, threshold; /* Look for best size during the last sifting */ for (move = moves; move != NULL; move = move->next) { if (move->size < best_size) { best_size = move->size; } } /* If best_size equals size, the last sifting did not produce any ** improvement. We now toss a coin to decide whether to retain ** this change or not. */ if (best_size == size) { coin = random_generator(); #ifdef DD_STATS tosses++; #endif threshold = exp(-((double)(table->keys - table->isolated - size))/temp); if (coin < threshold) { #ifdef DD_STATS acceptances++; #endif return(1); } } /* Either there was improvement, or we have decided not to ** accept the uphill move. Go to best position. */ res = table->keys - table->isolated; for (move = moves; move != NULL; move = move->next) { if (res == best_size) return(1); res = cuddSwapInPlace(table,(int)move->x,(int)move->y); if (!res) return(0); } return(1); } /* end of sift_backward_prob */
/**Function******************************************************************** Synopsis [This function is for jumping down.] Description [This is a simplified version of ddSiftingDown. It does not use lower bounding. Returns the set of moves in case of success; NULL if memory is full.] SideEffects [None] SeeAlso [] ******************************************************************************/ static Move * ddJumpingDown( DdManager * table, int x, int x_high, int initial_size) { Move *moves; Move *move; int y; int size; int limit_size = initial_size; moves = NULL; y = cuddNextHigh(table,x); while (y <= x_high) { size = cuddSwapInPlace(table,x,y); if (size == 0) goto ddJumpingDownOutOfMem; move = (Move *)cuddDynamicAllocNode(table); if (move == NULL) goto ddJumpingDownOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double) size > table->maxGrowth * (double) limit_size) { break; } else if (size < limit_size) { limit_size = size; } x = y; y = cuddNextHigh(table,x); } return(moves); ddJumpingDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocNode(table, (DdNode *) moves); moves = move; } return(NULL); } /* end of ddJumpingDown */
/**Function******************************************************************** Synopsis [Moves one variable up.] Description [Takes a variable from position x and sifts it up to position x_low; x_low should be less than x. Returns 1 if successful; 0 otherwise] SideEffects [None] SeeAlso [] ******************************************************************************/ static int sift_up( DdManager * table, int x, int x_low) { int y; int size; y = cuddNextLow(table,x); while (y >= x_low) { size = cuddSwapInPlace(table,y,x); if (size == 0) { return(0); } x = y; y = cuddNextLow(table,x); } return(1); } /* end of sift_up */
/**Function******************************************************************** Synopsis [Tries all the permutations of the four variables between w and w+3 and retains the best.] Description [Tries all the permutations of the four variables between w and w+3 and retains the best. Assumes that no dead nodes are present. Returns the index of the best permutation (1-24) in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddPermuteWindow4( DdManager * table, int w) { int x,y,z; int size,sizeNew; int best; #ifdef DD_DEBUG assert(table->dead == 0); assert(w+3 < table->size); #endif size = table->keys - table->isolated; x = w+1; y = x+1; z = y+1; /* The permutation pattern is: * (w,x)(y,z)(w,x)(x,y) * (y,z)(w,x)(y,z)(x,y) * repeated three times to get all 4! = 24 permutations. * This gives a hamiltonian circuit of Cayley's graph. * The codes to the permutation are assigned in topological order. * The permutations at lower distance from the final permutation are * assigned lower codes. This way we can choose, between * permutations that give the same size, one that requires the minimum * number of swaps from the final permutation of the hamiltonian circuit. * There is an exception to this rule: ABCD is given Code 1, to * avoid oscillation when convergence is sought. */ #define ABCD 1 best = ABCD; #define BACD 7 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size) { if (sizeNew == 0) return(0); best = BACD; size = sizeNew; } #define BADC 13 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size) { if (sizeNew == 0) return(0); best = BADC; size = sizeNew; } #define ABDC 8 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && ABDC < best)) { if (sizeNew == 0) return(0); best = ABDC; size = sizeNew; } #define ADBC 14 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size) { if (sizeNew == 0) return(0); best = ADBC; size = sizeNew; } #define ADCB 9 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && ADCB < best)) { if (sizeNew == 0) return(0); best = ADCB; size = sizeNew; } #define DACB 15 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size) { if (sizeNew == 0) return(0); best = DACB; size = sizeNew; } #define DABC 20 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size) { if (sizeNew == 0) return(0); best = DABC; size = sizeNew; } #define DBAC 23 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size) { if (sizeNew == 0) return(0); best = DBAC; size = sizeNew; } #define BDAC 19 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && BDAC < best)) { if (sizeNew == 0) return(0); best = BDAC; size = sizeNew; } #define BDCA 21 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && BDCA < best)) { if (sizeNew == 0) return(0); best = BDCA; size = sizeNew; } #define DBCA 24 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size) { if (sizeNew == 0) return(0); best = DBCA; size = sizeNew; } #define DCBA 22 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size || (sizeNew == size && DCBA < best)) { if (sizeNew == 0) return(0); best = DCBA; size = sizeNew; } #define DCAB 18 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && DCAB < best)) { if (sizeNew == 0) return(0); best = DCAB; size = sizeNew; } #define CDAB 12 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && CDAB < best)) { if (sizeNew == 0) return(0); best = CDAB; size = sizeNew; } #define CDBA 17 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && CDBA < best)) { if (sizeNew == 0) return(0); best = CDBA; size = sizeNew; } #define CBDA 11 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size || (sizeNew == size && CBDA < best)) { if (sizeNew == 0) return(0); best = CBDA; size = sizeNew; } #define BCDA 16 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && BCDA < best)) { if (sizeNew == 0) return(0); best = BCDA; size = sizeNew; } #define BCAD 10 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && BCAD < best)) { if (sizeNew == 0) return(0); best = BCAD; size = sizeNew; } #define CBAD 5 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && CBAD < best)) { if (sizeNew == 0) return(0); best = CBAD; size = sizeNew; } #define CABD 3 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size || (sizeNew == size && CABD < best)) { if (sizeNew == 0) return(0); best = CABD; size = sizeNew; } #define CADB 6 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && CADB < best)) { if (sizeNew == 0) return(0); best = CADB; size = sizeNew; } #define ACDB 4 sizeNew = cuddSwapInPlace(table,w,x); if (sizeNew < size || (sizeNew == size && ACDB < best)) { if (sizeNew == 0) return(0); best = ACDB; size = sizeNew; } #define ACBD 2 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size || (sizeNew == size && ACBD < best)) { if (sizeNew == 0) return(0); best = ACBD; size = sizeNew; } /* Now take the shortest route to the best permutation. ** The initial permutation is ACBD. */ switch(best) { case DBCA: if (!cuddSwapInPlace(table,y,z)) return(0); case BDCA: if (!cuddSwapInPlace(table,x,y)) return(0); case CDBA: if (!cuddSwapInPlace(table,w,x)) return(0); case ADBC: if (!cuddSwapInPlace(table,y,z)) return(0); case ABDC: if (!cuddSwapInPlace(table,x,y)) return(0); case ACDB: if (!cuddSwapInPlace(table,y,z)) return(0); case ACBD: break; case DCBA: if (!cuddSwapInPlace(table,y,z)) return(0); case BCDA: if (!cuddSwapInPlace(table,x,y)) return(0); case CBDA: if (!cuddSwapInPlace(table,w,x)) return(0); if (!cuddSwapInPlace(table,x,y)) return(0); if (!cuddSwapInPlace(table,y,z)) return(0); break; case DBAC: if (!cuddSwapInPlace(table,x,y)) return(0); case DCAB: if (!cuddSwapInPlace(table,w,x)) return(0); case DACB: if (!cuddSwapInPlace(table,y,z)) return(0); case BACD: if (!cuddSwapInPlace(table,x,y)) return(0); case CABD: if (!cuddSwapInPlace(table,w,x)) return(0); break; case DABC: if (!cuddSwapInPlace(table,y,z)) return(0); case BADC: if (!cuddSwapInPlace(table,x,y)) return(0); case CADB: if (!cuddSwapInPlace(table,w,x)) return(0); if (!cuddSwapInPlace(table,y,z)) return(0); break; case BDAC: if (!cuddSwapInPlace(table,x,y)) return(0); case CDAB: if (!cuddSwapInPlace(table,w,x)) return(0); case ADCB: if (!cuddSwapInPlace(table,y,z)) return(0); case ABCD: if (!cuddSwapInPlace(table,x,y)) return(0); break; case BCAD: if (!cuddSwapInPlace(table,x,y)) return(0); case CBAD: if (!cuddSwapInPlace(table,w,x)) return(0); if (!cuddSwapInPlace(table,x,y)) return(0); break; default: return(0); } #ifdef DD_DEBUG assert(table->keys - table->isolated == (unsigned) size); #endif return(best); } /* end of ddPermuteWindow4 */
/**Function******************************************************************** Synopsis [Tries all the permutations of the three variables between x and x+2 and retains the best.] Description [Tries all the permutations of the three variables between x and x+2 and retains the best. Assumes that no dead nodes are present. Returns the index of the best permutation (1-6) in case of success; 0 otherwise.Assumes that no dead nodes are present. Returns the index of the best permutation (1-6) in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddPermuteWindow3( DdManager * table, int x) { int y,z; int size,sizeNew; int best; #ifdef DD_DEBUG assert(table->dead == 0); assert(x+2 < table->size); #endif size = table->keys - table->isolated; y = x+1; z = y+1; /* The permutation pattern is: ** (x,y)(y,z) ** repeated three times to get all 3! = 6 permutations. */ #define ABC 1 best = ABC; #define BAC 2 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size) { if (sizeNew == 0) return(0); best = BAC; size = sizeNew; } #define BCA 3 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size) { if (sizeNew == 0) return(0); best = BCA; size = sizeNew; } #define CBA 4 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size) { if (sizeNew == 0) return(0); best = CBA; size = sizeNew; } #define CAB 5 sizeNew = cuddSwapInPlace(table,y,z); if (sizeNew < size) { if (sizeNew == 0) return(0); best = CAB; size = sizeNew; } #define ACB 6 sizeNew = cuddSwapInPlace(table,x,y); if (sizeNew < size) { if (sizeNew == 0) return(0); best = ACB; size = sizeNew; } /* Now take the shortest route to the best permuytation. ** The initial permutation is ACB. */ switch(best) { case BCA: if (!cuddSwapInPlace(table,y,z)) return(0); case CBA: if (!cuddSwapInPlace(table,x,y)) return(0); case ABC: if (!cuddSwapInPlace(table,y,z)) return(0); case ACB: break; case BAC: if (!cuddSwapInPlace(table,y,z)) return(0); case CAB: if (!cuddSwapInPlace(table,x,y)) return(0); break; default: return(0); } #ifdef DD_DEBUG assert(table->keys - table->isolated == (unsigned) size); #endif return(best); } /* end of ddPermuteWindow3 */
/**Function******************************************************************** Synopsis [Reorders by repeatedly applying a sliding window of width 2.] Description [Reorders by repeatedly applying a sliding window of width 2. Tries both permutations of the variables in a window that slides from low to high. Assumes that no dead nodes are present. Uses an event-driven approach to determine convergence. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int ddWindowConv2( DdManager * table, int low, int high) { int x; int res; int nwin; int newevent; int *events; int size; #ifdef DD_DEBUG assert(low >= 0 && high < table->size); #endif if (high-low < 1) return(ddWindowConv2(table,low,high)); nwin = high-low; events = ALLOC(int,nwin); if (events == NULL) { table->errorCode = CUDD_MEMORY_OUT; return(0); } for (x=0; x<nwin; x++) { events[x] = 1; } res = table->keys - table->isolated; do { newevent = 0; for (x=0; x<nwin; x++) { if (events[x]) { size = res; res = cuddSwapInPlace(table,x+low,x+low+1); if (res == 0) { FREE(events); return(0); } if (res >= size) { /* no improvement: undo permutation */ res = cuddSwapInPlace(table,x+low,x+low+1); if (res == 0) { FREE(events); return(0); } } if (res < size) { if (x < nwin-1) events[x+1] = 1; if (x > 0) events[x-1] = 1; newevent = 1; } events[x] = 0; #ifdef DD_STATS if (res < size) { (void) fprintf(table->out,"-"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } #ifdef DD_STATS if (newevent) { (void) fprintf(table->out,"|"); fflush(table->out); } #endif } while (newevent); FREE(events); return(1); } /* end of ddWindowConv3 */
/**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 [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] ******************************************************************************/ static int ddSymmGroupMove( DdManager * table, int x, int y, Move ** moves) { Move *move; int size; int i,j; int xtop,xbot,xsize,ytop,ybot,ysize,newxtop; int swapx,swapy; #ifdef DD_DEBUG assert(x < y); /* we assume that x < y */ #endif /* Find top, bottom, and size for the two groups. */ xbot = x; xtop = table->subtables[x].next; xsize = xbot - xtop + 1; ybot = y; while ((unsigned) ybot < table->subtables[ybot].next) ybot = table->subtables[ybot].next; ytop = y; ysize = ybot - ytop + 1; /* Sift the variables of the second group up through the first group. */ for (i = 1; i <= ysize; i++) { for (j = 1; j <= xsize; j++) { size = cuddSwapInPlace(table,x,y); if (size == 0) return(0); swapx = x; swapy = y; y = x; x = y - 1; } y = ytop + i; x = y - 1; } /* fix symmetries */ y = xtop; /* ytop is now where xtop used to be */ for (i = 0; i < ysize-1 ; i++) { table->subtables[y].next = y + 1; y = y + 1; } table->subtables[y].next = xtop; /* y is bottom of its group, join */ /* its symmetry to top of its group */ x = y + 1; newxtop = x; for (i = 0; i < xsize - 1 ; i++) { table->subtables[x].next = x + 1; x = x + 1; } table->subtables[x].next = newxtop; /* x is bottom of its group, join */ /* its symmetry to top of its group */ /* Store group move */ move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) return(0); move->x = swapx; move->y = swapy; move->size = size; move->next = *moves; *moves = move; return(size); } /* end of ddSymmGroupMove */
/**Function******************************************************************** Synopsis [Moves x down until either it reaches the bound (xHigh) or the size of the DD heap increases too much.] Description [Moves x down until either it reaches the bound (xHigh) or the size of the DD heap increases too much. Assumes that x is the bottom of a symmetry group. Checks x for symmetry to the adjacent variables. If symmetry is found, the symmetry group of x is merged with the symmetry group of the other variable. Returns the set of moves in case of success; MV_OOM if memory is full.] SideEffects [None] ******************************************************************************/ static Move * ddSymmSiftingDown( DdManager * table, int x, int xHigh) { Move *moves; Move *move; int y; int size; int limitSize; int gxtop,gybot; int R; /* upper bound on node decrease */ int xindex, yindex; int isolated; int z; int zindex; #ifdef DD_DEBUG int checkR; #endif moves = NULL; /* Initialize R */ xindex = table->invperm[x]; gxtop = table->subtables[x].next; limitSize = size = table->keys - table->isolated; R = 0; for (z = xHigh; z > gxtop; z--) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R += table->subtables[z].keys - isolated; } } y = cuddNextHigh(table,x); while (y <= xHigh && size - R < limitSize) { #ifdef DD_DEBUG gxtop = table->subtables[x].next; checkR = 0; for (z = xHigh; z > gxtop; z--) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; checkR += table->subtables[z].keys - isolated; } } assert(R == checkR); #endif gybot = table->subtables[y].next; while (table->subtables[gybot].next != (unsigned) y) gybot = table->subtables[gybot].next; if (cuddSymmCheck(table,x,y)) { /* Symmetry found, attach symm groups */ gxtop = table->subtables[x].next; table->subtables[x].next = y; table->subtables[gybot].next = gxtop; } else if (table->subtables[x].next == (unsigned) x && table->subtables[y].next == (unsigned) y) { /* x and y have self symmetry */ /* Update upper bound on node decrease. */ yindex = table->invperm[y]; if (cuddTestInteract(table,xindex,yindex)) { isolated = table->vars[yindex]->ref == 1; R -= table->subtables[y].keys - isolated; } size = cuddSwapInPlace(table,x,y); #ifdef DD_DEBUG assert(table->subtables[x].next == (unsigned) x); assert(table->subtables[y].next == (unsigned) y); #endif if (size == 0) goto ddSymmSiftingDownOutOfMem; move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto ddSymmSiftingDownOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; } else { /* Group move */ /* Update upper bound on node decrease: first phase. */ gxtop = table->subtables[x].next; z = gxtop + 1; do { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R -= table->subtables[z].keys - isolated; } z++; } while (z <= gybot); size = ddSymmGroupMove(table,x,y,&moves); if (size == 0) goto ddSymmSiftingDownOutOfMem; if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; /* Update upper bound on node decrease: second phase. */ gxtop = table->subtables[gybot].next; for (z = gxtop + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == xindex || cuddTestInteract(table,xindex,zindex)) { isolated = table->vars[zindex]->ref == 1; R += table->subtables[z].keys - isolated; } } } x = gybot; y = cuddNextHigh(table,x); } return(moves); ddSymmSiftingDownOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingDown */
/**Function******************************************************************** Synopsis [Moves x up until either it reaches the bound (xLow) or the size of the DD heap increases too much.] Description [Moves x up until either it reaches the bound (xLow) or the size of the DD heap increases too much. Assumes that x is the top of a symmetry group. Checks x for symmetry to the adjacent variables. If symmetry is found, the symmetry group of x is merged with the symmetry group of the other variable. Returns the set of moves in case of success; MV_OOM if memory is full.] SideEffects [None] ******************************************************************************/ static Move * ddSymmSiftingUp( DdManager * table, int y, int xLow) { Move *moves; Move *move; int x; int size; int i; int gxtop,gybot; int limitSize; int xindex, yindex; int zindex; int z; int isolated; int L; /* lower bound on DD size */ #ifdef DD_DEBUG int checkL; #endif moves = NULL; yindex = table->invperm[y]; /* Initialize the lower bound. ** The part of the DD below the bottom of y' group will not change. ** The part of the DD above y that does not interact with y will not ** change. The rest may vanish in the best case, except for ** the nodes at level xLow, which will not vanish, regardless. */ limitSize = L = table->keys - table->isolated; gybot = y; while ((unsigned) gybot < table->subtables[gybot].next) gybot = table->subtables[gybot].next; for (z = xLow + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; L -= table->subtables[z].keys - isolated; } } x = cuddNextLow(table,y); while (x >= xLow && L <= limitSize) { #ifdef DD_DEBUG gybot = y; while ((unsigned) gybot < table->subtables[gybot].next) gybot = table->subtables[gybot].next; checkL = table->keys - table->isolated; for (z = xLow + 1; z <= gybot; z++) { zindex = table->invperm[z]; if (zindex == yindex || cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; checkL -= table->subtables[z].keys - isolated; } } assert(L == checkL); #endif gxtop = table->subtables[x].next; if (cuddSymmCheck(table,x,y)) { /* Symmetry found, attach symm groups */ table->subtables[x].next = y; i = table->subtables[y].next; while (table->subtables[i].next != (unsigned) y) i = table->subtables[i].next; table->subtables[i].next = gxtop; } else if (table->subtables[x].next == (unsigned) x && table->subtables[y].next == (unsigned) y) { /* x and y have self symmetry */ xindex = table->invperm[x]; size = cuddSwapInPlace(table,x,y); #ifdef DD_DEBUG assert(table->subtables[x].next == (unsigned) x); assert(table->subtables[y].next == (unsigned) y); #endif if (size == 0) goto ddSymmSiftingUpOutOfMem; /* Update the lower bound. */ if (cuddTestInteract(table,xindex,yindex)) { isolated = table->vars[xindex]->ref == 1; L += table->subtables[y].keys - isolated; } move = (Move *) cuddDynamicAllocNode(table); if (move == NULL) goto ddSymmSiftingUpOutOfMem; move->x = x; move->y = y; move->size = size; move->next = moves; moves = move; if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; } else { /* Group move */ size = ddSymmGroupMove(table,x,y,&moves); if (size == 0) goto ddSymmSiftingUpOutOfMem; /* Update the lower bound. */ z = moves->y; do { zindex = table->invperm[z]; if (cuddTestInteract(table,zindex,yindex)) { isolated = table->vars[zindex]->ref == 1; L += table->subtables[z].keys - isolated; } z = table->subtables[z].next; } while (z != (int) moves->y); if ((double) size > (double) limitSize * table->maxGrowth) return(moves); if (size < limitSize) limitSize = size; } y = gxtop; x = cuddNextLow(table,y); } return(moves); ddSymmSiftingUpOutOfMem: while (moves != NULL) { move = moves->next; cuddDeallocMove(table, moves); moves = move; } return(MV_OOM); } /* end of ddSymmSiftingUp */