Beispiel #1
0
/**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 */
Beispiel #3
0
/**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 */
Beispiel #4
0
/**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 */
Beispiel #5
0
/**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 */
Beispiel #6
0
/**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 &lt; 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 */
Beispiel #7
0
/**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 */
Beispiel #8
0
/**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 */
Beispiel #10
0
/**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 */
Beispiel #11
0
/**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 &lt; 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 */
Beispiel #16
0
/**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 */
Beispiel #17
0
/**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 */
Beispiel #18
0
/**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 */
Beispiel #19
0
/**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 */