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.
		
		
		
		
		
			
		
			
				
					
					
						
							1020 lines
						
					
					
						
							28 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1020 lines
						
					
					
						
							28 KiB
						
					
					
				| /**CFile*********************************************************************** | |
|  | |
|   FileName    [cuddExact.c] | |
|  | |
|   PackageName [cudd] | |
|  | |
|   Synopsis    [Functions for exact variable reordering.] | |
|  | |
|   Description [External procedures included in this file: | |
| 		<ul> | |
| 		</ul> | |
| 	Internal procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddExact() | |
| 		</ul> | |
| 	Static procedures included in this module: | |
| 		<ul> | |
| 		<li> getMaxBinomial() | |
| 		<li> gcd() | |
| 		<li> getMatrix() | |
| 		<li> freeMatrix() | |
| 		<li> getLevelKeys() | |
| 		<li> ddShuffle() | |
| 		<li> ddSiftUp() | |
| 		<li> updateUB() | |
| 		<li> ddCountRoots() | |
| 		<li> ddClearGlobal() | |
| 		<li> computeLB() | |
| 		<li> updateEntry() | |
| 		<li> pushDown() | |
| 		<li> initSymmInfo() | |
| 		</ul>] | |
|  | |
|   Author      [Cheng Hua, Fabio Somenzi] | |
|  | |
|   Copyright   [Copyright (c) 1995-2012, 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.] | |
|  | |
| ******************************************************************************/ | |
| 
 | |
| #include "util.h" | |
| #include "cuddInt.h" | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Constant declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifndef lint | |
| static char rcsid[] DD_UNUSED = "$Id: cuddExact.c,v 1.30 2012/02/05 01:07:18 fabio Exp $"; | |
| #endif | |
|  | |
| #ifdef DD_STATS | |
| static int ddTotalShuffles; | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /**AutomaticStart*************************************************************/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static int getMaxBinomial (int n); | |
| static DdHalfWord ** getMatrix (int rows, int cols); | |
| static void freeMatrix (DdHalfWord **matrix); | |
| static int getLevelKeys (DdManager *table, int l); | |
| static int ddShuffle (DdManager *table, DdHalfWord *permutation, int lower, int upper); | |
| static int ddSiftUp (DdManager *table, int x, int xLow); | |
| static int updateUB (DdManager *table, int oldBound, DdHalfWord *bestOrder, int lower, int upper); | |
| static int ddCountRoots (DdManager *table, int lower, int upper); | |
| static void ddClearGlobal (DdManager *table, int lower, int maxlevel); | |
| static int computeLB (DdManager *table, DdHalfWord *order, int roots, int cost, int lower, int upper, int level); | |
| static int updateEntry (DdManager *table, DdHalfWord *order, int level, int cost, DdHalfWord **orders, int *costs, int subsets, char *mask, int lower, int upper); | |
| static void pushDown (DdHalfWord *order, int j, int level); | |
| static DdHalfWord * initSymmInfo (DdManager *table, int lower, int upper); | |
| static int checkSymmInfo (DdManager *table, DdHalfWord *symmInfo, int index, int level); | |
| 
 | |
| /**AutomaticEnd***************************************************************/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Exact variable ordering algorithm.] | |
|  | |
|   Description [Exact variable ordering algorithm. Finds an optimum | |
|   order for the variables between lower and upper.  Returns 1 if | |
|   successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddExact( | |
|   DdManager * table, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int k, i, j; | |
|     int maxBinomial, oldSubsets, newSubsets; | |
|     int subsetCost; | |
|     int size;			/* number of variables to be reordered */ | |
|     int unused, nvars, level, result; | |
|     int upperBound, lowerBound, cost; | |
|     int roots; | |
|     char *mask = NULL; | |
|     DdHalfWord  *symmInfo = NULL; | |
|     DdHalfWord **newOrder = NULL; | |
|     DdHalfWord **oldOrder = NULL; | |
|     int *newCost = NULL; | |
|     int *oldCost = NULL; | |
|     DdHalfWord **tmpOrder; | |
|     int *tmpCost; | |
|     DdHalfWord *bestOrder = NULL; | |
|     DdHalfWord *order; | |
| #ifdef DD_STATS | |
|     int  ddTotalSubsets; | |
| #endif | |
|  | |
|     /* Restrict the range to be reordered by excluding unused variables | |
|     ** at the two ends. */ | |
|     while (table->subtables[lower].keys == 1 && | |
| 	   table->vars[table->invperm[lower]]->ref == 1 && | |
| 	   lower < upper) | |
| 	lower++; | |
|     while (table->subtables[upper].keys == 1 && | |
| 	   table->vars[table->invperm[upper]]->ref == 1 && | |
| 	   lower < upper) | |
| 	upper--; | |
|     if (lower == upper) return(1); /* trivial problem */ | |
| 
 | |
|     /* Apply symmetric sifting to get a good upper bound and to extract | |
|     ** symmetry information. */ | |
|     result = cuddSymmSiftingConv(table,lower,upper); | |
|     if (result == 0) goto cuddExactOutOfMem; | |
| 
 | |
| #ifdef DD_STATS | |
|     (void) fprintf(table->out,"\n"); | |
|     ddTotalShuffles = 0; | |
|     ddTotalSubsets = 0; | |
| #endif | |
|  | |
|     /* Initialization. */ | |
|     nvars = table->size; | |
|     size = upper - lower + 1; | |
|     /* Count unused variable among those to be reordered.  This is only | |
|     ** used to compute maxBinomial. */ | |
|     unused = 0; | |
|     for (i = lower + 1; i < upper; i++) { | |
| 	if (table->subtables[i].keys == 1 && | |
| 	    table->vars[table->invperm[i]]->ref == 1) | |
| 	    unused++; | |
|     } | |
| 
 | |
|     /* Find the maximum number of subsets we may have to store. */ | |
|     maxBinomial = getMaxBinomial(size - unused); | |
|     if (maxBinomial == -1) goto cuddExactOutOfMem; | |
| 
 | |
|     newOrder = getMatrix(maxBinomial, size); | |
|     if (newOrder == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     newCost = ALLOC(int, maxBinomial); | |
|     if (newCost == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     oldOrder = getMatrix(maxBinomial, size); | |
|     if (oldOrder == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     oldCost = ALLOC(int, maxBinomial); | |
|     if (oldCost == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     bestOrder = ALLOC(DdHalfWord, size); | |
|     if (bestOrder == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     mask = ALLOC(char, nvars); | |
|     if (mask == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     symmInfo = initSymmInfo(table, lower, upper); | |
|     if (symmInfo == NULL) goto cuddExactOutOfMem; | |
| 
 | |
|     roots = ddCountRoots(table, lower, upper); | |
| 
 | |
|     /* Initialize the old order matrix for the empty subset and the best | |
|     ** order to the current order. The cost for the empty subset includes | |
|     ** the cost of the levels between upper and the constants. These levels | |
|     ** are not going to change. Hence, we count them only once. | |
|     */ | |
|     oldSubsets = 1; | |
|     for (i = 0; i < size; i++) { | |
| 	oldOrder[0][i] = bestOrder[i] = (DdHalfWord) table->invperm[i+lower]; | |
|     } | |
|     subsetCost = table->constants.keys; | |
|     for (i = upper + 1; i < nvars; i++) | |
| 	subsetCost += getLevelKeys(table,i); | |
|     oldCost[0] = subsetCost; | |
|     /* The upper bound is initialized to the current size of the BDDs. */ | |
|     upperBound = table->keys - table->isolated; | |
| 
 | |
|     /* Now consider subsets of increasing size. */ | |
|     for (k = 1; k <= size; k++) { | |
| #ifdef DD_STATS | |
| 	(void) fprintf(table->out,"Processing subsets of size %d\n", k); | |
| 	fflush(table->out); | |
| #endif | |
| 	newSubsets = 0; | |
| 	level = size - k;		/* offset of first bottom variable */ | |
| 
 | |
| 	for (i = 0; i < oldSubsets; i++) { /* for each subset of size k-1 */ | |
| 	    order = oldOrder[i]; | |
| 	    cost = oldCost[i]; | |
| 	    lowerBound = computeLB(table, order, roots, cost, lower, upper, | |
| 				   level); | |
| 	    if (lowerBound >= upperBound) | |
| 		continue; | |
| 	    /* Impose new order. */ | |
| 	    result = ddShuffle(table, order, lower, upper); | |
| 	    if (result == 0) goto cuddExactOutOfMem; | |
| 	    upperBound = updateUB(table,upperBound,bestOrder,lower,upper); | |
| 	    /* For each top bottom variable. */ | |
| 	    for (j = level; j >= 0; j--) { | |
| 		/* Skip unused variables. */ | |
| 		if (table->subtables[j+lower-1].keys == 1 && | |
| 		    table->vars[table->invperm[j+lower-1]]->ref == 1) continue; | |
| 		/* Find cost under this order. */ | |
| 		subsetCost = cost + getLevelKeys(table, lower + level); | |
| 		newSubsets = updateEntry(table, order, level, subsetCost, | |
| 					 newOrder, newCost, newSubsets, mask, | |
| 					 lower, upper); | |
| 		if (j == 0) | |
| 		    break; | |
| 		if (checkSymmInfo(table, symmInfo, order[j-1], level) == 0) | |
| 		    continue; | |
| 		pushDown(order,j-1,level); | |
| 		/* Impose new order. */ | |
| 		result = ddShuffle(table, order, lower, upper); | |
| 		if (result == 0) goto cuddExactOutOfMem; | |
| 		upperBound = updateUB(table,upperBound,bestOrder,lower,upper); | |
| 	    } /* for each bottom variable */ | |
| 	} /* for each subset of size k */ | |
| 
 | |
| 	/* New orders become old orders in preparation for next iteration. */ | |
| 	tmpOrder = oldOrder; tmpCost = oldCost; | |
| 	oldOrder = newOrder; oldCost = newCost; | |
| 	newOrder = tmpOrder; newCost = tmpCost; | |
| #ifdef DD_STATS | |
| 	ddTotalSubsets += newSubsets; | |
| #endif | |
| 	oldSubsets = newSubsets; | |
|     } | |
|     result = ddShuffle(table, bestOrder, lower, upper); | |
|     if (result == 0) goto cuddExactOutOfMem; | |
| #ifdef DD_STATS | |
| #ifdef DD_VERBOSE | |
|     (void) fprintf(table->out,"\n"); | |
| #endif | |
|     (void) fprintf(table->out,"#:S_EXACT   %8d: total subsets\n", | |
| 		   ddTotalSubsets); | |
|     (void) fprintf(table->out,"#:H_EXACT   %8d: total shuffles", | |
| 		   ddTotalShuffles); | |
| #endif | |
|  | |
|     freeMatrix(newOrder); | |
|     freeMatrix(oldOrder); | |
|     FREE(bestOrder); | |
|     FREE(oldCost); | |
|     FREE(newCost); | |
|     FREE(symmInfo); | |
|     FREE(mask); | |
|     return(1); | |
| 
 | |
| cuddExactOutOfMem: | |
| 
 | |
|     if (newOrder != NULL) freeMatrix(newOrder); | |
|     if (oldOrder != NULL) freeMatrix(oldOrder); | |
|     if (bestOrder != NULL) FREE(bestOrder); | |
|     if (oldCost != NULL) FREE(oldCost); | |
|     if (newCost != NULL) FREE(newCost); | |
|     if (symmInfo != NULL) FREE(symmInfo); | |
|     if (mask != NULL) FREE(mask); | |
|     table->errorCode = CUDD_MEMORY_OUT; | |
|     return(0); | |
| 
 | |
| } /* end of cuddExact */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Returns the maximum value of (n choose k) for a given n.] | |
|  | |
|   Description [Computes the maximum value of (n choose k) for a given | |
|   n.  The maximum value occurs for k = n/2 when n is even, or k = | |
|   (n-1)/2 when n is odd.  The algorithm used in this procedure avoids | |
|   intermediate overflow problems.  It is based on the identity | |
|   <pre> | |
|     binomial(n,k) = n/k * binomial(n-1,k-1). | |
|   </pre> | |
|   Returns the computed value if successful; -1 if out of range.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| getMaxBinomial( | |
|   int n) | |
| { | |
|     double i, j, result; | |
| 
 | |
|     if (n < 0 || n > 33) return(-1); /* error */ | |
|     if (n < 2) return(1); | |
| 
 | |
|     for (result = (double)((n+3)/2), i = result+1, j=2; i <= n; i++, j++) { | |
| 	result *= i; | |
| 	result /= j; | |
|     } | |
| 
 | |
|     return((int)result); | |
| 
 | |
| } /* end of getMaxBinomial */ | |
| 
 | |
| 
 | |
| #if 0 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Returns the gcd of two integers.] | |
|  | |
|   Description [Returns the gcd of two integers. Uses the binary GCD | |
|   algorithm described in Cormen, Leiserson, and Rivest.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| gcd( | |
|   int  x, | |
|   int  y) | |
| { | |
|     int a; | |
|     int b; | |
|     int lsbMask; | |
|  | |
|     /* GCD(n,0) = n. */ | |
|     if (x == 0) return(y); | |
|     if (y == 0) return(x); | |
|  | |
|     a = x; b = y; lsbMask = 1; | |
|  | |
|     /* Here both a and b are != 0. The iteration maintains this invariant. | |
|     ** Hence, we only need to check for when they become equal. | |
|     */ | |
|     while (a != b) { | |
| 	if (a & lsbMask) { | |
| 	    if (b & lsbMask) {	/* both odd */ | |
| 		if (a < b) { | |
| 		    b = (b - a) >> 1; | |
| 		} else { | |
| 		    a = (a - b) >> 1; | |
| 		} | |
| 	    } else {		/* a odd, b even */ | |
| 		b >>= 1; | |
| 	    } | |
| 	} else { | |
| 	    if (b & lsbMask) {	/* a even, b odd */ | |
| 		a >>= 1; | |
| 	    } else {		/* both even */ | |
| 		lsbMask <<= 1; | |
| 	    } | |
| 	} | |
|     } | |
|  | |
|     return(a); | |
|  | |
| } /* end of gcd */ | |
| #endif | |
|  | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Allocates a two-dimensional matrix of ints.] | |
|  | |
|   Description [Allocates a two-dimensional matrix of ints. | |
|   Returns the pointer to the matrix if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [freeMatrix] | |
|  | |
| ******************************************************************************/ | |
| static DdHalfWord ** | |
| getMatrix( | |
|   int  rows /* number of rows */, | |
|   int  cols /* number of columns */) | |
| { | |
|     DdHalfWord **matrix; | |
|     int i; | |
| 
 | |
|     if (cols*rows == 0) return(NULL); | |
|     matrix = ALLOC(DdHalfWord *, rows); | |
|     if (matrix == NULL) return(NULL); | |
|     matrix[0] = ALLOC(DdHalfWord, cols*rows); | |
|     if (matrix[0] == NULL) { | |
| 	FREE(matrix); | |
| 	return(NULL); | |
|     } | |
|     for (i = 1; i < rows; i++) { | |
| 	matrix[i] = matrix[i-1] + cols; | |
|     } | |
|     return(matrix); | |
| 
 | |
| } /* end of getMatrix */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Frees a two-dimensional matrix allocated by getMatrix.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [getMatrix] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| freeMatrix( | |
|   DdHalfWord ** matrix) | |
| { | |
|     FREE(matrix[0]); | |
|     FREE(matrix); | |
|     return; | |
| 
 | |
| } /* end of freeMatrix */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Returns the number of nodes at one level of a unique table.] | |
|  | |
|   Description [Returns the number of nodes at one level of a unique table. | |
|   The projection function, if isolated, is not counted.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| getLevelKeys( | |
|   DdManager * table, | |
|   int  l) | |
| { | |
|     int isolated; | |
|     int x;        /* x is an index */ | |
| 
 | |
|     x = table->invperm[l]; | |
|     isolated = table->vars[x]->ref == 1; | |
| 
 | |
|     return(table->subtables[l].keys - isolated); | |
| 
 | |
| } /* end of getLevelKeys */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Reorders variables according to a given permutation.] | |
|  | |
|   Description [Reorders variables according to a given permutation. | |
|   The i-th permutation array contains the index of the variable that | |
|   should be brought to the i-th level. ddShuffle assumes that no | |
|   dead nodes are present and that the interaction matrix is properly | |
|   initialized.  The reordering is achieved by a series of upward sifts. | |
|   Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddShuffle( | |
|   DdManager * table, | |
|   DdHalfWord * permutation, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     DdHalfWord	index; | |
|     int		level; | |
|     int		position; | |
| #if 0 | |
|     int		numvars; | |
| #endif | |
|     int		result; | |
| #ifdef DD_STATS | |
|     unsigned long localTime; | |
|     int		initialSize; | |
| #ifdef DD_VERBOSE | |
|     int		finalSize; | |
| #endif | |
|     int		previousSize; | |
| #endif | |
|  | |
| #ifdef DD_STATS | |
|     localTime = util_cpu_time(); | |
|     initialSize = table->keys - table->isolated; | |
| #endif | |
|  | |
| #if 0 | |
|     numvars = table->size; | |
|  | |
|     (void) fprintf(table->out,"%d:", ddTotalShuffles); | |
|     for (level = 0; level < numvars; level++) { | |
| 	(void) fprintf(table->out," %d", table->invperm[level]); | |
|     } | |
|     (void) fprintf(table->out,"\n"); | |
| #endif | |
|  | |
|     for (level = 0; level <= upper - lower; level++) { | |
| 	index = permutation[level]; | |
| 	position = table->perm[index]; | |
| #ifdef DD_STATS | |
| 	previousSize = table->keys - table->isolated; | |
| #endif | |
| 	result = ddSiftUp(table,position,level+lower); | |
| 	if (!result) return(0); | |
|     } | |
| 
 | |
| #ifdef DD_STATS | |
|     ddTotalShuffles++; | |
| #ifdef DD_VERBOSE | |
|     finalSize = table->keys - table->isolated; | |
|     if (finalSize < initialSize) { | |
| 	(void) fprintf(table->out,"-"); | |
|     } else if (finalSize > initialSize) { | |
| 	(void) fprintf(table->out,"+"); | |
|     } else { | |
| 	(void) fprintf(table->out,"="); | |
|     } | |
|     if ((ddTotalShuffles & 63) == 0) (void) fprintf(table->out,"\n"); | |
|     fflush(table->out); | |
| #endif | |
| #endif | |
|  | |
|     return(1); | |
| 
 | |
| } /* end of ddShuffle */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Moves one variable up.] | |
|  | |
|   Description [Takes a variable from position x and sifts it up to | |
|   position xLow;  xLow should be less than or equal to x. | |
|   Returns 1 if successful; 0 otherwise] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddSiftUp( | |
|   DdManager * table, | |
|   int  x, | |
|   int  xLow) | |
| { | |
|     int        y; | |
|     int        size; | |
| 
 | |
|     y = cuddNextLow(table,x); | |
|     while (y >= xLow) { | |
| 	size = cuddSwapInPlace(table,y,x); | |
| 	if (size == 0) { | |
| 	    return(0); | |
| 	} | |
| 	x = y; | |
| 	y = cuddNextLow(table,x); | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of ddSiftUp */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Updates the upper bound and saves the best order seen so far.] | |
|  | |
|   Description [Updates the upper bound and saves the best order seen so far. | |
|   Returns the current value of the upper bound.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| updateUB( | |
|   DdManager * table, | |
|   int  oldBound, | |
|   DdHalfWord * bestOrder, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int i; | |
|     int newBound = table->keys - table->isolated; | |
| 
 | |
|     if (newBound < oldBound) { | |
| #ifdef DD_STATS | |
| 	(void) fprintf(table->out,"New upper bound = %d\n", newBound); | |
| 	fflush(table->out); | |
| #endif | |
| 	for (i = lower; i <= upper; i++) | |
| 	    bestOrder[i-lower] = (DdHalfWord) table->invperm[i]; | |
| 	return(newBound); | |
|     } else { | |
| 	return(oldBound); | |
|     } | |
| 
 | |
| } /* end of updateUB */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of roots.] | |
|  | |
|   Description [Counts the number of roots at the levels between lower and | |
|   upper.  The computation is based on breadth-first search. | |
|   A node is a root if it is not reachable from any previously visited node. | |
|   (All the nodes at level lower are therefore considered roots.) | |
|   The visited flag uses the LSB of the next pointer.  Returns the root | |
|   count. The roots that are constant nodes are always ignored.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [ddClearGlobal] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddCountRoots( | |
|   DdManager * table, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int i,j; | |
|     DdNode *f; | |
|     DdNodePtr *nodelist; | |
|     DdNode *sentinel = &(table->sentinel); | |
|     int slots; | |
|     int roots = 0; | |
|     int maxlevel = lower; | |
| 
 | |
|     for (i = lower; i <= upper; i++) { | |
| 	nodelist = table->subtables[i].nodelist; | |
| 	slots = table->subtables[i].slots; | |
| 	for (j = 0; j < slots; j++) { | |
| 	    f = nodelist[j]; | |
| 	    while (f != sentinel) { | |
| 		/* A node is a root of the DAG if it cannot be | |
| 		** reached by nodes above it. If a node was never | |
| 		** reached during the previous depth-first searches, | |
| 		** then it is a root, and we start a new depth-first | |
| 		** search from it. | |
| 		*/ | |
| 		if (!Cudd_IsComplement(f->next)) { | |
| 		    if (f != table->vars[f->index]) { | |
| 			roots++; | |
| 		    } | |
| 		} | |
| 		if (!Cudd_IsConstant(cuddT(f))) { | |
| 		    cuddT(f)->next = Cudd_Complement(cuddT(f)->next); | |
| 		    if (table->perm[cuddT(f)->index] > maxlevel) | |
| 			maxlevel = table->perm[cuddT(f)->index]; | |
| 		} | |
| 		if (!Cudd_IsConstant(cuddE(f))) { | |
| 		    Cudd_Regular(cuddE(f))->next = | |
| 			Cudd_Complement(Cudd_Regular(cuddE(f))->next); | |
| 		    if (table->perm[Cudd_Regular(cuddE(f))->index] > maxlevel) | |
| 			maxlevel = table->perm[Cudd_Regular(cuddE(f))->index]; | |
| 		} | |
| 		f = Cudd_Regular(f->next); | |
| 	    } | |
| 	} | |
|     } | |
|     ddClearGlobal(table, lower, maxlevel); | |
| 
 | |
|     return(roots); | |
| 
 | |
| } /* end of ddCountRoots */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Scans the DD and clears the LSB of the next pointers.] | |
|  | |
|   Description [Scans the DD and clears the LSB of the next pointers. | |
|   The LSB of the next pointers are used as markers to tell whether a | |
|   node was reached. Once the roots are counted, these flags are | |
|   reset.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [ddCountRoots] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddClearGlobal( | |
|   DdManager * table, | |
|   int  lower, | |
|   int  maxlevel) | |
| { | |
|     int i,j; | |
|     DdNode *f; | |
|     DdNodePtr *nodelist; | |
|     DdNode *sentinel = &(table->sentinel); | |
|     int slots; | |
| 
 | |
|     for (i = lower; i <= maxlevel; i++) { | |
| 	nodelist = table->subtables[i].nodelist; | |
| 	slots = table->subtables[i].slots; | |
| 	for (j = 0; j < slots; j++) { | |
| 	    f = nodelist[j]; | |
| 	    while (f != sentinel) { | |
| 		f->next = Cudd_Regular(f->next); | |
| 		f = f->next; | |
| 	    } | |
| 	} | |
|     } | |
| 
 | |
| } /* end of ddClearGlobal */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Computes a lower bound on the size of a BDD.] | |
|  | |
|   Description [Computes a lower bound on the size of a BDD from the | |
|   following factors: | |
|   <ul> | |
|   <li> size of the lower part of it; | |
|   <li> size of the part of the upper part not subjected to reordering; | |
|   <li> number of roots in the part of the BDD subjected to reordering; | |
|   <li> variable in the support of the roots in the upper part of the | |
|        BDD subjected to reordering. | |
|   <ul/>] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| computeLB( | |
|   DdManager * table		/* manager */, | |
|   DdHalfWord * order		/* optimal order for the subset */, | |
|   int  roots			/* roots between lower and upper */, | |
|   int  cost			/* minimum cost for the subset */, | |
|   int  lower			/* lower level to be reordered */, | |
|   int  upper			/* upper level to be reordered */, | |
|   int  level			/* offset for the current top bottom var */ | |
|   ) | |
| { | |
|     int i; | |
|     int lb = cost; | |
|     int lb1 = 0; | |
|     int lb2; | |
|     int support; | |
|     DdHalfWord ref; | |
| 
 | |
|     /* The levels not involved in reordering are not going to change. | |
|     ** Add their sizes to the lower bound. | |
|     */ | |
|     for (i = 0; i < lower; i++) { | |
| 	lb += getLevelKeys(table,i); | |
|     } | |
|     /* If a variable is in the support, then there is going | |
|     ** to be at least one node labeled by that variable. | |
|     */ | |
|     for (i = lower; i <= lower+level; i++) { | |
| 	support = table->subtables[i].keys > 1 || | |
| 	    table->vars[order[i-lower]]->ref > 1; | |
| 	lb1 += support; | |
|     } | |
| 
 | |
|     /* Estimate the number of nodes required to connect the roots to | |
|     ** the nodes in the bottom part. */ | |
|     if (lower+level+1 < table->size) { | |
| 	if (lower+level < upper) | |
| 	    ref = table->vars[order[level+1]]->ref; | |
| 	else | |
| 	    ref = table->vars[table->invperm[upper+1]]->ref; | |
| 	lb2 = table->subtables[lower+level+1].keys - | |
| 	    (ref > (DdHalfWord) 1) - roots; | |
|     } else { | |
| 	lb2 = 0; | |
|     } | |
| 
 | |
|     lb += lb1 > lb2 ? lb1 : lb2; | |
| 
 | |
|     return(lb); | |
| 
 | |
| } /* end of computeLB */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Updates entry for a subset.] | |
|  | |
|   Description [Updates entry for a subset. Finds the subset, if it exists. | |
|   If the new order for the subset has lower cost, or if the subset did not | |
|   exist, it stores the new order and cost. Returns the number of subsets | |
|   currently in the table.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| updateEntry( | |
|   DdManager * table, | |
|   DdHalfWord * order, | |
|   int  level, | |
|   int  cost, | |
|   DdHalfWord ** orders, | |
|   int * costs, | |
|   int  subsets, | |
|   char * mask, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int i, j; | |
|     int size = upper - lower + 1; | |
| 
 | |
|     /* Build a mask that says what variables are in this subset. */ | |
|     for (i = lower; i <= upper; i++) | |
| 	mask[table->invperm[i]] = 0; | |
|     for (i = level; i < size; i++) | |
| 	mask[order[i]] = 1; | |
| 
 | |
|     /* Check each subset until a match is found or all subsets are examined. */ | |
|     for (i = 0; i < subsets; i++) { | |
| 	DdHalfWord *subset = orders[i]; | |
| 	for (j = level; j < size; j++) { | |
| 	    if (mask[subset[j]] == 0) | |
| 		break; | |
| 	} | |
| 	if (j == size)		/* no mismatches: success */ | |
| 	    break; | |
|     } | |
|     if (i == subsets || cost < costs[i]) {		/* add or replace */ | |
| 	for (j = 0; j < size; j++) | |
| 	    orders[i][j] = order[j]; | |
| 	costs[i] = cost; | |
| 	subsets += (i == subsets); | |
|     } | |
|     return(subsets); | |
| 
 | |
| } /* end of updateEntry */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Pushes a variable in the order down to position "level."] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| pushDown( | |
|   DdHalfWord * order, | |
|   int  j, | |
|   int  level) | |
| { | |
|     int i; | |
|     DdHalfWord tmp; | |
| 
 | |
|     tmp = order[j]; | |
|     for (i = j; i < level; i++) { | |
| 	order[i] = order[i+1]; | |
|     } | |
|     order[level] = tmp; | |
|     return; | |
| 
 | |
| } /* end of pushDown */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Gathers symmetry information.] | |
|  | |
|   Description [Translates the symmetry information stored in the next | |
|   field of each subtable from level to indices. This procedure is called | |
|   immediately after symmetric sifting, so that the next fields are correct. | |
|   By translating this informaton in terms of indices, we make it independent | |
|   of subsequent reorderings. The format used is that of the next fields: | |
|   a circular list where each variable points to the next variable in the | |
|   same symmetry group. Only the entries between lower and upper are | |
|   considered.  The procedure returns a pointer to an array | |
|   holding the symmetry information if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [checkSymmInfo] | |
|  | |
| ******************************************************************************/ | |
| static DdHalfWord * | |
| initSymmInfo( | |
|   DdManager * table, | |
|   int  lower, | |
|   int  upper) | |
| { | |
|     int level, index, next, nextindex; | |
|     DdHalfWord *symmInfo; | |
| 
 | |
|     symmInfo =  ALLOC(DdHalfWord, table->size); | |
|     if (symmInfo == NULL) return(NULL); | |
| 
 | |
|     for (level = lower; level <= upper; level++) { | |
| 	index = table->invperm[level]; | |
| 	next =  table->subtables[level].next; | |
| 	nextindex = table->invperm[next]; | |
| 	symmInfo[index] = nextindex; | |
|     } | |
|     return(symmInfo); | |
| 
 | |
| } /* end of initSymmInfo */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Check symmetry condition.] | |
|  | |
|   Description [Returns 1 if a variable is the one with the highest index | |
|   among those belonging to a symmetry group that are in the top part of | |
|   the BDD.  The top part is given by level.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [initSymmInfo] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| checkSymmInfo( | |
|   DdManager * table, | |
|   DdHalfWord * symmInfo, | |
|   int  index, | |
|   int  level) | |
| { | |
|     int i; | |
| 
 | |
|     i = symmInfo[index]; | |
|     while (i != index) { | |
| 	if (index < i && table->perm[i] <= level) | |
| 	    return(0); | |
| 	i = symmInfo[i]; | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of checkSymmInfo */
 |