You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
757 lines
19 KiB
757 lines
19 KiB
/**
|
|
@file
|
|
|
|
@ingroup cudd
|
|
|
|
@brief Reordering of DDs based on simulated annealing
|
|
|
|
@author Jae-Young Jang, Jorgen Sivesind
|
|
|
|
@copyright@parblock
|
|
Copyright (c) 1995-2015, Regents of the University of Colorado
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
Neither the name of the University of Colorado nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@endparblock
|
|
|
|
*/
|
|
|
|
#include "util.h"
|
|
#include "cuddInt.h"
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* Annealing parameters */
|
|
#define BETA 0.6
|
|
#define ALPHA 0.90
|
|
#define EXC_PROB 0.4
|
|
#define JUMP_UP_PROB 0.36
|
|
#define MAXGEN_RATIO 15.0
|
|
#define STOP_TEMP 1.0
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/** \cond */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int stopping_criterion (int c1, int c2, int c3, int c4, double temp);
|
|
static double random_generator (DdManager *dd);
|
|
static int ddExchange (DdManager *table, int x, int y, double temp);
|
|
static int ddJumpingAux (DdManager *table, int x, int x_low, int x_high, double temp);
|
|
static Move * ddJumpingUp (DdManager *table, int x, int x_low, int initial_size);
|
|
static Move * ddJumpingDown (DdManager *table, int x, int x_high, int initial_size);
|
|
static int siftBackwardProb (DdManager *table, Move *moves, int size, double temp);
|
|
static void copyOrder (DdManager *table, int *array, int lower, int upper);
|
|
static int restoreOrder (DdManager *table, int *array, int lower, int upper);
|
|
|
|
/** \endcond */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**
|
|
@brief Get new variable-order by simulated annealing algorithm.
|
|
|
|
@details Get x, y by random selection. Choose either
|
|
exchange or jump randomly. In case of jump, choose between jump_up
|
|
and jump_down randomly. Do exchange or jump and get optimal case.
|
|
Loop until there is no improvement or temperature reaches
|
|
minimum.
|
|
|
|
@return 1 in case of success; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
int
|
|
cuddAnnealing(
|
|
DdManager * table,
|
|
int lower,
|
|
int upper)
|
|
{
|
|
int nvars;
|
|
int size;
|
|
int x,y;
|
|
int result;
|
|
int c1, c2, c3, c4;
|
|
int BestCost;
|
|
int *BestOrder;
|
|
double NewTemp, temp;
|
|
double rand1;
|
|
int innerloop, maxGen;
|
|
int ecount, ucount, dcount;
|
|
|
|
nvars = upper - lower + 1;
|
|
|
|
result = cuddSifting(table,lower,upper);
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"\n");
|
|
#endif
|
|
if (result == 0) return(0);
|
|
|
|
size = (int) (table->keys - table->isolated);
|
|
|
|
/* Keep track of the best order. */
|
|
BestCost = size;
|
|
BestOrder = ALLOC(int,nvars);
|
|
if (BestOrder == NULL) {
|
|
table->errorCode = CUDD_MEMORY_OUT;
|
|
return(0);
|
|
}
|
|
copyOrder(table,BestOrder,lower,upper);
|
|
|
|
temp = BETA * size;
|
|
maxGen = (int) (MAXGEN_RATIO * nvars);
|
|
|
|
c1 = size + 10;
|
|
c2 = c1 + 10;
|
|
c3 = size;
|
|
c4 = c2 + 10;
|
|
ecount = ucount = dcount = 0;
|
|
|
|
while (!stopping_criterion(c1, c2, c3, c4, temp)) {
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"temp=%f\tsize=%d\tgen=%d\t",
|
|
temp,size,maxGen);
|
|
table->tosses = table->acceptances = 0;
|
|
#endif
|
|
for (innerloop = 0; innerloop < maxGen; innerloop++) {
|
|
/* Choose x, y randomly. */
|
|
x = (int) Cudd_Random(table) % nvars;
|
|
do {
|
|
y = (int) Cudd_Random(table) % nvars;
|
|
} while (x == y);
|
|
x += lower;
|
|
y += lower;
|
|
if (x > y) {
|
|
int tmp = x;
|
|
x = y;
|
|
y = tmp;
|
|
}
|
|
|
|
/* Choose move with roulette wheel. */
|
|
rand1 = random_generator(table);
|
|
if (rand1 < EXC_PROB) {
|
|
result = ddExchange(table,x,y,temp); /* exchange */
|
|
ecount++;
|
|
#if 0
|
|
(void) fprintf(table->out,
|
|
"Exchange of %d and %d: size = %d\n",
|
|
x,y,table->keys - table->isolated);
|
|
#endif
|
|
} else if (rand1 < EXC_PROB + JUMP_UP_PROB) {
|
|
result = ddJumpingAux(table,y,x,y,temp); /* jumping_up */
|
|
ucount++;
|
|
#if 0
|
|
(void) fprintf(table->out,
|
|
"Jump up of %d to %d: size = %d\n",
|
|
y,x,table->keys - table->isolated);
|
|
#endif
|
|
} else {
|
|
result = ddJumpingAux(table,x,x,y,temp); /* jumping_down */
|
|
dcount++;
|
|
#if 0
|
|
(void) fprintf(table->out,
|
|
"Jump down of %d to %d: size = %d\n",
|
|
x,y,table->keys - table->isolated);
|
|
#endif
|
|
}
|
|
|
|
if (!result) {
|
|
FREE(BestOrder);
|
|
return(0);
|
|
}
|
|
|
|
size = (int) (table->keys - table->isolated); /* keep current size */
|
|
if (size < BestCost) { /* update best order */
|
|
BestCost = size;
|
|
copyOrder(table,BestOrder,lower,upper);
|
|
}
|
|
}
|
|
c1 = c2;
|
|
c2 = c3;
|
|
c3 = c4;
|
|
c4 = size;
|
|
NewTemp = ALPHA * temp;
|
|
if (NewTemp >= 1.0) {
|
|
maxGen = (int)(log(NewTemp) / log(temp) * maxGen);
|
|
}
|
|
temp = NewTemp; /* control variable */
|
|
#ifdef DD_STATS
|
|
(void) fprintf(table->out,"uphill = %d\taccepted = %d\n",
|
|
table->tosses,table->acceptances);
|
|
fflush(table->out);
|
|
#endif
|
|
}
|
|
|
|
result = restoreOrder(table,BestOrder,lower,upper);
|
|
FREE(BestOrder);
|
|
if (!result) return(0);
|
|
#ifdef DD_STATS
|
|
fprintf(table->out,"#:N_EXCHANGE %8d : total exchanges\n",ecount);
|
|
fprintf(table->out,"#:N_JUMPUP %8d : total jumps up\n",ucount);
|
|
fprintf(table->out,"#:N_JUMPDOWN %8d : total jumps down",dcount);
|
|
#endif
|
|
return(1);
|
|
|
|
} /* end of cuddAnnealing */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
@brief Checks termination condition.
|
|
|
|
@details If temperature is STOP_TEMP or there is no improvement
|
|
then terminates.
|
|
|
|
@return 1 if the termination criterion is met; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static int
|
|
stopping_criterion(
|
|
int c1,
|
|
int c2,
|
|
int c3,
|
|
int c4,
|
|
double temp)
|
|
{
|
|
if (STOP_TEMP < temp) {
|
|
return(0);
|
|
} else if ((c1 == c2) && (c1 == c3) && (c1 == c4)) {
|
|
return(1);
|
|
} else {
|
|
return(0);
|
|
}
|
|
|
|
} /* end of stopping_criterion */
|
|
|
|
|
|
/**
|
|
@brief Random number generator.
|
|
|
|
@return a double precision value between 0.0 and 1.0.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static double
|
|
random_generator(DdManager * dd)
|
|
{
|
|
return((double)(Cudd_Random(dd) / 2147483561.0));
|
|
|
|
} /* end of random_generator */
|
|
|
|
|
|
/**
|
|
@brief Exchanges two variables, x and y.
|
|
|
|
@details This is the same funcion as ddSwapping except for the
|
|
comparison expression. Use probability function, exp(-size_change/temp).
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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 = (int) (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;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(1);
|
|
|
|
ddExchangeOutOfMem:
|
|
while (moves != NULL) {
|
|
move = moves->next;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(0);
|
|
|
|
} /* end of ddExchange */
|
|
|
|
|
|
/**
|
|
@brief Moves a variable to a specified position.
|
|
|
|
@details If x==x_low, it executes jumping_down. If x==x_high, it
|
|
executes jumping_up. This funcion is similar to ddSiftingAux.
|
|
|
|
@return 1 in case of success; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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 = (int) (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;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(1);
|
|
|
|
ddJumpingAuxOutOfMem:
|
|
while (moves != NULL) {
|
|
move = moves->next;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(0);
|
|
|
|
} /* end of ddJumpingAux */
|
|
|
|
|
|
/**
|
|
@brief This function is for jumping up.
|
|
|
|
@details This is a simplified version of ddSiftingUp. It does not
|
|
use lower bounding.
|
|
|
|
@return the set of moves in case of success; NULL if memory is full.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of ddJumpingUp */
|
|
|
|
|
|
/**
|
|
@brief This function is for jumping down.
|
|
|
|
@details This is a simplified version of ddSiftingDown. It does not
|
|
use lower bounding.
|
|
|
|
@return the set of moves in case of success; NULL if memory is full.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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;
|
|
cuddDeallocMove(table, moves);
|
|
moves = move;
|
|
}
|
|
return(NULL);
|
|
|
|
} /* end of ddJumpingDown */
|
|
|
|
|
|
/**
|
|
@brief Returns the %DD to the best position encountered during
|
|
sifting if there was improvement.
|
|
|
|
@details Otherwise, "tosses a coin" to decide whether to keep
|
|
the current configuration or return the %DD to the original
|
|
one.
|
|
|
|
@return 1 in case of success; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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(table);
|
|
#ifdef DD_STATS
|
|
table->tosses++;
|
|
#endif
|
|
threshold = exp(-((double)(table->keys - table->isolated -
|
|
(unsigned int) size))/temp);
|
|
if (coin < threshold) {
|
|
#ifdef DD_STATS
|
|
table->acceptances++;
|
|
#endif
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
/* Either there was improvement, or we have decided not to
|
|
** accept the uphill move. Go to best position.
|
|
*/
|
|
res = (int) (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 */
|
|
|
|
|
|
/**
|
|
@brief Copies the current variable order to array.
|
|
|
|
@details At the same time inverts the permutation.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
static void
|
|
copyOrder(
|
|
DdManager * table,
|
|
int * array,
|
|
int lower,
|
|
int upper)
|
|
{
|
|
int i;
|
|
int nvars;
|
|
|
|
nvars = upper - lower + 1;
|
|
for (i = 0; i < nvars; i++) {
|
|
array[i] = table->invperm[i+lower];
|
|
}
|
|
|
|
} /* end of copyOrder */
|
|
|
|
|
|
/**
|
|
@brief Restores the variable order in array by a series of sifts up.
|
|
|
|
@return 1 in case of success; 0 otherwise.
|
|
|
|
@sideeffect None
|
|
|
|
*/
|
|
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 */
|
|
|