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.
		
		
		
		
		
			
		
			
				
					
					
						
							4032 lines
						
					
					
						
							107 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							4032 lines
						
					
					
						
							107 KiB
						
					
					
				| /**CFile*********************************************************************** | |
|  | |
|   FileName    [cuddUtil.c] | |
|  | |
|   PackageName [cudd] | |
|  | |
|   Synopsis    [Utility functions.] | |
|  | |
|   Description [External procedures included in this module: | |
| 		<ul> | |
| 		<li> Cudd_PrintMinterm() | |
| 		<li> Cudd_bddPrintCover() | |
| 		<li> Cudd_PrintDebug() | |
| 		<li> Cudd_DagSize() | |
| 		<li> Cudd_EstimateCofactor() | |
| 		<li> Cudd_EstimateCofactorSimple() | |
| 		<li> Cudd_SharingSize() | |
| 		<li> Cudd_CountMinterm() | |
| 		<li> Cudd_EpdCountMinterm() | |
| 		<li> Cudd_CountPath() | |
| 		<li> Cudd_CountPathsToNonZero() | |
|                 <li> Cudd_SupportIndices() | |
| 		<li> Cudd_Support() | |
| 		<li> Cudd_SupportIndex() | |
| 		<li> Cudd_SupportSize() | |
| 		<li> Cudd_VectorSupportIndices() | |
| 		<li> Cudd_VectorSupport() | |
| 		<li> Cudd_VectorSupportIndex() | |
| 		<li> Cudd_VectorSupportSize() | |
| 		<li> Cudd_ClassifySupport() | |
| 		<li> Cudd_CountLeaves() | |
| 		<li> Cudd_bddPickOneCube() | |
| 		<li> Cudd_bddPickOneMinterm() | |
| 		<li> Cudd_bddPickArbitraryMinterms() | |
| 		<li> Cudd_SubsetWithMaskVars() | |
| 		<li> Cudd_FirstCube() | |
| 		<li> Cudd_NextCube() | |
| 		<li> Cudd_bddComputeCube() | |
| 		<li> Cudd_addComputeCube() | |
| 		<li> Cudd_FirstNode() | |
| 		<li> Cudd_NextNode() | |
| 		<li> Cudd_GenFree() | |
| 		<li> Cudd_IsGenEmpty() | |
| 		<li> Cudd_IndicesToCube() | |
| 		<li> Cudd_PrintVersion() | |
| 		<li> Cudd_AverageDistance() | |
| 		<li> Cudd_Random() | |
| 		<li> Cudd_Srandom() | |
| 		<li> Cudd_Density() | |
| 		</ul> | |
| 	Internal procedures included in this module: | |
| 		<ul> | |
| 		<li> cuddP() | |
| 		<li> cuddStCountfree() | |
| 		<li> cuddCollectNodes() | |
| 		<li> cuddNodeArray() | |
| 		</ul> | |
| 	Static procedures included in this module: | |
| 		<ul> | |
| 		<li> dp2() | |
| 		<li> ddPrintMintermAux() | |
| 		<li> ddDagInt() | |
| 		<li> ddCountMintermAux() | |
| 		<li> ddEpdCountMintermAux() | |
| 		<li> ddCountPathAux() | |
| 		<li> ddSupportStep() | |
| 		<li> ddClearFlag() | |
| 		<li> ddLeavesInt() | |
| 		<li> ddPickArbitraryMinterms() | |
| 		<li> ddPickRepresentativeCube() | |
| 		<li> ddEpdFree() | |
|                 <li> ddFindSupport() | |
|                 <li> ddClearVars() | |
|                 <li> indexCompare() | |
| 		</ul>] | |
|  | |
|   Author      [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                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /* Random generator constants. */ | |
| #define MODULUS1 2147483563 | |
| #define LEQA1 40014 | |
| #define LEQQ1 53668 | |
| #define LEQR1 12211 | |
| #define MODULUS2 2147483399 | |
| #define LEQA2 40692 | |
| #define LEQQ2 52774 | |
| #define LEQR2 3791 | |
| #define STAB_SIZE 64 | |
| #define STAB_DIV (1 + (MODULUS1 - 1) / STAB_SIZE) | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Stucture declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Type declarations                                                         */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Variable declarations                                                     */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #ifndef lint | |
| static char rcsid[] DD_UNUSED = "$Id: cuddUtil.c,v 1.83 2012/02/05 01:07:19 fabio Exp $"; | |
| #endif | |
|  | |
| static	DdNode	*background, *zero; | |
| 
 | |
| static	long cuddRand = 0; | |
| static	long cuddRand2; | |
| static	long shuffleSelect; | |
| static	long shuffleTable[STAB_SIZE]; | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Macro declarations                                                        */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| #define bang(f)	((Cudd_IsComplement(f)) ? '!' : ' ') | |
|  | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
|  | |
| /**AutomaticStart*************************************************************/ | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Static function prototypes                                                */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| static int dp2 (DdManager *dd, DdNode *f, st_table *t); | |
| static void ddPrintMintermAux (DdManager *dd, DdNode *node, int *list); | |
| static int ddDagInt (DdNode *n); | |
| static int cuddNodeArrayRecur (DdNode *f, DdNodePtr *table, int index); | |
| static int cuddEstimateCofactor (DdManager *dd, st_table *table, DdNode * node, int i, int phase, DdNode ** ptr); | |
| static DdNode * cuddUniqueLookup (DdManager * unique, int  index, DdNode * T, DdNode * E); | |
| static int cuddEstimateCofactorSimple (DdNode * node, int i); | |
| static double ddCountMintermAux (DdNode *node, double max, DdHashTable *table); | |
| static int ddEpdCountMintermAux (DdNode *node, EpDouble *max, EpDouble *epd, st_table *table); | |
| static double ddCountPathAux (DdNode *node, st_table *table); | |
| static double ddCountPathsToNonZero (DdNode * N, st_table * table); | |
| static void ddSupportStep (DdNode *f, int *support); | |
| static void ddClearFlag (DdNode *f); | |
| static int ddLeavesInt (DdNode *n); | |
| static int ddPickArbitraryMinterms (DdManager *dd, DdNode *node, int nvars, int nminterms, char **string); | |
| static int ddPickRepresentativeCube (DdManager *dd, DdNode *node, double *weight, char *string); | |
| static enum st_retval ddEpdFree (char * key, char * value, char * arg); | |
| static void ddFindSupport(DdManager *dd, DdNode *f, int *SP); | |
| static void ddClearVars(DdManager *dd, int SP); | |
| static int indexCompare(const void *a, const void *b); | |
| 
 | |
| /**AutomaticEnd***************************************************************/ | |
| 
 | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
|  | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of exported functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints a disjoint sum of products.] | |
|  | |
|   Description [Prints a disjoint sum of product cover for the function | |
|   rooted at node. Each product corresponds to a path from node to a | |
|   leaf node different from the logical zero, and different from the | |
|   background value. Uses the package default output file.  Returns 1 | |
|   if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintDebug Cudd_bddPrintCover] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_PrintMinterm( | |
|   DdManager * manager, | |
|   DdNode * node) | |
| { | |
|     int		i, *list; | |
| 
 | |
|     background = manager->background; | |
|     zero = Cudd_Not(manager->one); | |
|     list = ALLOC(int,manager->size); | |
|     if (list == NULL) { | |
| 	manager->errorCode = CUDD_MEMORY_OUT; | |
| 	return(0); | |
|     } | |
|     for (i = 0; i < manager->size; i++) list[i] = 2; | |
|     ddPrintMintermAux(manager,node,list); | |
|     FREE(list); | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_PrintMinterm */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints a sum of prime implicants of a BDD.] | |
|  | |
|   Description [Prints a sum of product cover for an incompletely | |
|   specified function given by a lower bound and an upper bound.  Each | |
|   product is a prime implicant obtained by expanding the product | |
|   corresponding to a path from node to the constant one.  Uses the | |
|   package default output file.  Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintMinterm] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_bddPrintCover( | |
|   DdManager *dd, | |
|   DdNode *l, | |
|   DdNode *u) | |
| { | |
|     int *array; | |
|     int q, result; | |
|     DdNode *lb; | |
| #ifdef DD_DEBUG | |
|     DdNode *cover; | |
| #endif | |
|  | |
|     array = ALLOC(int, Cudd_ReadSize(dd)); | |
|     if (array == NULL) return(0); | |
|     lb = l; | |
|     cuddRef(lb); | |
| #ifdef DD_DEBUG | |
|     cover = Cudd_ReadLogicZero(dd); | |
|     cuddRef(cover); | |
| #endif | |
|     while (lb != Cudd_ReadLogicZero(dd)) { | |
| 	DdNode *implicant, *prime, *tmp; | |
| 	int length; | |
| 	implicant = Cudd_LargestCube(dd,lb,&length); | |
| 	if (implicant == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,lb); | |
| 	    FREE(array); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(implicant); | |
| 	prime = Cudd_bddMakePrime(dd,implicant,u); | |
| 	if (prime == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,lb); | |
| 	    Cudd_RecursiveDeref(dd,implicant); | |
| 	    FREE(array); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(prime); | |
| 	Cudd_RecursiveDeref(dd,implicant); | |
| 	tmp = Cudd_bddAnd(dd,lb,Cudd_Not(prime)); | |
| 	if (tmp == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,lb); | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    FREE(array); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(tmp); | |
| 	Cudd_RecursiveDeref(dd,lb); | |
| 	lb = tmp; | |
| 	result = Cudd_BddToCubeArray(dd,prime,array); | |
| 	if (result == 0) { | |
| 	    Cudd_RecursiveDeref(dd,lb); | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    FREE(array); | |
| 	    return(0); | |
| 	} | |
| 	for (q = 0; q < dd->size; q++) { | |
| 	    switch (array[q]) { | |
| 	    case 0: | |
| 		(void) fprintf(dd->out, "0"); | |
| 		break; | |
| 	    case 1: | |
| 		(void) fprintf(dd->out, "1"); | |
| 		break; | |
| 	    case 2: | |
| 		(void) fprintf(dd->out, "-"); | |
| 		break; | |
| 	    default: | |
| 		(void) fprintf(dd->out, "?"); | |
| 	    } | |
| 	} | |
| 	(void) fprintf(dd->out, " 1\n"); | |
| #ifdef DD_DEBUG | |
| 	tmp = Cudd_bddOr(dd,prime,cover); | |
| 	if (tmp == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,cover); | |
| 	    Cudd_RecursiveDeref(dd,lb); | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    FREE(array); | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(tmp); | |
| 	Cudd_RecursiveDeref(dd,cover); | |
| 	cover = tmp; | |
| #endif | |
| 	Cudd_RecursiveDeref(dd,prime); | |
|     } | |
|     (void) fprintf(dd->out, "\n"); | |
|     Cudd_RecursiveDeref(dd,lb); | |
|     FREE(array); | |
| #ifdef DD_DEBUG | |
|     if (!Cudd_bddLeq(dd,cover,u) || !Cudd_bddLeq(dd,l,cover)) { | |
| 	Cudd_RecursiveDeref(dd,cover); | |
| 	return(0); | |
|     } | |
|     Cudd_RecursiveDeref(dd,cover); | |
| #endif | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_bddPrintCover */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints to the standard output a DD and its statistics.] | |
|  | |
|   Description [Prints to the standard output a DD and its statistics. | |
|   The statistics include the number of nodes, the number of leaves, and | |
|   the number of minterms. (The number of minterms is the number of | |
|   assignments to the variables that cause the function to be different | |
|   from the logical zero (for BDDs) and from the background value (for | |
|   ADDs.) The statistics are printed if pr > 0. Specifically: | |
|   <ul> | |
|   <li> pr = 0 : prints nothing | |
|   <li> pr = 1 : prints counts of nodes and minterms | |
|   <li> pr = 2 : prints counts + disjoint sum of product | |
|   <li> pr = 3 : prints counts + list of nodes | |
|   <li> pr > 3 : prints counts + disjoint sum of product + list of nodes | |
|   </ul> | |
|   For the purpose of counting the number of minterms, the function is | |
|   supposed to depend on n variables. Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_DagSize Cudd_CountLeaves Cudd_CountMinterm | |
|   Cudd_PrintMinterm] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_PrintDebug( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   int  n, | |
|   int  pr) | |
| { | |
|     DdNode *azero, *bzero; | |
|     int	   nodes; | |
|     int	   leaves; | |
|     double minterms; | |
|     int    retval = 1; | |
| 
 | |
|     if (f == NULL) { | |
| 	(void) fprintf(dd->out,": is the NULL DD\n"); | |
| 	(void) fflush(dd->out); | |
| 	return(0); | |
|     } | |
|     azero = DD_ZERO(dd); | |
|     bzero = Cudd_Not(DD_ONE(dd)); | |
|     if ((f == azero || f == bzero) && pr > 0){ | |
|        (void) fprintf(dd->out,": is the zero DD\n"); | |
|        (void) fflush(dd->out); | |
|        return(1); | |
|     } | |
|     if (pr > 0) { | |
| 	nodes = Cudd_DagSize(f); | |
| 	if (nodes == CUDD_OUT_OF_MEM) retval = 0; | |
| 	leaves = Cudd_CountLeaves(f); | |
| 	if (leaves == CUDD_OUT_OF_MEM) retval = 0; | |
| 	minterms = Cudd_CountMinterm(dd, f, n); | |
| 	if (minterms == (double)CUDD_OUT_OF_MEM) retval = 0; | |
| 	(void) fprintf(dd->out,": %d nodes %d leaves %g minterms\n", | |
| 		       nodes, leaves, minterms); | |
| 	if (pr > 2) { | |
| 	    if (!cuddP(dd, f)) retval = 0; | |
| 	} | |
| 	if (pr == 2 || pr > 3) { | |
| 	    if (!Cudd_PrintMinterm(dd,f)) retval = 0; | |
| 	    (void) fprintf(dd->out,"\n"); | |
| 	} | |
| 	(void) fflush(dd->out); | |
|     } | |
|     return(retval); | |
| 
 | |
| } /* end of Cudd_PrintDebug */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of nodes in a DD.] | |
|  | |
|   Description [Counts the number of nodes in a DD. Returns the number | |
|   of nodes in the graph rooted at node.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_SharingSize Cudd_PrintDebug] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_DagSize( | |
|   DdNode * node) | |
| { | |
|     int	i; | |
| 
 | |
|     i = ddDagInt(Cudd_Regular(node)); | |
|     ddClearFlag(Cudd_Regular(node)); | |
| 
 | |
|     return(i); | |
| 
 | |
| } /* end of Cudd_DagSize */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Estimates the number of nodes in a cofactor of a DD.] | |
|  | |
|   Description [Estimates the number of nodes in a cofactor of a DD. | |
|   Returns an estimate of the number of nodes in a cofactor of | |
|   the graph rooted at node with respect to the variable whose index is i. | |
|   In case of failure, returns CUDD_OUT_OF_MEM. | |
|   This function uses a refinement of the algorithm of Cabodi et al. | |
|   (ICCAD96). The refinement allows the procedure to account for part | |
|   of the recombination that may occur in the part of the cofactor above | |
|   the cofactoring variable. This procedure does not create any new node. | |
|   It does keep a small table of results; therefore it may run out of memory. | |
|   If this is a concern, one should use Cudd_EstimateCofactorSimple, which | |
|   is faster, does not allocate any memory, but is less accurate.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_DagSize Cudd_EstimateCofactorSimple] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_EstimateCofactor( | |
|   DdManager *dd /* manager */, | |
|   DdNode * f	/* function */, | |
|   int i		/* index of variable */, | |
|   int phase	/* 1: positive; 0: negative */ | |
|   ) | |
| { | |
|     int	val; | |
|     DdNode *ptr; | |
|     st_table *table; | |
| 
 | |
|     table = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (table == NULL) return(CUDD_OUT_OF_MEM); | |
|     val = cuddEstimateCofactor(dd,table,Cudd_Regular(f),i,phase,&ptr); | |
|     ddClearFlag(Cudd_Regular(f)); | |
|     st_free_table(table); | |
| 
 | |
|     return(val); | |
| 
 | |
| } /* end of Cudd_EstimateCofactor */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Estimates the number of nodes in a cofactor of a DD.] | |
|  | |
|   Description [Estimates the number of nodes in a cofactor of a DD. | |
|   Returns an estimate of the number of nodes in the positive cofactor of | |
|   the graph rooted at node with respect to the variable whose index is i. | |
|   This procedure implements with minor changes the algorithm of Cabodi et al. | |
|   (ICCAD96). It does not allocate any memory, it does not change the | |
|   state of the manager, and it is fast. However, it has been observed to | |
|   overestimate the size of the cofactor by as much as a factor of 2.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_DagSize] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_EstimateCofactorSimple( | |
|   DdNode * node, | |
|   int i) | |
| { | |
|     int	val; | |
| 
 | |
|     val = cuddEstimateCofactorSimple(Cudd_Regular(node),i); | |
|     ddClearFlag(Cudd_Regular(node)); | |
| 
 | |
|     return(val); | |
| 
 | |
| } /* end of Cudd_EstimateCofactorSimple */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of nodes in an array of DDs.] | |
|  | |
|   Description [Counts the number of nodes in an array of DDs. Shared | |
|   nodes are counted only once.  Returns the total number of nodes.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_DagSize] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_SharingSize( | |
|   DdNode ** nodeArray, | |
|   int  n) | |
| { | |
|     int	i,j; | |
| 
 | |
|     i = 0; | |
|     for (j = 0; j < n; j++) { | |
| 	i += ddDagInt(Cudd_Regular(nodeArray[j])); | |
|     } | |
|     for (j = 0; j < n; j++) { | |
| 	ddClearFlag(Cudd_Regular(nodeArray[j])); | |
|     } | |
|     return(i); | |
| 
 | |
| } /* end of Cudd_SharingSize */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of minterms of a DD.] | |
|  | |
|   Description [Counts the number of minterms of a DD. The function is | |
|   assumed to depend on nvars variables. The minterm count is | |
|   represented as a double, to allow for a larger number of variables. | |
|   Returns the number of minterms of the function rooted at node if | |
|   successful; (double) CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintDebug Cudd_CountPath] | |
|  | |
| ******************************************************************************/ | |
| double | |
| Cudd_CountMinterm( | |
|   DdManager * manager, | |
|   DdNode * node, | |
|   int  nvars) | |
| { | |
|     double	max; | |
|     DdHashTable	*table; | |
|     double	res; | |
|     CUDD_VALUE_TYPE epsilon; | |
| 
 | |
|     background = manager->background; | |
|     zero = Cudd_Not(manager->one); | |
| 
 | |
|     max = pow(2.0,(double)nvars); | |
|     table = cuddHashTableInit(manager,1,2); | |
|     if (table == NULL) { | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     epsilon = Cudd_ReadEpsilon(manager); | |
|     Cudd_SetEpsilon(manager,(CUDD_VALUE_TYPE)0.0); | |
|     res = ddCountMintermAux(node,max,table); | |
|     cuddHashTableQuit(table); | |
|     Cudd_SetEpsilon(manager,epsilon); | |
| 
 | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_CountMinterm */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of paths of a DD.] | |
|  | |
|   Description [Counts the number of paths of a DD.  Paths to all | |
|   terminal nodes are counted. The path count is represented as a | |
|   double, to allow for a larger number of variables.  Returns the | |
|   number of paths of the function rooted at node if successful; | |
|   (double) CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_CountMinterm] | |
|  | |
| ******************************************************************************/ | |
| double | |
| Cudd_CountPath( | |
|   DdNode * node) | |
| { | |
| 
 | |
|     st_table	*table; | |
|     double	i; | |
| 
 | |
|     table = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (table == NULL) { | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     i = ddCountPathAux(Cudd_Regular(node),table); | |
|     st_foreach(table, cuddStCountfree, NULL); | |
|     st_free_table(table); | |
|     return(i); | |
| 
 | |
| } /* end of Cudd_CountPath */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of minterms of a DD with extended precision.] | |
|  | |
|   Description [Counts the number of minterms of a DD with extended precision. | |
|   The function is assumed to depend on nvars variables. The minterm count is | |
|   represented as an EpDouble, to allow any number of variables. | |
|   Returns 0 if successful; CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintDebug Cudd_CountPath] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_EpdCountMinterm( | |
|   DdManager * manager, | |
|   DdNode * node, | |
|   int  nvars, | |
|   EpDouble * epd) | |
| { | |
|     EpDouble	max, tmp; | |
|     st_table	*table; | |
|     int		status; | |
| 
 | |
|     background = manager->background; | |
|     zero = Cudd_Not(manager->one); | |
| 
 | |
|     EpdPow2(nvars, &max); | |
|     table = st_init_table(EpdCmp, st_ptrhash); | |
|     if (table == NULL) { | |
| 	EpdMakeZero(epd, 0); | |
| 	return(CUDD_OUT_OF_MEM); | |
|     } | |
|     status = ddEpdCountMintermAux(Cudd_Regular(node),&max,epd,table); | |
|     st_foreach(table, ddEpdFree, NULL); | |
|     st_free_table(table); | |
|     if (status == CUDD_OUT_OF_MEM) { | |
| 	EpdMakeZero(epd, 0); | |
| 	return(CUDD_OUT_OF_MEM); | |
|     } | |
|     if (Cudd_IsComplement(node)) { | |
| 	EpdSubtract3(&max, epd, &tmp); | |
| 	EpdCopy(&tmp, epd); | |
|     } | |
|     return(0); | |
| 
 | |
| } /* end of Cudd_EpdCountMinterm */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of paths to a non-zero terminal of a DD.] | |
|  | |
|   Description [Counts the number of paths to a non-zero terminal of a | |
|   DD.  The path count is | |
|   represented as a double, to allow for a larger number of variables. | |
|   Returns the number of paths of the function rooted at node.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_CountMinterm Cudd_CountPath] | |
|  | |
| ******************************************************************************/ | |
| double | |
| Cudd_CountPathsToNonZero( | |
|   DdNode * node) | |
| { | |
| 
 | |
|     st_table	*table; | |
|     double	i; | |
| 
 | |
|     table = st_init_table(st_ptrcmp,st_ptrhash); | |
|     if (table == NULL) { | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     i = ddCountPathsToNonZero(node,table); | |
|     st_foreach(table, cuddStCountfree, NULL); | |
|     st_free_table(table); | |
|     return(i); | |
| 
 | |
| } /* end of Cudd_CountPathsToNonZero */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a DD depends.] | |
|  | |
|   Description [Finds the variables on which a DD depends.  Returns the | |
|   number of variables if successful; CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [The indices of the support variables are returned as | |
|   side effects.  If the function is constant, no array is allocated.] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_SupportIndex Cudd_VectorSupportIndices] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_SupportIndices( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* DD whose support is sought */, | |
|   int **indices /* array containing (on return) the indices */) | |
| { | |
|     int SP = 0; | |
| 
 | |
|     ddFindSupport(dd, Cudd_Regular(f), &SP); | |
|     ddClearFlag(Cudd_Regular(f)); | |
|     ddClearVars(dd, SP); | |
|     if (SP > 0) { | |
|         int i; | |
|         *indices = ALLOC(int, SP); | |
|         if (*indices == NULL) { | |
|             dd->errorCode = CUDD_MEMORY_OUT; | |
|             return(CUDD_OUT_OF_MEM); | |
|         } | |
| 
 | |
|         for (i = 0; i < SP; i++) | |
|             (*indices)[i] = (int) (ptrint) dd->stack[i]; | |
| 
 | |
|         qsort(*indices, SP, sizeof(int), indexCompare); | |
|     } else { | |
|         *indices = NULL; | |
|     } | |
| 
 | |
|     return(SP); | |
| 
 | |
| } /* end of Cudd_SupportIndices */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a DD depends.] | |
|  | |
|   Description [Finds the variables on which a DD depends. | |
|   Returns a BDD consisting of the product of the variables if | |
|   successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_VectorSupport Cudd_ClassifySupport] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_Support( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* DD whose support is sought */) | |
| { | |
|     int	*support; | |
|     DdNode *res; | |
|     int j; | |
| 
 | |
|     int size = Cudd_SupportIndices(dd, f, &support); | |
|     if (size == CUDD_OUT_OF_MEM) | |
|         return(NULL); | |
| 
 | |
|     /* Transform support from array of indices to cube. */ | |
|     res = DD_ONE(dd); | |
|     cuddRef(res); | |
|      | |
|     for (j = size - 1; j >= 0; j--) { /* for each index bottom-up (almost) */ | |
|         int index = support[j]; | |
|         DdNode *var = dd->vars[index]; | |
|         DdNode *tmp = Cudd_bddAnd(dd,res,var); | |
|         if (tmp == NULL) { | |
|             Cudd_RecursiveDeref(dd,res); | |
|             FREE(support); | |
|             return(NULL); | |
|         } | |
|         cuddRef(tmp); | |
|         Cudd_RecursiveDeref(dd,res); | |
|         res = tmp; | |
|     } | |
| 
 | |
|     FREE(support); | |
|     cuddDeref(res); | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_Support */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a DD depends.] | |
|  | |
|   Description [Finds the variables on which a DD depends.  Returns an | |
|   index array of the variables if successful; NULL otherwise.  The | |
|   size of the array equals the number of variables in the manager. | |
|   Each entry of the array is 1 if the corresponding variable is in the | |
|   support of the DD and 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_SupportIndices Cudd_ClassifySupport] | |
|  | |
| ******************************************************************************/ | |
| int * | |
| Cudd_SupportIndex( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* DD whose support is sought */) | |
| { | |
|     int	*support; | |
|     int	i; | |
|     int size; | |
| 
 | |
|     /* Allocate and initialize support array for ddSupportStep. */ | |
|     size = ddMax(dd->size, dd->sizeZ); | |
|     support = ALLOC(int,size); | |
|     if (support == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < size; i++) { | |
| 	support[i] = 0; | |
|     } | |
| 
 | |
|     /* Compute support and clean up markers. */ | |
|     ddSupportStep(Cudd_Regular(f),support); | |
|     ddClearFlag(Cudd_Regular(f)); | |
| 
 | |
|     return(support); | |
| 
 | |
| } /* end of Cudd_SupportIndex */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the variables on which a DD depends.] | |
|  | |
|   Description [Returns the variables on which a DD depends.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_SupportIndices] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_SupportSize( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* DD whose support size is sought */) | |
| { | |
|     int SP = 0; | |
| 
 | |
|     ddFindSupport(dd, Cudd_Regular(f), &SP); | |
|     ddClearFlag(Cudd_Regular(f)); | |
|     ddClearVars(dd, SP); | |
| 
 | |
|     return(SP); | |
| 
 | |
| } /* end of Cudd_SupportSize */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a set of DDs depends.] | |
|  | |
|   Description [Finds the variables on which a set of DDs depends.  The | |
|   set must contain either BDDs and ADDs, or ZDDs.  Returns the number | |
|   of variables if successful; CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [The indices of the support variables are returned as | |
|   side effects.  If the function is constant, no array is allocated.] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_SupportIndex Cudd_VectorSupportIndices] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_VectorSupportIndices( | |
|   DdManager * dd /* manager */, | |
|   DdNode ** F /* DD whose support is sought */, | |
|   int  n /* size of the array */, | |
|   int **indices /* array containing (on return) the indices */) | |
| { | |
|     int i; | |
|     int SP = 0; | |
| 
 | |
|     /* Compute support and clean up markers. */ | |
|     for (i = 0; i < n; i++) { | |
| 	ddFindSupport(dd, Cudd_Regular(F[i]), &SP); | |
|     } | |
|     for (i = 0; i < n; i++) { | |
| 	ddClearFlag(Cudd_Regular(F[i])); | |
|     } | |
|     ddClearVars(dd, SP); | |
| 
 | |
|     if (SP > 0) { | |
|         int i; | |
|         *indices = ALLOC(int, SP); | |
|         if (*indices == NULL) { | |
|             dd->errorCode = CUDD_MEMORY_OUT; | |
|             return(CUDD_OUT_OF_MEM); | |
|         } | |
| 
 | |
|         for (i = 0; i < SP; i++) | |
|             (*indices)[i] = (int) (ptrint) dd->stack[i]; | |
| 
 | |
|         qsort(*indices, SP, sizeof(int), indexCompare); | |
|     } else { | |
|         *indices = NULL; | |
|     } | |
| 
 | |
|     return(SP); | |
| 
 | |
| } /* end of Cudd_VectorSupportIndices */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a set of DDs depends.] | |
|  | |
|   Description [Finds the variables on which a set of DDs depends. | |
|   The set must contain either BDDs and ADDs, or ZDDs. | |
|   Returns a BDD consisting of the product of the variables if | |
|   successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_ClassifySupport] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_VectorSupport( | |
|   DdManager * dd /* manager */, | |
|   DdNode ** F /* array of DDs whose support is sought */, | |
|   int  n /* size of the array */) | |
| { | |
|     int	*support; | |
|     DdNode *res; | |
|     int	j; | |
|     int size = Cudd_VectorSupportIndices(dd, F, n, &support); | |
|     if (size == CUDD_OUT_OF_MEM) | |
|         return(NULL); | |
| 
 | |
|     /* Transform support from array of indices to cube. */ | |
|     res = DD_ONE(dd); | |
|     cuddRef(res); | |
|      | |
|     for (j = size - 1; j >= 0; j--) { /* for each index bottom-up (almost) */ | |
|         int index = support[j]; | |
|         DdNode *var = dd->vars[index]; | |
|         DdNode *tmp = Cudd_bddAnd(dd,res,var); | |
|         if (tmp == NULL) { | |
|             Cudd_RecursiveDeref(dd,res); | |
|             FREE(support); | |
|             return(NULL); | |
|         } | |
|         cuddRef(tmp); | |
|         Cudd_RecursiveDeref(dd,res); | |
|         res = tmp; | |
|     } | |
| 
 | |
|     FREE(support); | |
|     cuddDeref(res); | |
|     return(res); | |
| 
 | |
| } /* end of Cudd_VectorSupport */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the variables on which a set of DDs depends.] | |
|  | |
|   Description [Finds the variables on which a set of DDs depends. | |
|   The set must contain either BDDs and ADDs, or ZDDs. | |
|   Returns an index array of the variables if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_SupportIndex Cudd_VectorSupport Cudd_VectorSupportIndices] | |
|  | |
| ******************************************************************************/ | |
| int * | |
| Cudd_VectorSupportIndex( | |
|   DdManager * dd /* manager */, | |
|   DdNode ** F /* array of DDs whose support is sought */, | |
|   int  n /* size of the array */) | |
| { | |
|     int	*support; | |
|     int	i; | |
|     int size; | |
| 
 | |
|     /* Allocate and initialize support array for ddSupportStep. */ | |
|     size = ddMax(dd->size, dd->sizeZ); | |
|     support = ALLOC(int,size); | |
|     if (support == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < size; i++) { | |
| 	support[i] = 0; | |
|     } | |
| 
 | |
|     /* Compute support and clean up markers. */ | |
|     for (i = 0; i < n; i++) { | |
| 	ddSupportStep(Cudd_Regular(F[i]),support); | |
|     } | |
|     for (i = 0; i < n; i++) { | |
| 	ddClearFlag(Cudd_Regular(F[i])); | |
|     } | |
| 
 | |
|     return(support); | |
| 
 | |
| } /* end of Cudd_VectorSupportIndex */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the variables on which a set of DDs depends.] | |
|  | |
|   Description [Returns the variables on which a set of DDs depends. | |
|   The set must contain either BDDs and ADDs, or ZDDs.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_VectorSupport Cudd_SupportSize] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_VectorSupportSize( | |
|   DdManager * dd /* manager */, | |
|   DdNode ** F /* array of DDs whose support is sought */, | |
|   int  n /* size of the array */) | |
| { | |
|     int i; | |
|     int SP = 0; | |
| 
 | |
|     /* Compute support and clean up markers. */ | |
|     for (i = 0; i < n; i++) { | |
| 	ddFindSupport(dd, Cudd_Regular(F[i]), &SP); | |
|     } | |
|     for (i = 0; i < n; i++) { | |
| 	ddClearFlag(Cudd_Regular(F[i])); | |
|     } | |
|     ddClearVars(dd, SP); | |
| 
 | |
|     return(SP); | |
| 
 | |
| } /* end of Cudd_VectorSupportSize */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Classifies the variables in the support of two DDs.] | |
|  | |
|   Description [Classifies the variables in the support of two DDs | |
|   <code>f</code> and <code>g</code>, depending on whther they appear | |
|   in both DDs, only in <code>f</code>, or only in <code>g</code>. | |
|   Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [The cubes of the three classes of variables are | |
|   returned as side effects.] | |
|  | |
|   SeeAlso     [Cudd_Support Cudd_VectorSupport] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_ClassifySupport( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* first DD */, | |
|   DdNode * g /* second DD */, | |
|   DdNode ** common /* cube of shared variables */, | |
|   DdNode ** onlyF /* cube of variables only in f */, | |
|   DdNode ** onlyG /* cube of variables only in g */) | |
| { | |
|     int	*supportF, *supportG; | |
|     int	fi, gi; | |
|     int sizeF, sizeG; | |
| 
 | |
|     sizeF = Cudd_SupportIndices(dd, f, &supportF); | |
|     if (sizeF == CUDD_OUT_OF_MEM) | |
|         return(0); | |
| 
 | |
|     sizeG = Cudd_SupportIndices(dd, g, &supportG); | |
|     if (sizeG == CUDD_OUT_OF_MEM) { | |
|         FREE(supportF); | |
|         return(0); | |
|     } | |
| 
 | |
|     /* Classify variables and create cubes. This part of the procedure | |
|     ** relies on the sorting of the indices in the two support arrays. | |
|     */ | |
|     *common = *onlyF = *onlyG = DD_ONE(dd); | |
|     cuddRef(*common); cuddRef(*onlyF); cuddRef(*onlyG); | |
|     fi = sizeF - 1; | |
|     gi = sizeG - 1; | |
|     while (fi >= 0 || gi >= 0) { | |
|         int indexF = fi >= 0 ? supportF[fi] : -1; | |
|         int indexG = gi >= 0 ? supportG[gi] : -1; | |
|         int index = ddMax(indexF, indexG); | |
|         DdNode *var = dd->vars[index]; | |
| #ifdef DD_DEBUG | |
|         assert(index >= 0); | |
| #endif | |
|         if (indexF == indexG) { | |
|             DdNode *tmp = Cudd_bddAnd(dd,*common,var); | |
| 	    if (tmp == NULL) { | |
| 		Cudd_RecursiveDeref(dd,*common); | |
| 		Cudd_RecursiveDeref(dd,*onlyF); | |
| 		Cudd_RecursiveDeref(dd,*onlyG); | |
| 		FREE(supportF); FREE(supportG); | |
| 		return(0); | |
| 	    } | |
| 	    cuddRef(tmp); | |
| 	    Cudd_RecursiveDeref(dd,*common); | |
| 	    *common = tmp; | |
|             fi--; | |
|             gi--; | |
|         } else if (index == indexF) { | |
| 	    DdNode *tmp = Cudd_bddAnd(dd,*onlyF,var); | |
| 	    if (tmp == NULL) { | |
| 		Cudd_RecursiveDeref(dd,*common); | |
| 		Cudd_RecursiveDeref(dd,*onlyF); | |
| 		Cudd_RecursiveDeref(dd,*onlyG); | |
| 		FREE(supportF); FREE(supportG); | |
| 		return(0); | |
| 	    } | |
| 	    cuddRef(tmp); | |
| 	    Cudd_RecursiveDeref(dd,*onlyF); | |
| 	    *onlyF = tmp; | |
|             fi--; | |
|         } else { /* index == indexG */ | |
| 	    DdNode *tmp = Cudd_bddAnd(dd,*onlyG,var); | |
| 	    if (tmp == NULL) { | |
| 		Cudd_RecursiveDeref(dd,*common); | |
| 		Cudd_RecursiveDeref(dd,*onlyF); | |
| 		Cudd_RecursiveDeref(dd,*onlyG); | |
| 		FREE(supportF); FREE(supportG); | |
| 		return(0); | |
| 	    } | |
| 	    cuddRef(tmp); | |
| 	    Cudd_RecursiveDeref(dd,*onlyG); | |
| 	    *onlyG = tmp; | |
|             gi--; | |
|         } | |
|     } | |
| 
 | |
|     FREE(supportF); FREE(supportG); | |
|     cuddDeref(*common); cuddDeref(*onlyF); cuddDeref(*onlyG); | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_ClassifySupport */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Counts the number of leaves in a DD.] | |
|  | |
|   Description [Counts the number of leaves in a DD. Returns the number | |
|   of leaves in the DD rooted at node if successful; CUDD_OUT_OF_MEM | |
|   otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintDebug] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_CountLeaves( | |
|   DdNode * node) | |
| { | |
|     int	i; | |
| 
 | |
|     i = ddLeavesInt(Cudd_Regular(node)); | |
|     ddClearFlag(Cudd_Regular(node)); | |
|     return(i); | |
| 
 | |
| } /* end of Cudd_CountLeaves */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Picks one on-set cube randomly from the given DD.] | |
|  | |
|   Description [Picks one on-set cube randomly from the given DD. The | |
|   cube is written into an array of characters.  The array must have at | |
|   least as many entries as there are variables. Returns 1 if | |
|   successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddPickOneMinterm] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_bddPickOneCube( | |
|   DdManager * ddm, | |
|   DdNode * node, | |
|   char * string) | |
| { | |
|     DdNode *N, *T, *E; | |
|     DdNode *one, *bzero; | |
|     char   dir; | |
|     int    i; | |
| 
 | |
|     if (string == NULL || node == NULL) return(0); | |
| 
 | |
|     /* The constant 0 function has no on-set cubes. */ | |
|     one = DD_ONE(ddm); | |
|     bzero = Cudd_Not(one); | |
|     if (node == bzero) return(0); | |
| 
 | |
|     for (i = 0; i < ddm->size; i++) string[i] = 2; | |
| 
 | |
|     for (;;) { | |
| 
 | |
| 	if (node == one) break; | |
| 
 | |
| 	N = Cudd_Regular(node); | |
| 
 | |
| 	T = cuddT(N); E = cuddE(N); | |
| 	if (Cudd_IsComplement(node)) { | |
| 	    T = Cudd_Not(T); E = Cudd_Not(E); | |
| 	} | |
| 	if (T == bzero) { | |
| 	    string[N->index] = 0; | |
| 	    node = E; | |
| 	} else if (E == bzero) { | |
| 	    string[N->index] = 1; | |
| 	    node = T; | |
| 	} else { | |
| 	    dir = (char) ((Cudd_Random() & 0x2000) >> 13); | |
| 	    string[N->index] = dir; | |
| 	    node = dir ? T : E; | |
| 	} | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_bddPickOneCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Picks one on-set minterm randomly from the given DD.] | |
|  | |
|   Description [Picks one on-set minterm randomly from the given | |
|   DD. The minterm is in terms of <code>vars</code>. The array | |
|   <code>vars</code> should contain at least all variables in the | |
|   support of <code>f</code>; if this condition is not met the minterm | |
|   built by this procedure may not be contained in | |
|   <code>f</code>. Builds a BDD for the minterm and returns a pointer | |
|   to it if successful; NULL otherwise. There are three reasons why the | |
|   procedure may fail: | |
|   <ul> | |
|   <li> It may run out of memory; | |
|   <li> the function <code>f</code> may be the constant 0; | |
|   <li> the minterm may not be contained in <code>f</code>. | |
|   </ul>] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddPickOneCube] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_bddPickOneMinterm( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* function from which to pick one minterm */, | |
|   DdNode ** vars /* array of variables */, | |
|   int  n /* size of <code>vars</code> */) | |
| { | |
|     char *string; | |
|     int i, size; | |
|     int *indices; | |
|     int result; | |
|     DdNode *old, *neW; | |
| 
 | |
|     size = dd->size; | |
|     string = ALLOC(char, size); | |
|     if (string == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     indices = ALLOC(int,n); | |
|     if (indices == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(string); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     for (i = 0; i < n; i++) { | |
| 	indices[i] = vars[i]->index; | |
|     } | |
| 
 | |
|     result = Cudd_bddPickOneCube(dd,f,string); | |
|     if (result == 0) { | |
| 	FREE(string); | |
| 	FREE(indices); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     /* Randomize choice for don't cares. */ | |
|     for (i = 0; i < n; i++) { | |
| 	if (string[indices[i]] == 2) | |
| 	    string[indices[i]] = (char) ((Cudd_Random() & 0x20) >> 5); | |
|     } | |
| 
 | |
|     /* Build result BDD. */ | |
|     old = Cudd_ReadOne(dd); | |
|     cuddRef(old); | |
| 
 | |
|     for (i = n-1; i >= 0; i--) { | |
| 	neW = Cudd_bddAnd(dd,old,Cudd_NotCond(vars[i],string[indices[i]]==0)); | |
| 	if (neW == NULL) { | |
| 	    FREE(string); | |
| 	    FREE(indices); | |
| 	    Cudd_RecursiveDeref(dd,old); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(neW); | |
| 	Cudd_RecursiveDeref(dd,old); | |
| 	old = neW; | |
|     } | |
| 
 | |
| #ifdef DD_DEBUG | |
|     /* Test. */ | |
|     if (Cudd_bddLeq(dd,old,f)) { | |
| 	cuddDeref(old); | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,old); | |
| 	old = NULL; | |
|     } | |
| #else | |
|     cuddDeref(old); | |
| #endif | |
|  | |
|     FREE(string); | |
|     FREE(indices); | |
|     return(old); | |
| 
 | |
| }  /* end of Cudd_bddPickOneMinterm */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Picks k on-set minterms evenly distributed from given DD.] | |
|  | |
|   Description [Picks k on-set minterms evenly distributed from given DD. | |
|   The minterms are in terms of <code>vars</code>. The array | |
|   <code>vars</code> should contain at least all variables in the | |
|   support of <code>f</code>; if this condition is not met the minterms | |
|   built by this procedure may not be contained in | |
|   <code>f</code>. Builds an array of BDDs for the minterms and returns a | |
|   pointer to it if successful; NULL otherwise. There are three reasons | |
|   why the procedure may fail: | |
|   <ul> | |
|   <li> It may run out of memory; | |
|   <li> the function <code>f</code> may be the constant 0; | |
|   <li> the minterms may not be contained in <code>f</code>. | |
|   </ul>] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddPickOneMinterm Cudd_bddPickOneCube] | |
|  | |
| ******************************************************************************/ | |
| DdNode ** | |
| Cudd_bddPickArbitraryMinterms( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* function from which to pick k minterms */, | |
|   DdNode ** vars /* array of variables */, | |
|   int  n /* size of <code>vars</code> */, | |
|   int  k /* number of minterms to find */) | |
| { | |
|     char **string; | |
|     int i, j, l, size; | |
|     int *indices; | |
|     int result; | |
|     DdNode **old, *neW; | |
|     double minterms; | |
|     char *saveString; | |
|     int saveFlag, savePoint, isSame; | |
| 
 | |
|     minterms = Cudd_CountMinterm(dd,f,n); | |
|     if ((double)k > minterms) { | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     size = dd->size; | |
|     string = ALLOC(char *, k); | |
|     if (string == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < k; i++) { | |
| 	string[i] = ALLOC(char, size + 1); | |
| 	if (string[i] == NULL) { | |
| 	    for (j = 0; j < i; j++) | |
| 		FREE(string[i]); | |
| 	    FREE(string); | |
| 	    dd->errorCode = CUDD_MEMORY_OUT; | |
| 	    return(NULL); | |
| 	} | |
| 	for (j = 0; j < size; j++) string[i][j] = '2'; | |
| 	string[i][size] = '\0'; | |
|     } | |
|     indices = ALLOC(int,n); | |
|     if (indices == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	for (i = 0; i < k; i++) | |
| 	    FREE(string[i]); | |
| 	FREE(string); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     for (i = 0; i < n; i++) { | |
| 	indices[i] = vars[i]->index; | |
|     } | |
| 
 | |
|     result = ddPickArbitraryMinterms(dd,f,n,k,string); | |
|     if (result == 0) { | |
| 	for (i = 0; i < k; i++) | |
| 	    FREE(string[i]); | |
| 	FREE(string); | |
| 	FREE(indices); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     old = ALLOC(DdNode *, k); | |
|     if (old == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	for (i = 0; i < k; i++) | |
| 	    FREE(string[i]); | |
| 	FREE(string); | |
| 	FREE(indices); | |
| 	return(NULL); | |
|     } | |
|     saveString = ALLOC(char, size + 1); | |
|     if (saveString == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	for (i = 0; i < k; i++) | |
| 	    FREE(string[i]); | |
| 	FREE(string); | |
| 	FREE(indices); | |
| 	FREE(old); | |
| 	return(NULL); | |
|     } | |
|     saveFlag = 0; | |
| 
 | |
|     /* Build result BDD array. */ | |
|     for (i = 0; i < k; i++) { | |
| 	isSame = 0; | |
| 	if (!saveFlag) { | |
| 	    for (j = i + 1; j < k; j++) { | |
| 		if (strcmp(string[i], string[j]) == 0) { | |
| 		    savePoint = i; | |
| 		    strcpy(saveString, string[i]); | |
| 		    saveFlag = 1; | |
| 		    break; | |
| 		} | |
| 	    } | |
| 	} else { | |
| 	    if (strcmp(string[i], saveString) == 0) { | |
| 		isSame = 1; | |
| 	    } else { | |
| 		saveFlag = 0; | |
| 		for (j = i + 1; j < k; j++) { | |
| 		    if (strcmp(string[i], string[j]) == 0) { | |
| 			savePoint = i; | |
| 			strcpy(saveString, string[i]); | |
| 			saveFlag = 1; | |
| 			break; | |
| 		    } | |
| 		} | |
| 	    } | |
| 	} | |
| 	/* Randomize choice for don't cares. */ | |
| 	for (j = 0; j < n; j++) { | |
| 	    if (string[i][indices[j]] == '2') | |
| 		string[i][indices[j]] = | |
| 		  (char) ((Cudd_Random() & 0x20) ? '1' : '0'); | |
| 	} | |
| 
 | |
| 	while (isSame) { | |
| 	    isSame = 0; | |
| 	    for (j = savePoint; j < i; j++) { | |
| 		if (strcmp(string[i], string[j]) == 0) { | |
| 		    isSame = 1; | |
| 		    break; | |
| 		} | |
| 	    } | |
| 	    if (isSame) { | |
| 		strcpy(string[i], saveString); | |
| 		/* Randomize choice for don't cares. */ | |
| 		for (j = 0; j < n; j++) { | |
| 		    if (string[i][indices[j]] == '2') | |
| 			string[i][indices[j]] = | |
| 			  (char) ((Cudd_Random() & 0x20) ? '1' : '0'); | |
| 		} | |
| 	    } | |
| 	} | |
| 
 | |
| 	old[i] = Cudd_ReadOne(dd); | |
| 	cuddRef(old[i]); | |
| 
 | |
| 	for (j = 0; j < n; j++) { | |
| 	    if (string[i][indices[j]] == '0') { | |
| 		neW = Cudd_bddAnd(dd,old[i],Cudd_Not(vars[j])); | |
| 	    } else { | |
| 		neW = Cudd_bddAnd(dd,old[i],vars[j]); | |
| 	    } | |
| 	    if (neW == NULL) { | |
| 		FREE(saveString); | |
| 		for (l = 0; l < k; l++) | |
| 		    FREE(string[l]); | |
| 		FREE(string); | |
| 		FREE(indices); | |
| 		for (l = 0; l <= i; l++) | |
| 		    Cudd_RecursiveDeref(dd,old[l]); | |
| 		FREE(old); | |
| 		return(NULL); | |
| 	    } | |
| 	    cuddRef(neW); | |
| 	    Cudd_RecursiveDeref(dd,old[i]); | |
| 	    old[i] = neW; | |
| 	} | |
| 
 | |
| 	/* Test. */ | |
| 	if (!Cudd_bddLeq(dd,old[i],f)) { | |
| 	    FREE(saveString); | |
| 	    for (l = 0; l < k; l++) | |
| 		FREE(string[l]); | |
| 	    FREE(string); | |
| 	    FREE(indices); | |
| 	    for (l = 0; l <= i; l++) | |
| 		Cudd_RecursiveDeref(dd,old[l]); | |
| 	    FREE(old); | |
| 	    return(NULL); | |
| 	} | |
|     } | |
| 
 | |
|     FREE(saveString); | |
|     for (i = 0; i < k; i++) { | |
| 	cuddDeref(old[i]); | |
| 	FREE(string[i]); | |
|     } | |
|     FREE(string); | |
|     FREE(indices); | |
|     return(old); | |
| 
 | |
| }  /* end of Cudd_bddPickArbitraryMinterms */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Extracts a subset from a BDD.] | |
|  | |
|   Description [Extracts a subset from a BDD in the following procedure. | |
|   1. Compute the weight for each mask variable by counting the number of | |
|      minterms for both positive and negative cofactors of the BDD with | |
|      respect to each mask variable. (weight = #positive - #negative) | |
|   2. Find a representative cube of the BDD by using the weight. From the | |
|      top variable of the BDD, for each variable, if the weight is greater | |
|      than 0.0, choose THEN branch, othereise ELSE branch, until meeting | |
|      the constant 1. | |
|   3. Quantify out the variables not in maskVars from the representative | |
|      cube and if a variable in maskVars is don't care, replace the | |
|      variable with a constant(1 or 0) depending on the weight. | |
|   4. Make a subset of the BDD by multiplying with the modified cube.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_SubsetWithMaskVars( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* function from which to pick a cube */, | |
|   DdNode ** vars /* array of variables */, | |
|   int  nvars /* size of <code>vars</code> */, | |
|   DdNode ** maskVars /* array of variables */, | |
|   int  mvars /* size of <code>maskVars</code> */) | |
| { | |
|     double	*weight; | |
|     char	*string; | |
|     int		i, size; | |
|     int		*indices, *mask; | |
|     int		result; | |
|     DdNode	*zero, *cube, *newCube, *subset; | |
|     DdNode	*cof; | |
| 
 | |
|     DdNode	*support; | |
|     support = Cudd_Support(dd,f); | |
|     cuddRef(support); | |
|     Cudd_RecursiveDeref(dd,support); | |
| 
 | |
|     zero = Cudd_Not(dd->one); | |
|     size = dd->size; | |
| 
 | |
|     weight = ALLOC(double,size); | |
|     if (weight == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < size; i++) { | |
| 	weight[i] = 0.0; | |
|     } | |
|     for (i = 0; i < mvars; i++) { | |
| 	cof = Cudd_Cofactor(dd, f, maskVars[i]); | |
| 	cuddRef(cof); | |
| 	weight[i] = Cudd_CountMinterm(dd, cof, nvars); | |
| 	Cudd_RecursiveDeref(dd,cof); | |
| 
 | |
| 	cof = Cudd_Cofactor(dd, f, Cudd_Not(maskVars[i])); | |
| 	cuddRef(cof); | |
| 	weight[i] -= Cudd_CountMinterm(dd, cof, nvars); | |
| 	Cudd_RecursiveDeref(dd,cof); | |
|     } | |
| 
 | |
|     string = ALLOC(char, size + 1); | |
|     if (string == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(weight); | |
| 	return(NULL); | |
|     } | |
|     mask = ALLOC(int, size); | |
|     if (mask == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(weight); | |
| 	FREE(string); | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < size; i++) { | |
| 	string[i] = '2'; | |
| 	mask[i] = 0; | |
|     } | |
|     string[size] = '\0'; | |
|     indices = ALLOC(int,nvars); | |
|     if (indices == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(weight); | |
| 	FREE(string); | |
| 	FREE(mask); | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < nvars; i++) { | |
| 	indices[i] = vars[i]->index; | |
|     } | |
| 
 | |
|     result = ddPickRepresentativeCube(dd,f,weight,string); | |
|     if (result == 0) { | |
| 	FREE(weight); | |
| 	FREE(string); | |
| 	FREE(mask); | |
| 	FREE(indices); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     cube = Cudd_ReadOne(dd); | |
|     cuddRef(cube); | |
|     zero = Cudd_Not(Cudd_ReadOne(dd)); | |
|     for (i = 0; i < nvars; i++) { | |
| 	if (string[indices[i]] == '0') { | |
| 	    newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero); | |
| 	} else if (string[indices[i]] == '1') { | |
| 	    newCube = Cudd_bddIte(dd,cube,vars[i],zero); | |
| 	} else | |
| 	    continue; | |
| 	if (newCube == NULL) { | |
| 	    FREE(weight); | |
| 	    FREE(string); | |
| 	    FREE(mask); | |
| 	    FREE(indices); | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(newCube); | |
| 	Cudd_RecursiveDeref(dd,cube); | |
| 	cube = newCube; | |
|     } | |
|     Cudd_RecursiveDeref(dd,cube); | |
| 
 | |
|     for (i = 0; i < mvars; i++) { | |
| 	mask[maskVars[i]->index] = 1; | |
|     } | |
|     for (i = 0; i < nvars; i++) { | |
| 	if (mask[indices[i]]) { | |
| 	    if (string[indices[i]] == '2') { | |
| 		if (weight[indices[i]] >= 0.0) | |
| 		    string[indices[i]] = '1'; | |
| 		else | |
| 		    string[indices[i]] = '0'; | |
| 	    } | |
| 	} else { | |
| 	    string[indices[i]] = '2'; | |
| 	} | |
|     } | |
| 
 | |
|     cube = Cudd_ReadOne(dd); | |
|     cuddRef(cube); | |
|     zero = Cudd_Not(Cudd_ReadOne(dd)); | |
| 
 | |
|     /* Build result BDD. */ | |
|     for (i = 0; i < nvars; i++) { | |
| 	if (string[indices[i]] == '0') { | |
| 	    newCube = Cudd_bddIte(dd,cube,Cudd_Not(vars[i]),zero); | |
| 	} else if (string[indices[i]] == '1') { | |
| 	    newCube = Cudd_bddIte(dd,cube,vars[i],zero); | |
| 	} else | |
| 	    continue; | |
| 	if (newCube == NULL) { | |
| 	    FREE(weight); | |
| 	    FREE(string); | |
| 	    FREE(mask); | |
| 	    FREE(indices); | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(newCube); | |
| 	Cudd_RecursiveDeref(dd,cube); | |
| 	cube = newCube; | |
|     } | |
| 
 | |
|     subset = Cudd_bddAnd(dd,f,cube); | |
|     cuddRef(subset); | |
|     Cudd_RecursiveDeref(dd,cube); | |
| 
 | |
|     /* Test. */ | |
|     if (Cudd_bddLeq(dd,subset,f)) { | |
| 	cuddDeref(subset); | |
|     } else { | |
| 	Cudd_RecursiveDeref(dd,subset); | |
| 	subset = NULL; | |
|     } | |
| 
 | |
|     FREE(weight); | |
|     FREE(string); | |
|     FREE(mask); | |
|     FREE(indices); | |
|     return(subset); | |
| 
 | |
| } /* end of Cudd_SubsetWithMaskVars */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the first cube of a decision diagram.] | |
|  | |
|   Description [Defines an iterator on the onset of a decision diagram | |
|   and finds its first cube. Returns a generator that contains the | |
|   information necessary to continue the enumeration if successful; NULL | |
|   otherwise.<p> | |
|   A cube is represented as an array of literals, which are integers in | |
|   {0, 1, 2}; 0 represents a complemented literal, 1 represents an | |
|   uncomplemented literal, and 2 stands for don't care. The enumeration | |
|   produces a disjoint cover of the function associated with the diagram. | |
|   The size of the array equals the number of variables in the manager at | |
|   the time Cudd_FirstCube is called.<p> | |
|   For each cube, a value is also returned. This value is always 1 for a | |
|   BDD, while it may be different from 1 for an ADD. | |
|   For BDDs, the offset is the set of cubes whose value is the logical zero. | |
|   For ADDs, the offset is the set of cubes whose value is the | |
|   background value. The cubes of the offset are not enumerated.] | |
|  | |
|   SideEffects [The first cube and its value are returned as side effects.] | |
|  | |
|   SeeAlso     [Cudd_ForeachCube Cudd_NextCube Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_FirstNode] | |
|  | |
| ******************************************************************************/ | |
| DdGen * | |
| Cudd_FirstCube( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   int ** cube, | |
|   CUDD_VALUE_TYPE * value) | |
| { | |
|     DdGen *gen; | |
|     DdNode *top, *treg, *next, *nreg, *prev, *preg; | |
|     int i; | |
|     int nvars; | |
| 
 | |
|     /* Sanity Check. */ | |
|     if (dd == NULL || f == NULL) return(NULL); | |
| 
 | |
|     /* Allocate generator an initialize it. */ | |
|     gen = ALLOC(DdGen,1); | |
|     if (gen == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     gen->manager = dd; | |
|     gen->type = CUDD_GEN_CUBES; | |
|     gen->status = CUDD_GEN_EMPTY; | |
|     gen->gen.cubes.cube = NULL; | |
|     gen->gen.cubes.value = DD_ZERO_VAL; | |
|     gen->stack.sp = 0; | |
|     gen->stack.stack = NULL; | |
|     gen->node = NULL; | |
| 
 | |
|     nvars = dd->size; | |
|     gen->gen.cubes.cube = ALLOC(int,nvars); | |
|     if (gen->gen.cubes.cube == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(gen); | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i < nvars; i++) gen->gen.cubes.cube[i] = 2; | |
| 
 | |
|     /* The maximum stack depth is one plus the number of variables. | |
|     ** because a path may have nodes at all levels, including the | |
|     ** constant level. | |
|     */ | |
|     gen->stack.stack = ALLOC(DdNodePtr, nvars+1); | |
|     if (gen->stack.stack == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(gen->gen.cubes.cube); | |
| 	FREE(gen); | |
| 	return(NULL); | |
|     } | |
|     for (i = 0; i <= nvars; i++) gen->stack.stack[i] = NULL; | |
| 
 | |
|     /* Find the first cube of the onset. */ | |
|     gen->stack.stack[gen->stack.sp] = f; gen->stack.sp++; | |
| 
 | |
|     while (1) { | |
| 	top = gen->stack.stack[gen->stack.sp-1]; | |
| 	treg = Cudd_Regular(top); | |
| 	if (!cuddIsConstant(treg)) { | |
| 	    /* Take the else branch first. */ | |
| 	    gen->gen.cubes.cube[treg->index] = 0; | |
| 	    next = cuddE(treg); | |
| 	    if (top != treg) next = Cudd_Not(next); | |
| 	    gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++; | |
| 	} else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) { | |
| 	    /* Backtrack */ | |
| 	    while (1) { | |
| 		if (gen->stack.sp == 1) { | |
| 		    /* The current node has no predecessor. */ | |
| 		    gen->status = CUDD_GEN_EMPTY; | |
| 		    gen->stack.sp--; | |
| 		    goto done; | |
| 		} | |
| 		prev = gen->stack.stack[gen->stack.sp-2]; | |
| 		preg = Cudd_Regular(prev); | |
| 		nreg = cuddT(preg); | |
| 		if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;} | |
| 		if (next != top) { /* follow the then branch next */ | |
| 		    gen->gen.cubes.cube[preg->index] = 1; | |
| 		    gen->stack.stack[gen->stack.sp-1] = next; | |
| 		    break; | |
| 		} | |
| 		/* Pop the stack and try again. */ | |
| 		gen->gen.cubes.cube[preg->index] = 2; | |
| 		gen->stack.sp--; | |
| 		top = gen->stack.stack[gen->stack.sp-1]; | |
| 		treg = Cudd_Regular(top); | |
| 	    } | |
| 	} else { | |
| 	    gen->status = CUDD_GEN_NONEMPTY; | |
| 	    gen->gen.cubes.value = cuddV(top); | |
| 	    goto done; | |
| 	} | |
|     } | |
| 
 | |
| done: | |
|     *cube = gen->gen.cubes.cube; | |
|     *value = gen->gen.cubes.value; | |
|     return(gen); | |
| 
 | |
| } /* end of Cudd_FirstCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Generates the next cube of a decision diagram onset.] | |
|  | |
|   Description [Generates the next cube of a decision diagram onset, | |
|   using generator gen. Returns 0 if the enumeration is completed; 1 | |
|   otherwise.] | |
|  | |
|   SideEffects [The cube and its value are returned as side effects. The | |
|   generator is modified.] | |
|  | |
|   SeeAlso     [Cudd_ForeachCube Cudd_FirstCube Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_NextNode] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_NextCube( | |
|   DdGen * gen, | |
|   int ** cube, | |
|   CUDD_VALUE_TYPE * value) | |
| { | |
|     DdNode *top, *treg, *next, *nreg, *prev, *preg; | |
|     DdManager *dd = gen->manager; | |
| 
 | |
|     /* Backtrack from previously reached terminal node. */ | |
|     while (1) { | |
| 	if (gen->stack.sp == 1) { | |
| 	    /* The current node has no predecessor. */ | |
| 	    gen->status = CUDD_GEN_EMPTY; | |
| 	    gen->stack.sp--; | |
| 	    goto done; | |
| 	} | |
| 	top = gen->stack.stack[gen->stack.sp-1]; | |
| 	treg = Cudd_Regular(top); | |
| 	prev = gen->stack.stack[gen->stack.sp-2]; | |
| 	preg = Cudd_Regular(prev); | |
| 	nreg = cuddT(preg); | |
| 	if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;} | |
| 	if (next != top) { /* follow the then branch next */ | |
| 	    gen->gen.cubes.cube[preg->index] = 1; | |
| 	    gen->stack.stack[gen->stack.sp-1] = next; | |
| 	    break; | |
| 	} | |
| 	/* Pop the stack and try again. */ | |
| 	gen->gen.cubes.cube[preg->index] = 2; | |
| 	gen->stack.sp--; | |
|     } | |
| 
 | |
|     while (1) { | |
| 	top = gen->stack.stack[gen->stack.sp-1]; | |
| 	treg = Cudd_Regular(top); | |
| 	if (!cuddIsConstant(treg)) { | |
| 	    /* Take the else branch first. */ | |
| 	    gen->gen.cubes.cube[treg->index] = 0; | |
| 	    next = cuddE(treg); | |
| 	    if (top != treg) next = Cudd_Not(next); | |
| 	    gen->stack.stack[gen->stack.sp] = next; gen->stack.sp++; | |
| 	} else if (top == Cudd_Not(DD_ONE(dd)) || top == dd->background) { | |
| 	    /* Backtrack */ | |
| 	    while (1) { | |
| 		if (gen->stack.sp == 1) { | |
| 		    /* The current node has no predecessor. */ | |
| 		    gen->status = CUDD_GEN_EMPTY; | |
| 		    gen->stack.sp--; | |
| 		    goto done; | |
| 		} | |
| 		prev = gen->stack.stack[gen->stack.sp-2]; | |
| 		preg = Cudd_Regular(prev); | |
| 		nreg = cuddT(preg); | |
| 		if (prev != preg) {next = Cudd_Not(nreg);} else {next = nreg;} | |
| 		if (next != top) { /* follow the then branch next */ | |
| 		    gen->gen.cubes.cube[preg->index] = 1; | |
| 		    gen->stack.stack[gen->stack.sp-1] = next; | |
| 		    break; | |
| 		} | |
| 		/* Pop the stack and try again. */ | |
| 		gen->gen.cubes.cube[preg->index] = 2; | |
| 		gen->stack.sp--; | |
| 		top = gen->stack.stack[gen->stack.sp-1]; | |
| 		treg = Cudd_Regular(top); | |
| 	    } | |
| 	} else { | |
| 	    gen->status = CUDD_GEN_NONEMPTY; | |
| 	    gen->gen.cubes.value = cuddV(top); | |
| 	    goto done; | |
| 	} | |
|     } | |
| 
 | |
| done: | |
|     if (gen->status == CUDD_GEN_EMPTY) return(0); | |
|     *cube = gen->gen.cubes.cube; | |
|     *value = gen->gen.cubes.value; | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_NextCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the first prime of a Boolean function.] | |
|  | |
|   Description [Defines an iterator on a pair of BDDs describing a | |
|   (possibly incompletely specified) Boolean functions and finds the | |
|   first cube of a cover of the function.  Returns a generator | |
|   that contains the information necessary to continue the enumeration | |
|   if successful; NULL otherwise.<p> | |
|  | |
|   The two argument BDDs are the lower and upper bounds of an interval. | |
|   It is a mistake to call this function with a lower bound that is not | |
|   less than or equal to the upper bound.<p> | |
|  | |
|   A cube is represented as an array of literals, which are integers in | |
|   {0, 1, 2}; 0 represents a complemented literal, 1 represents an | |
|   uncomplemented literal, and 2 stands for don't care. The enumeration | |
|   produces a prime and irredundant cover of the function associated | |
|   with the two BDDs.  The size of the array equals the number of | |
|   variables in the manager at the time Cudd_FirstCube is called.<p> | |
|  | |
|   This iterator can only be used on BDDs.] | |
|  | |
|   SideEffects [The first cube is returned as side effect.] | |
|  | |
|   SeeAlso     [Cudd_ForeachPrime Cudd_NextPrime Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_FirstCube Cudd_FirstNode] | |
|  | |
| ******************************************************************************/ | |
| DdGen * | |
| Cudd_FirstPrime( | |
|   DdManager *dd, | |
|   DdNode *l, | |
|   DdNode *u, | |
|   int **cube) | |
| { | |
|     DdGen *gen; | |
|     DdNode *implicant, *prime, *tmp; | |
|     int length, result; | |
| 
 | |
|     /* Sanity Check. */ | |
|     if (dd == NULL || l == NULL || u == NULL) return(NULL); | |
| 
 | |
|     /* Allocate generator an initialize it. */ | |
|     gen = ALLOC(DdGen,1); | |
|     if (gen == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     gen->manager = dd; | |
|     gen->type = CUDD_GEN_PRIMES; | |
|     gen->status = CUDD_GEN_EMPTY; | |
|     gen->gen.primes.cube = NULL; | |
|     gen->gen.primes.ub = u; | |
|     gen->stack.sp = 0; | |
|     gen->stack.stack = NULL; | |
|     gen->node = l; | |
|     cuddRef(l); | |
| 
 | |
|     gen->gen.primes.cube = ALLOC(int,dd->size); | |
|     if (gen->gen.primes.cube == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	FREE(gen); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     if (gen->node == Cudd_ReadLogicZero(dd)) { | |
| 	gen->status = CUDD_GEN_EMPTY; | |
|     } else { | |
| 	implicant = Cudd_LargestCube(dd,gen->node,&length); | |
| 	if (implicant == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,gen->node); | |
| 	    FREE(gen->gen.primes.cube); | |
| 	    FREE(gen); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(implicant); | |
| 	prime = Cudd_bddMakePrime(dd,implicant,gen->gen.primes.ub); | |
| 	if (prime == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,gen->node); | |
| 	    Cudd_RecursiveDeref(dd,implicant); | |
| 	    FREE(gen->gen.primes.cube); | |
| 	    FREE(gen); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(prime); | |
| 	Cudd_RecursiveDeref(dd,implicant); | |
| 	tmp = Cudd_bddAnd(dd,gen->node,Cudd_Not(prime)); | |
| 	if (tmp == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,gen->node); | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    FREE(gen->gen.primes.cube); | |
| 	    FREE(gen); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(tmp); | |
| 	Cudd_RecursiveDeref(dd,gen->node); | |
| 	gen->node = tmp; | |
| 	result = Cudd_BddToCubeArray(dd,prime,gen->gen.primes.cube); | |
| 	if (result == 0) { | |
| 	    Cudd_RecursiveDeref(dd,gen->node); | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    FREE(gen->gen.primes.cube); | |
| 	    FREE(gen); | |
| 	    return(NULL); | |
| 	} | |
| 	Cudd_RecursiveDeref(dd,prime); | |
| 	gen->status = CUDD_GEN_NONEMPTY; | |
|     } | |
|     *cube = gen->gen.primes.cube; | |
|     return(gen); | |
| 
 | |
| } /* end of Cudd_FirstPrime */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Generates the next prime of a Boolean function.] | |
|  | |
|   Description [Generates the next cube of a Boolean function, | |
|   using generator gen. Returns 0 if the enumeration is completed; 1 | |
|   otherwise.] | |
|  | |
|   SideEffects [The cube and is returned as side effects. The | |
|   generator is modified.] | |
|  | |
|   SeeAlso     [Cudd_ForeachPrime Cudd_FirstPrime Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_NextCube Cudd_NextNode] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_NextPrime( | |
|   DdGen *gen, | |
|   int **cube) | |
| { | |
|     DdNode *implicant, *prime, *tmp; | |
|     DdManager *dd = gen->manager; | |
|     int length, result; | |
| 
 | |
|     if (gen->node == Cudd_ReadLogicZero(dd)) { | |
| 	gen->status = CUDD_GEN_EMPTY; | |
|     } else { | |
| 	implicant = Cudd_LargestCube(dd,gen->node,&length); | |
| 	if (implicant == NULL) { | |
| 	    gen->status = CUDD_GEN_EMPTY; | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(implicant); | |
| 	prime = Cudd_bddMakePrime(dd,implicant,gen->gen.primes.ub); | |
| 	if (prime == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,implicant); | |
| 	    gen->status = CUDD_GEN_EMPTY; | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(prime); | |
| 	Cudd_RecursiveDeref(dd,implicant); | |
| 	tmp = Cudd_bddAnd(dd,gen->node,Cudd_Not(prime)); | |
| 	if (tmp == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    gen->status = CUDD_GEN_EMPTY; | |
| 	    return(0); | |
| 	} | |
| 	cuddRef(tmp); | |
| 	Cudd_RecursiveDeref(dd,gen->node); | |
| 	gen->node = tmp; | |
| 	result = Cudd_BddToCubeArray(dd,prime,gen->gen.primes.cube); | |
| 	if (result == 0) { | |
| 	    Cudd_RecursiveDeref(dd,prime); | |
| 	    gen->status = CUDD_GEN_EMPTY; | |
| 	    return(0); | |
| 	} | |
| 	Cudd_RecursiveDeref(dd,prime); | |
| 	gen->status = CUDD_GEN_NONEMPTY; | |
|     } | |
|     if (gen->status == CUDD_GEN_EMPTY) return(0); | |
|     *cube = gen->gen.primes.cube; | |
|     return(1); | |
| 
 | |
| } /* end of Cudd_NextPrime */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Computes the cube of an array of BDD variables.] | |
|  | |
|   Description [Computes the cube of an array of BDD variables. If | |
|   non-null, the phase argument indicates which literal of each | |
|   variable should appear in the cube. If phase\[i\] is nonzero, then the | |
|   positive literal is used. If phase is NULL, the cube is positive unate. | |
|   Returns a pointer to the result if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_addComputeCube Cudd_IndicesToCube Cudd_CubeArrayToBdd] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_bddComputeCube( | |
|   DdManager * dd, | |
|   DdNode ** vars, | |
|   int * phase, | |
|   int  n) | |
| { | |
|     DdNode	*cube; | |
|     DdNode	*fn; | |
|     int         i; | |
| 
 | |
|     cube = DD_ONE(dd); | |
|     cuddRef(cube); | |
| 
 | |
|     for (i = n - 1; i >= 0; i--) { | |
| 	if (phase == NULL || phase[i] != 0) { | |
| 	    fn = Cudd_bddAnd(dd,vars[i],cube); | |
| 	} else { | |
| 	    fn = Cudd_bddAnd(dd,Cudd_Not(vars[i]),cube); | |
| 	} | |
| 	if (fn == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(fn); | |
| 	Cudd_RecursiveDeref(dd,cube); | |
| 	cube = fn; | |
|     } | |
|     cuddDeref(cube); | |
| 
 | |
|     return(cube); | |
| 
 | |
| }  /* end of Cudd_bddComputeCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Computes the cube of an array of ADD variables.] | |
|  | |
|   Description [Computes the cube of an array of ADD variables.  If | |
|   non-null, the phase argument indicates which literal of each | |
|   variable should appear in the cube. If phase\[i\] is nonzero, then the | |
|   positive literal is used. If phase is NULL, the cube is positive unate. | |
|   Returns a pointer to the result if successful; NULL otherwise.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso     [Cudd_bddComputeCube] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_addComputeCube( | |
|   DdManager * dd, | |
|   DdNode ** vars, | |
|   int * phase, | |
|   int  n) | |
| { | |
|     DdNode	*cube, *zero; | |
|     DdNode	*fn; | |
|     int         i; | |
| 
 | |
|     cube = DD_ONE(dd); | |
|     cuddRef(cube); | |
|     zero = DD_ZERO(dd); | |
| 
 | |
|     for (i = n - 1; i >= 0; i--) { | |
| 	if (phase == NULL || phase[i] != 0) { | |
| 	    fn = Cudd_addIte(dd,vars[i],cube,zero); | |
| 	} else { | |
| 	    fn = Cudd_addIte(dd,vars[i],zero,cube); | |
| 	} | |
| 	if (fn == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(fn); | |
| 	Cudd_RecursiveDeref(dd,cube); | |
| 	cube = fn; | |
|     } | |
|     cuddDeref(cube); | |
| 
 | |
|     return(cube); | |
| 
 | |
| } /* end of Cudd_addComputeCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Builds the BDD of a cube from a positional array.] | |
|  | |
|   Description [Builds a cube from a positional array.  The array must | |
|   have one integer entry for each BDD variable.  If the i-th entry is | |
|   1, the variable of index i appears in true form in the cube; If the | |
|   i-th entry is 0, the variable of index i appears complemented in the | |
|   cube; otherwise the variable does not appear in the cube.  Returns a | |
|   pointer to the BDD for the cube if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddComputeCube Cudd_IndicesToCube Cudd_BddToCubeArray] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_CubeArrayToBdd( | |
|   DdManager *dd, | |
|   int *array) | |
| { | |
|     DdNode *cube, *var, *tmp; | |
|     int i; | |
|     int size = Cudd_ReadSize(dd); | |
| 
 | |
|     cube = DD_ONE(dd); | |
|     cuddRef(cube); | |
|     for (i = size - 1; i >= 0; i--) { | |
| 	if ((array[i] & ~1) == 0) { | |
| 	    var = Cudd_bddIthVar(dd,i); | |
| 	    tmp = Cudd_bddAnd(dd,cube,Cudd_NotCond(var,array[i]==0)); | |
| 	    if (tmp == NULL) { | |
| 		Cudd_RecursiveDeref(dd,cube); | |
| 		return(NULL); | |
| 	    } | |
| 	    cuddRef(tmp); | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    cube = tmp; | |
| 	} | |
|     } | |
|     cuddDeref(cube); | |
|     return(cube); | |
| 
 | |
| } /* end of Cudd_CubeArrayToBdd */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Builds a positional array from the BDD of a cube.] | |
|  | |
|   Description [Builds a positional array from the BDD of a cube. | |
|   Array must have one entry for each BDD variable.  The positional | |
|   array has 1 in i-th position if the variable of index i appears in | |
|   true form in the cube; it has 0 in i-th position if the variable of | |
|   index i appears in complemented form in the cube; finally, it has 2 | |
|   in i-th position if the variable of index i does not appear in the | |
|   cube.  Returns 1 if successful (the BDD is indeed a cube); 0 | |
|   otherwise.] | |
|  | |
|   SideEffects [The result is in the array passed by reference.] | |
|  | |
|   SeeAlso     [Cudd_CubeArrayToBdd] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_BddToCubeArray( | |
|   DdManager *dd, | |
|   DdNode *cube, | |
|   int *array) | |
| { | |
|     DdNode *scan, *t, *e; | |
|     int i; | |
|     int size = Cudd_ReadSize(dd); | |
|     DdNode *zero = Cudd_Not(DD_ONE(dd)); | |
| 
 | |
|     for (i = size-1; i >= 0; i--) { | |
| 	array[i] = 2; | |
|     } | |
|     scan = cube; | |
|     while (!Cudd_IsConstant(scan)) { | |
| 	int index = Cudd_Regular(scan)->index; | |
| 	cuddGetBranches(scan,&t,&e); | |
| 	if (t == zero) { | |
| 	    array[index] = 0; | |
| 	    scan = e; | |
| 	} else if (e == zero) { | |
| 	    array[index] = 1; | |
| 	    scan = t; | |
| 	} else { | |
| 	    return(0);	/* cube is not a cube */ | |
| 	} | |
|     } | |
|     if (scan == zero) { | |
| 	return(0); | |
|     } else { | |
| 	return(1); | |
|     } | |
| 
 | |
| } /* end of Cudd_BddToCubeArray */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the first node of a decision diagram.] | |
|  | |
|   Description [Defines an iterator on the nodes of a decision diagram | |
|   and finds its first node. Returns a generator that contains the | |
|   information necessary to continue the enumeration if successful; | |
|   NULL otherwise.  The nodes are enumerated in a reverse topological | |
|   order, so that a node is always preceded in the enumeration by its | |
|   descendants.] | |
|  | |
|   SideEffects [The first node is returned as a side effect.] | |
|  | |
|   SeeAlso     [Cudd_ForeachNode Cudd_NextNode Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_FirstCube] | |
|  | |
| ******************************************************************************/ | |
| DdGen * | |
| Cudd_FirstNode( | |
|   DdManager * dd, | |
|   DdNode * f, | |
|   DdNode ** node) | |
| { | |
|     DdGen *gen; | |
|     int size; | |
| 
 | |
|     /* Sanity Check. */ | |
|     if (dd == NULL || f == NULL) return(NULL); | |
| 
 | |
|     /* Allocate generator an initialize it. */ | |
|     gen = ALLOC(DdGen,1); | |
|     if (gen == NULL) { | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     gen->manager = dd; | |
|     gen->type = CUDD_GEN_NODES; | |
|     gen->status = CUDD_GEN_EMPTY; | |
|     gen->stack.sp = 0; | |
|     gen->node = NULL; | |
| 
 | |
|     /* Collect all the nodes on the generator stack for later perusal. */ | |
|     gen->stack.stack = cuddNodeArray(Cudd_Regular(f), &size); | |
|     if (gen->stack.stack == NULL) { | |
| 	FREE(gen); | |
| 	dd->errorCode = CUDD_MEMORY_OUT; | |
| 	return(NULL); | |
|     } | |
|     gen->gen.nodes.size = size; | |
| 
 | |
|     /* Find the first node. */ | |
|     if (gen->stack.sp < gen->gen.nodes.size) { | |
| 	gen->status = CUDD_GEN_NONEMPTY; | |
| 	gen->node = gen->stack.stack[gen->stack.sp]; | |
| 	*node = gen->node; | |
|     } | |
| 
 | |
|     return(gen); | |
| 
 | |
| } /* end of Cudd_FirstNode */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds the next node of a decision diagram.] | |
|  | |
|   Description [Finds the node of a decision diagram, using generator | |
|   gen. Returns 0 if the enumeration is completed; 1 otherwise.] | |
|  | |
|   SideEffects [The next node is returned as a side effect.] | |
|  | |
|   SeeAlso     [Cudd_ForeachNode Cudd_FirstNode Cudd_GenFree Cudd_IsGenEmpty | |
|   Cudd_NextCube] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_NextNode( | |
|   DdGen * gen, | |
|   DdNode ** node) | |
| { | |
|     /* Find the next node. */ | |
|     gen->stack.sp++; | |
|     if (gen->stack.sp < gen->gen.nodes.size) { | |
| 	gen->node = gen->stack.stack[gen->stack.sp]; | |
| 	*node = gen->node; | |
| 	return(1); | |
|     } else { | |
| 	gen->status = CUDD_GEN_EMPTY; | |
| 	return(0); | |
|     } | |
| 
 | |
| } /* end of Cudd_NextNode */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Frees a CUDD generator.] | |
|  | |
|   Description [Frees a CUDD generator. Always returns 0, so that it can | |
|   be used in mis-like foreach constructs.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube | |
|   Cudd_FirstNode Cudd_NextNode Cudd_IsGenEmpty] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_GenFree( | |
|   DdGen * gen) | |
| { | |
|     if (gen == NULL) return(0); | |
|     switch (gen->type) { | |
|     case CUDD_GEN_CUBES: | |
|     case CUDD_GEN_ZDD_PATHS: | |
| 	FREE(gen->gen.cubes.cube); | |
| 	FREE(gen->stack.stack); | |
| 	break; | |
|     case CUDD_GEN_PRIMES: | |
| 	FREE(gen->gen.primes.cube); | |
| 	Cudd_RecursiveDeref(gen->manager,gen->node); | |
| 	break; | |
|     case CUDD_GEN_NODES: | |
| 	FREE(gen->stack.stack); | |
| 	break; | |
|     default: | |
| 	return(0); | |
|     } | |
|     FREE(gen); | |
|     return(0); | |
| 
 | |
| } /* end of Cudd_GenFree */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Queries the status of a generator.] | |
|  | |
|   Description [Queries the status of a generator. Returns 1 if the | |
|   generator is empty or NULL; 0 otherswise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_ForeachCube Cudd_ForeachNode Cudd_FirstCube Cudd_NextCube | |
|   Cudd_FirstNode Cudd_NextNode Cudd_GenFree] | |
|  | |
| ******************************************************************************/ | |
| int | |
| Cudd_IsGenEmpty( | |
|   DdGen * gen) | |
| { | |
|     if (gen == NULL) return(1); | |
|     return(gen->status == CUDD_GEN_EMPTY); | |
| 
 | |
| } /* end of Cudd_IsGenEmpty */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Builds a cube of BDD variables from an array of indices.] | |
|  | |
|   Description [Builds a cube of BDD variables from an array of indices. | |
|   Returns a pointer to the result if successful; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_bddComputeCube Cudd_CubeArrayToBdd] | |
|  | |
| ******************************************************************************/ | |
| DdNode * | |
| Cudd_IndicesToCube( | |
|   DdManager * dd, | |
|   int * array, | |
|   int  n) | |
| { | |
|     DdNode *cube, *tmp; | |
|     int i; | |
| 
 | |
|     cube = DD_ONE(dd); | |
|     cuddRef(cube); | |
|     for (i = n - 1; i >= 0; i--) { | |
| 	tmp = Cudd_bddAnd(dd,Cudd_bddIthVar(dd,array[i]),cube); | |
| 	if (tmp == NULL) { | |
| 	    Cudd_RecursiveDeref(dd,cube); | |
| 	    return(NULL); | |
| 	} | |
| 	cuddRef(tmp); | |
| 	Cudd_RecursiveDeref(dd,cube); | |
| 	cube = tmp; | |
|     } | |
| 
 | |
|     cuddDeref(cube); | |
|     return(cube); | |
| 
 | |
| } /* end of Cudd_IndicesToCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints the package version number.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| void | |
| Cudd_PrintVersion( | |
|   FILE * fp) | |
| { | |
|     (void) fprintf(fp, "%s\n", CUDD_VERSION); | |
| 
 | |
| } /* end of Cudd_PrintVersion */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Computes the average distance between adjacent nodes.] | |
|  | |
|   Description [Computes the average distance between adjacent nodes in | |
|   the manager. Adjacent nodes are node pairs such that the second node | |
|   is the then child, else child, or next node in the collision list.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| double | |
| Cudd_AverageDistance( | |
|   DdManager * dd) | |
| { | |
|     double tetotal, nexttotal; | |
|     double tesubtotal, nextsubtotal; | |
|     double temeasured, nextmeasured; | |
|     int i, j; | |
|     int slots, nvars; | |
|     long diff; | |
|     DdNode *scan; | |
|     DdNodePtr *nodelist; | |
|     DdNode *sentinel = &(dd->sentinel); | |
| 
 | |
|     nvars = dd->size; | |
|     if (nvars == 0) return(0.0); | |
| 
 | |
|     /* Initialize totals. */ | |
|     tetotal = 0.0; | |
|     nexttotal = 0.0; | |
|     temeasured = 0.0; | |
|     nextmeasured = 0.0; | |
| 
 | |
|     /* Scan the variable subtables. */ | |
|     for (i = 0; i < nvars; i++) { | |
| 	nodelist = dd->subtables[i].nodelist; | |
| 	tesubtotal = 0.0; | |
| 	nextsubtotal = 0.0; | |
| 	slots = dd->subtables[i].slots; | |
| 	for (j = 0; j < slots; j++) { | |
| 	    scan = nodelist[j]; | |
| 	    while (scan != sentinel) { | |
| 		diff = (long) scan - (long) cuddT(scan); | |
| 		tesubtotal += (double) ddAbs(diff); | |
| 		diff = (long) scan - (long) Cudd_Regular(cuddE(scan)); | |
| 		tesubtotal += (double) ddAbs(diff); | |
| 		temeasured += 2.0; | |
| 		if (scan->next != sentinel) { | |
| 		    diff = (long) scan - (long) scan->next; | |
| 		    nextsubtotal += (double) ddAbs(diff); | |
| 		    nextmeasured += 1.0; | |
| 		} | |
| 		scan = scan->next; | |
| 	    } | |
| 	} | |
| 	tetotal += tesubtotal; | |
| 	nexttotal += nextsubtotal; | |
|     } | |
| 
 | |
|     /* Scan the constant table. */ | |
|     nodelist = dd->constants.nodelist; | |
|     nextsubtotal = 0.0; | |
|     slots = dd->constants.slots; | |
|     for (j = 0; j < slots; j++) { | |
| 	scan = nodelist[j]; | |
| 	while (scan != NULL) { | |
| 	    if (scan->next != NULL) { | |
| 		diff = (long) scan - (long) scan->next; | |
| 		nextsubtotal += (double) ddAbs(diff); | |
| 		nextmeasured += 1.0; | |
| 	    } | |
| 	    scan = scan->next; | |
| 	} | |
|     } | |
|     nexttotal += nextsubtotal; | |
| 
 | |
|     return((tetotal + nexttotal) / (temeasured + nextmeasured)); | |
| 
 | |
| } /* end of Cudd_AverageDistance */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Portable random number generator.] | |
|  | |
|   Description [Portable number generator based on ran2 from "Numerical | |
|   Recipes in C." It is a long period (> 2 * 10^18) random number generator | |
|   of L'Ecuyer with Bays-Durham shuffle. Returns a long integer uniformly | |
|   distributed between 0 and 2147483561 (inclusive of the endpoint values). | |
|   The random generator can be explicitly initialized by calling | |
|   Cudd_Srandom. If no explicit initialization is performed, then the | |
|   seed 1 is assumed.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_Srandom] | |
|  | |
| ******************************************************************************/ | |
| long | |
| Cudd_Random(void) | |
| { | |
|     int i;	/* index in the shuffle table */ | |
|     long int w; /* work variable */ | |
| 
 | |
|     /* cuddRand == 0 if the geneartor has not been initialized yet. */ | |
|     if (cuddRand == 0) Cudd_Srandom(1); | |
| 
 | |
|     /* Compute cuddRand = (cuddRand * LEQA1) % MODULUS1 avoiding | |
|     ** overflows by Schrage's method. | |
|     */ | |
|     w          = cuddRand / LEQQ1; | |
|     cuddRand   = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1; | |
|     cuddRand  += (cuddRand < 0) * MODULUS1; | |
| 
 | |
|     /* Compute cuddRand2 = (cuddRand2 * LEQA2) % MODULUS2 avoiding | |
|     ** overflows by Schrage's method. | |
|     */ | |
|     w          = cuddRand2 / LEQQ2; | |
|     cuddRand2  = LEQA2 * (cuddRand2 - w * LEQQ2) - w * LEQR2; | |
|     cuddRand2 += (cuddRand2 < 0) * MODULUS2; | |
| 
 | |
|     /* cuddRand is shuffled with the Bays-Durham algorithm. | |
|     ** shuffleSelect and cuddRand2 are combined to generate the output. | |
|     */ | |
| 
 | |
|     /* Pick one element from the shuffle table; "i" will be in the range | |
|     ** from 0 to STAB_SIZE-1. | |
|     */ | |
|     i = (int) (shuffleSelect / STAB_DIV); | |
|     /* Mix the element of the shuffle table with the current iterate of | |
|     ** the second sub-generator, and replace the chosen element of the | |
|     ** shuffle table with the current iterate of the first sub-generator. | |
|     */ | |
|     shuffleSelect   = shuffleTable[i] - cuddRand2; | |
|     shuffleTable[i] = cuddRand; | |
|     shuffleSelect  += (shuffleSelect < 1) * (MODULUS1 - 1); | |
|     /* Since shuffleSelect != 0, and we want to be able to return 0, | |
|     ** here we subtract 1 before returning. | |
|     */ | |
|     return(shuffleSelect - 1); | |
| 
 | |
| } /* end of Cudd_Random */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Initializer for the portable random number generator.] | |
|  | |
|   Description [Initializer for the portable number generator based on | |
|   ran2 in "Numerical Recipes in C." The input is the seed for the | |
|   generator. If it is negative, its absolute value is taken as seed. | |
|   If it is 0, then 1 is taken as seed. The initialized sets up the two | |
|   recurrences used to generate a long-period stream, and sets up the | |
|   shuffle table.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_Random] | |
|  | |
| ******************************************************************************/ | |
| void | |
| Cudd_Srandom( | |
|   long  seed) | |
| { | |
|     int i; | |
| 
 | |
|     if (seed < 0)       cuddRand = -seed; | |
|     else if (seed == 0) cuddRand = 1; | |
|     else                cuddRand = seed; | |
|     cuddRand2 = cuddRand; | |
|     /* Load the shuffle table (after 11 warm-ups). */ | |
|     for (i = 0; i < STAB_SIZE + 11; i++) { | |
| 	long int w; | |
| 	w = cuddRand / LEQQ1; | |
| 	cuddRand = LEQA1 * (cuddRand - w * LEQQ1) - w * LEQR1; | |
| 	cuddRand += (cuddRand < 0) * MODULUS1; | |
| 	shuffleTable[i % STAB_SIZE] = cuddRand; | |
|     } | |
|     shuffleSelect = shuffleTable[1 % STAB_SIZE]; | |
| 
 | |
| } /* end of Cudd_Srandom */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Computes the density of a BDD or ADD.] | |
|  | |
|   Description [Computes the density of a BDD or ADD. The density is | |
|   the ratio of the number of minterms to the number of nodes. If 0 is | |
|   passed as number of variables, the number of variables existing in | |
|   the manager is used. Returns the density if successful; (double) | |
|   CUDD_OUT_OF_MEM otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_CountMinterm Cudd_DagSize] | |
|  | |
| ******************************************************************************/ | |
| double | |
| Cudd_Density( | |
|   DdManager * dd /* manager */, | |
|   DdNode * f /* function whose density is sought */, | |
|   int  nvars /* size of the support of f */) | |
| { | |
|     double minterms; | |
|     int nodes; | |
|     double density; | |
| 
 | |
|     if (nvars == 0) nvars = dd->size; | |
|     minterms = Cudd_CountMinterm(dd,f,nvars); | |
|     if (minterms == (double) CUDD_OUT_OF_MEM) return(minterms); | |
|     nodes = Cudd_DagSize(f); | |
|     density = minterms / (double) nodes; | |
|     return(density); | |
| 
 | |
| } /* end of Cudd_Density */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Warns that a memory allocation failed.] | |
|  | |
|   Description [Warns that a memory allocation failed. | |
|   This function can be used as replacement of MMout_of_memory to prevent | |
|   the safe_mem functions of the util package from exiting when malloc | |
|   returns NULL. One possible use is in case of discretionary allocations; | |
|   for instance, the allocation of memory to enlarge the computed table.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| void | |
| Cudd_OutOfMem( | |
|   long size /* size of the allocation that failed */) | |
| { | |
|     (void) fflush(stdout); | |
|     (void) fprintf(stderr, "\nunable to allocate %ld bytes\n", size); | |
|     return; | |
| 
 | |
| } /* end of Cudd_OutOfMem */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of internal functions                                          */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Prints a DD to the standard output. One line per node is | |
|   printed.] | |
|  | |
|   Description [Prints a DD to the standard output. One line per node is | |
|   printed. Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_PrintDebug] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddP( | |
|   DdManager * dd, | |
|   DdNode * f) | |
| { | |
|     int retval; | |
|     st_table *table = st_init_table(st_ptrcmp,st_ptrhash); | |
| 
 | |
|     if (table == NULL) return(0); | |
| 
 | |
|     retval = dp2(dd,f,table); | |
|     st_free_table(table); | |
|     (void) fputc('\n',dd->out); | |
|     return(retval); | |
| 
 | |
| } /* end of cuddP */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Frees the memory used to store the minterm counts recorded | |
|   in the visited table.] | |
|  | |
|   Description [Frees the memory used to store the minterm counts | |
|   recorded in the visited table. Returns ST_CONTINUE.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| enum st_retval | |
| cuddStCountfree( | |
|   char * key, | |
|   char * value, | |
|   char * arg) | |
| { | |
|     double	*d; | |
| 
 | |
|     d = (double *)value; | |
|     FREE(d); | |
|     return(ST_CONTINUE); | |
| 
 | |
| } /* end of cuddStCountfree */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Recursively collects all the nodes of a DD in a symbol | |
|   table.] | |
|  | |
|   Description [Traverses the DD f and collects all its nodes in a | |
|   symbol table.  f is assumed to be a regular pointer and | |
|   cuddCollectNodes guarantees this assumption in the recursive calls. | |
|   Returns 1 in case of success; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| int | |
| cuddCollectNodes( | |
|   DdNode * f, | |
|   st_table * visited) | |
| { | |
|     DdNode	*T, *E; | |
|     int		retval; | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(!Cudd_IsComplement(f)); | |
| #endif | |
|  | |
|     /* If already visited, nothing to do. */ | |
|     if (st_is_member(visited, (char *) f) == 1) | |
| 	return(1); | |
| 
 | |
|     /* Check for abnormal condition that should never happen. */ | |
|     if (f == NULL) | |
| 	return(0); | |
| 
 | |
|     /* Mark node as visited. */ | |
|     if (st_add_direct(visited, (char *) f, NULL) == ST_OUT_OF_MEM) | |
| 	return(0); | |
| 
 | |
|     /* Check terminal case. */ | |
|     if (cuddIsConstant(f)) | |
| 	return(1); | |
| 
 | |
|     /* Recursive calls. */ | |
|     T = cuddT(f); | |
|     retval = cuddCollectNodes(T,visited); | |
|     if (retval != 1) return(retval); | |
|     E = Cudd_Regular(cuddE(f)); | |
|     retval = cuddCollectNodes(E,visited); | |
|     return(retval); | |
| 
 | |
| } /* end of cuddCollectNodes */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Recursively collects all the nodes of a DD in an array.] | |
|  | |
|   Description [Traverses the DD f and collects all its nodes in an array. | |
|   The caller should free the array returned by cuddNodeArray. | |
|   Returns a pointer to the array of nodes in case of success; NULL | |
|   otherwise.  The nodes are collected in reverse topological order, so | |
|   that a node is always preceded in the array by all its descendants.] | |
|  | |
|   SideEffects [The number of nodes is returned as a side effect.] | |
|  | |
|   SeeAlso     [Cudd_FirstNode] | |
|  | |
| ******************************************************************************/ | |
| DdNodePtr * | |
| cuddNodeArray( | |
|   DdNode *f, | |
|   int *n) | |
| { | |
|     DdNodePtr *table; | |
|     int size, retval; | |
| 
 | |
|     size = ddDagInt(Cudd_Regular(f)); | |
|     table = ALLOC(DdNodePtr, size); | |
|     if (table == NULL) { | |
| 	ddClearFlag(Cudd_Regular(f)); | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     retval = cuddNodeArrayRecur(f, table, 0); | |
|     assert(retval == size); | |
| 
 | |
|     *n = size; | |
|     return(table); | |
| 
 | |
| } /* cuddNodeArray */ | |
| 
 | |
| 
 | |
| /*---------------------------------------------------------------------------*/ | |
| /* Definition of static functions                                            */ | |
| /*---------------------------------------------------------------------------*/ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of cuddP.] | |
|  | |
|   Description [Performs the recursive step of cuddP. Returns 1 in case | |
|   of success; 0 otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| dp2( | |
|   DdManager *dd, | |
|   DdNode * f, | |
|   st_table * t) | |
| { | |
|     DdNode *g, *n, *N; | |
|     int T,E; | |
| 
 | |
|     if (f == NULL) { | |
| 	return(0); | |
|     } | |
|     g = Cudd_Regular(f); | |
|     if (cuddIsConstant(g)) { | |
| #if SIZEOF_VOID_P == 8 | |
| 	(void) fprintf(dd->out,"ID = %c0x%lx\tvalue = %-9g\n", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode),cuddV(g)); | |
| #else | |
| 	(void) fprintf(dd->out,"ID = %c0x%x\tvalue = %-9g\n", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode),cuddV(g)); | |
| #endif | |
| 	return(1); | |
|     } | |
|     if (st_is_member(t,(char *) g) == 1) { | |
| 	return(1); | |
|     } | |
|     if (st_add_direct(t,(char *) g,NULL) == ST_OUT_OF_MEM) | |
| 	return(0); | |
| #ifdef DD_STATS | |
| #if SIZEOF_VOID_P == 8 | |
|     (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %d\tr = %d\t", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode), g->index, g->ref); | |
| #else | |
|     (void) fprintf(dd->out,"ID = %c0x%x\tindex = %d\tr = %d\t", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode),g->index,g->ref); | |
| #endif | |
| #else | |
| #if SIZEOF_VOID_P == 8 | |
|     (void) fprintf(dd->out,"ID = %c0x%lx\tindex = %u\t", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode),g->index); | |
| #else | |
|     (void) fprintf(dd->out,"ID = %c0x%x\tindex = %hu\t", bang(f), | |
| 		(ptruint) g / (ptruint) sizeof(DdNode),g->index); | |
| #endif | |
| #endif | |
|     n = cuddT(g); | |
|     if (cuddIsConstant(n)) { | |
| 	(void) fprintf(dd->out,"T = %-9g\t",cuddV(n)); | |
| 	T = 1; | |
|     } else { | |
| #if SIZEOF_VOID_P == 8 | |
| 	(void) fprintf(dd->out,"T = 0x%lx\t",(ptruint) n / (ptruint) sizeof(DdNode)); | |
| #else | |
| 	(void) fprintf(dd->out,"T = 0x%x\t",(ptruint) n / (ptruint) sizeof(DdNode)); | |
| #endif | |
| 	T = 0; | |
|     } | |
| 
 | |
|     n = cuddE(g); | |
|     N = Cudd_Regular(n); | |
|     if (cuddIsConstant(N)) { | |
| 	(void) fprintf(dd->out,"E = %c%-9g\n",bang(n),cuddV(N)); | |
| 	E = 1; | |
|     } else { | |
| #if SIZEOF_VOID_P == 8 | |
| 	(void) fprintf(dd->out,"E = %c0x%lx\n", bang(n), (ptruint) N/(ptruint) sizeof(DdNode)); | |
| #else | |
| 	(void) fprintf(dd->out,"E = %c0x%x\n", bang(n), (ptruint) N/(ptruint) sizeof(DdNode)); | |
| #endif | |
| 	E = 0; | |
|     } | |
|     if (E == 0) { | |
| 	if (dp2(dd,N,t) == 0) | |
| 	    return(0); | |
|     } | |
|     if (T == 0) { | |
| 	if (dp2(dd,cuddT(g),t) == 0) | |
| 	    return(0); | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of dp2 */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_PrintMinterm.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddPrintMintermAux( | |
|   DdManager * dd /* manager */, | |
|   DdNode * node /* current node */, | |
|   int * list /* current recursion path */) | |
| { | |
|     DdNode	*N,*Nv,*Nnv; | |
|     int		i,v,index; | |
| 
 | |
|     N = Cudd_Regular(node); | |
| 
 | |
|     if (cuddIsConstant(N)) { | |
| 	/* Terminal case: Print one cube based on the current recursion | |
| 	** path, unless we have reached the background value (ADDs) or | |
| 	** the logical zero (BDDs). | |
| 	*/ | |
| 	if (node != background && node != zero) { | |
| 	    for (i = 0; i < dd->size; i++) { | |
| 		v = list[i]; | |
| 		if (v == 0) (void) fprintf(dd->out,"0"); | |
| 		else if (v == 1) (void) fprintf(dd->out,"1"); | |
| 		else (void) fprintf(dd->out,"-"); | |
| 	    } | |
| 	    (void) fprintf(dd->out," % g\n", cuddV(node)); | |
| 	} | |
|     } else { | |
| 	Nv  = cuddT(N); | |
| 	Nnv = cuddE(N); | |
| 	if (Cudd_IsComplement(node)) { | |
| 	    Nv  = Cudd_Not(Nv); | |
| 	    Nnv = Cudd_Not(Nnv); | |
| 	} | |
| 	index = N->index; | |
| 	list[index] = 0; | |
| 	ddPrintMintermAux(dd,Nnv,list); | |
| 	list[index] = 1; | |
| 	ddPrintMintermAux(dd,Nv,list); | |
| 	list[index] = 2; | |
|     } | |
|     return; | |
| 
 | |
| } /* end of ddPrintMintermAux */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_DagSize.] | |
|  | |
|   Description [Performs the recursive step of Cudd_DagSize. Returns the | |
|   number of nodes in the graph rooted at n.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddDagInt( | |
|   DdNode * n) | |
| { | |
|     int tval, eval; | |
| 
 | |
|     if (Cudd_IsComplement(n->next)) { | |
| 	return(0); | |
|     } | |
|     n->next = Cudd_Not(n->next); | |
|     if (cuddIsConstant(n)) { | |
| 	return(1); | |
|     } | |
|     tval = ddDagInt(cuddT(n)); | |
|     eval = ddDagInt(Cudd_Regular(cuddE(n))); | |
|     return(1 + tval + eval); | |
| 
 | |
| } /* end of ddDagInt */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of cuddNodeArray.] | |
|  | |
|   Description [Performs the recursive step of cuddNodeArray.  Returns | |
|   an the number of nodes in the DD.  Clear the least significant bit | |
|   of the next field that was used as visited flag by | |
|   cuddNodeArrayRecur when counting the nodes.  node is supposed to be | |
|   regular; the invariant is maintained by this procedure.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| cuddNodeArrayRecur( | |
|   DdNode *f, | |
|   DdNodePtr *table, | |
|   int index) | |
| { | |
|     int tindex, eindex; | |
| 
 | |
|     if (!Cudd_IsComplement(f->next)) { | |
| 	return(index); | |
|     } | |
|     /* Clear visited flag. */ | |
|     f->next = Cudd_Regular(f->next); | |
|     if (cuddIsConstant(f)) { | |
| 	table[index] = f; | |
| 	return(index + 1); | |
|     } | |
|     tindex = cuddNodeArrayRecur(cuddT(f), table, index); | |
|     eindex = cuddNodeArrayRecur(Cudd_Regular(cuddE(f)), table, tindex); | |
|     table[eindex] = f; | |
|     return(eindex + 1); | |
| 
 | |
| } /* end of cuddNodeArrayRecur */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CofactorEstimate.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CofactorEstimate. | |
|   Returns an estimate of the number of nodes in the DD of a | |
|   cofactor of node. Uses the least significant bit of the next field as | |
|   visited flag. node is supposed to be regular; the invariant is maintained | |
|   by this procedure.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| cuddEstimateCofactor( | |
|   DdManager *dd, | |
|   st_table *table, | |
|   DdNode * node, | |
|   int i, | |
|   int phase, | |
|   DdNode ** ptr) | |
| { | |
|     int tval, eval, val; | |
|     DdNode *ptrT, *ptrE; | |
| 
 | |
|     if (Cudd_IsComplement(node->next)) { | |
| 	if (!st_lookup(table,(char *)node,(char **)ptr)) { | |
| 	    if (st_add_direct(table,(char *)node,(char *)node) == | |
| 		ST_OUT_OF_MEM) | |
| 		return(CUDD_OUT_OF_MEM); | |
| 	    *ptr = node; | |
| 	} | |
| 	return(0); | |
|     } | |
|     node->next = Cudd_Not(node->next); | |
|     if (cuddIsConstant(node)) { | |
| 	*ptr = node; | |
| 	if (st_add_direct(table,(char *)node,(char *)node) == ST_OUT_OF_MEM) | |
| 	    return(CUDD_OUT_OF_MEM); | |
| 	return(1); | |
|     } | |
|     if ((int) node->index == i) { | |
| 	if (phase == 1) { | |
| 	    *ptr = cuddT(node); | |
| 	    val = ddDagInt(cuddT(node)); | |
| 	} else { | |
| 	    *ptr = cuddE(node); | |
| 	    val = ddDagInt(Cudd_Regular(cuddE(node))); | |
| 	} | |
| 	if (node->ref > 1) { | |
| 	    if (st_add_direct(table,(char *)node,(char *)*ptr) == | |
| 		ST_OUT_OF_MEM) | |
| 		return(CUDD_OUT_OF_MEM); | |
| 	} | |
| 	return(val); | |
|     } | |
|     if (dd->perm[node->index] > dd->perm[i]) { | |
| 	*ptr = node; | |
| 	tval = ddDagInt(cuddT(node)); | |
| 	eval = ddDagInt(Cudd_Regular(cuddE(node))); | |
| 	if (node->ref > 1) { | |
| 	    if (st_add_direct(table,(char *)node,(char *)node) == | |
| 		ST_OUT_OF_MEM) | |
| 		return(CUDD_OUT_OF_MEM); | |
| 	} | |
| 	val = 1 + tval + eval; | |
| 	return(val); | |
|     } | |
|     tval = cuddEstimateCofactor(dd,table,cuddT(node),i,phase,&ptrT); | |
|     eval = cuddEstimateCofactor(dd,table,Cudd_Regular(cuddE(node)),i, | |
| 				phase,&ptrE); | |
|     ptrE = Cudd_NotCond(ptrE,Cudd_IsComplement(cuddE(node))); | |
|     if (ptrT == ptrE) {		/* recombination */ | |
| 	*ptr = ptrT; | |
| 	val = tval; | |
| 	if (node->ref > 1) { | |
| 	    if (st_add_direct(table,(char *)node,(char *)*ptr) == | |
| 		    ST_OUT_OF_MEM) | |
| 		return(CUDD_OUT_OF_MEM); | |
| 	} | |
|     } else if ((ptrT != cuddT(node) || ptrE != cuddE(node)) && | |
| 	       (*ptr = cuddUniqueLookup(dd,node->index,ptrT,ptrE)) != NULL) { | |
| 	if (Cudd_IsComplement((*ptr)->next)) { | |
| 	    val = 0; | |
| 	} else { | |
| 	    val = 1 + tval + eval; | |
| 	} | |
| 	if (node->ref > 1) { | |
| 	    if (st_add_direct(table,(char *)node,(char *)*ptr) == | |
| 		    ST_OUT_OF_MEM) | |
| 		return(CUDD_OUT_OF_MEM); | |
| 	} | |
|     } else { | |
| 	*ptr = node; | |
| 	val = 1 + tval + eval; | |
|     } | |
|     return(val); | |
| 
 | |
| } /* end of cuddEstimateCofactor */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Checks the unique table for the existence of an internal node.] | |
|  | |
|   Description [Checks the unique table for the existence of an internal | |
|   node. Returns a pointer to the node if it is in the table; NULL otherwise.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [cuddUniqueInter] | |
|  | |
| ******************************************************************************/ | |
| static DdNode * | |
| cuddUniqueLookup( | |
|   DdManager * unique, | |
|   int  index, | |
|   DdNode * T, | |
|   DdNode * E) | |
| { | |
|     int posn; | |
|     unsigned int level; | |
|     DdNodePtr *nodelist; | |
|     DdNode *looking; | |
|     DdSubtable *subtable; | |
| 
 | |
|     if (index >= unique->size) { | |
| 	return(NULL); | |
|     } | |
| 
 | |
|     level = unique->perm[index]; | |
|     subtable = &(unique->subtables[level]); | |
| 
 | |
| #ifdef DD_DEBUG | |
|     assert(level < (unsigned) cuddI(unique,T->index)); | |
|     assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index)); | |
| #endif | |
|  | |
|     posn = ddHash(T, E, subtable->shift); | |
|     nodelist = subtable->nodelist; | |
|     looking = nodelist[posn]; | |
| 
 | |
|     while (T < cuddT(looking)) { | |
| 	looking = Cudd_Regular(looking->next); | |
|     } | |
|     while (T == cuddT(looking) && E < cuddE(looking)) { | |
| 	looking = Cudd_Regular(looking->next); | |
|     } | |
|     if (cuddT(looking) == T && cuddE(looking) == E) { | |
| 	return(looking); | |
|     } | |
| 
 | |
|     return(NULL); | |
| 
 | |
| } /* end of cuddUniqueLookup */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CofactorEstimateSimple.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CofactorEstimateSimple. | |
|   Returns an estimate of the number of nodes in the DD of the positive | |
|   cofactor of node. Uses the least significant bit of the next field as | |
|   visited flag. node is supposed to be regular; the invariant is maintained | |
|   by this procedure.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| cuddEstimateCofactorSimple( | |
|   DdNode * node, | |
|   int i) | |
| { | |
|     int tval, eval; | |
| 
 | |
|     if (Cudd_IsComplement(node->next)) { | |
| 	return(0); | |
|     } | |
|     node->next = Cudd_Not(node->next); | |
|     if (cuddIsConstant(node)) { | |
| 	return(1); | |
|     } | |
|     tval = cuddEstimateCofactorSimple(cuddT(node),i); | |
|     if ((int) node->index == i) return(tval); | |
|     eval = cuddEstimateCofactorSimple(Cudd_Regular(cuddE(node)),i); | |
|     return(1 + tval + eval); | |
| 
 | |
| } /* end of cuddEstimateCofactorSimple */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CountMinterm.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CountMinterm. | |
|   It is based on the following identity. Let |f| be the | |
|   number of minterms of f. Then: | |
|   <xmp> | |
|     |f| = (|f0|+|f1|)/2 | |
|   </xmp> | |
|   where f0 and f1 are the two cofactors of f.  Does not use the | |
|   identity |f'| = max - |f|, to minimize loss of accuracy due to | |
|   roundoff.  Returns the number of minterms of the function rooted at | |
|   node.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static double | |
| ddCountMintermAux( | |
|   DdNode * node, | |
|   double  max, | |
|   DdHashTable * table) | |
| { | |
|     DdNode	*N, *Nt, *Ne; | |
|     double	min, minT, minE; | |
|     DdNode	*res; | |
| 
 | |
|     N = Cudd_Regular(node); | |
| 
 | |
|     if (cuddIsConstant(N)) { | |
| 	if (node == background || node == zero) { | |
| 	    return(0.0); | |
| 	} else { | |
| 	    return(max); | |
| 	} | |
|     } | |
|     if (N->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) { | |
| 	min = cuddV(res); | |
| 	if (res->ref == 0) { | |
| 	    table->manager->dead++; | |
| 	    table->manager->constants.dead++; | |
| 	} | |
| 	return(min); | |
|     } | |
| 
 | |
|     Nt = cuddT(N); Ne = cuddE(N); | |
|     if (Cudd_IsComplement(node)) { | |
| 	Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne); | |
|     } | |
| 
 | |
|     minT = ddCountMintermAux(Nt,max,table); | |
|     if (minT == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     minT *= 0.5; | |
|     minE = ddCountMintermAux(Ne,max,table); | |
|     if (minE == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     minE *= 0.5; | |
|     min = minT + minE; | |
| 
 | |
|     if (N->ref != 1) { | |
| 	ptrint fanout = (ptrint) N->ref; | |
| 	cuddSatDec(fanout); | |
| 	res = cuddUniqueConst(table->manager,min); | |
| 	if (!cuddHashTableInsert1(table,node,res,fanout)) { | |
| 	    cuddRef(res); Cudd_RecursiveDeref(table->manager, res); | |
| 	    return((double)CUDD_OUT_OF_MEM); | |
| 	} | |
|     } | |
| 
 | |
|     return(min); | |
| 
 | |
| } /* end of ddCountMintermAux */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CountPath.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CountPath. | |
|   It is based on the following identity. Let |f| be the | |
|   number of paths of f. Then: | |
|   <xmp> | |
|     |f| = |f0|+|f1| | |
|   </xmp> | |
|   where f0 and f1 are the two cofactors of f.  Uses the | |
|   identity |f'| = |f|, to improve the utilization of the (local) cache. | |
|   Returns the number of paths of the function rooted at node.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static double | |
| ddCountPathAux( | |
|   DdNode * node, | |
|   st_table * table) | |
| { | |
| 
 | |
|     DdNode	*Nv, *Nnv; | |
|     double	paths, *ppaths, paths1, paths2; | |
|     double	*dummy; | |
| 
 | |
| 
 | |
|     if (cuddIsConstant(node)) { | |
| 	return(1.0); | |
|     } | |
|     if (st_lookup(table, node, &dummy)) { | |
| 	paths = *dummy; | |
| 	return(paths); | |
|     } | |
| 
 | |
|     Nv = cuddT(node); Nnv = cuddE(node); | |
| 
 | |
|     paths1 = ddCountPathAux(Nv,table); | |
|     if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     paths2 = ddCountPathAux(Cudd_Regular(Nnv),table); | |
|     if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     paths = paths1 + paths2; | |
| 
 | |
|     ppaths = ALLOC(double,1); | |
|     if (ppaths == NULL) { | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
| 
 | |
|     *ppaths = paths; | |
| 
 | |
|     if (st_add_direct(table,(char *)node, (char *)ppaths) == ST_OUT_OF_MEM) { | |
| 	FREE(ppaths); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     return(paths); | |
| 
 | |
| } /* end of ddCountPathAux */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_EpdCountMinterm.] | |
|  | |
|   Description [Performs the recursive step of Cudd_EpdCountMinterm. | |
|   It is based on the following identity. Let |f| be the | |
|   number of minterms of f. Then: | |
|   <xmp> | |
|     |f| = (|f0|+|f1|)/2 | |
|   </xmp> | |
|   where f0 and f1 are the two cofactors of f.  Does not use the | |
|   identity |f'| = max - |f|, to minimize loss of accuracy due to | |
|   roundoff.  Returns the number of minterms of the function rooted at | |
|   node.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddEpdCountMintermAux( | |
|   DdNode * node, | |
|   EpDouble * max, | |
|   EpDouble * epd, | |
|   st_table * table) | |
| { | |
|     DdNode	*Nt, *Ne; | |
|     EpDouble	*min, minT, minE; | |
|     EpDouble	*res; | |
|     int		status; | |
| 
 | |
|     /* node is assumed to be regular */ | |
|     if (cuddIsConstant(node)) { | |
| 	if (node == background || node == zero) { | |
| 	    EpdMakeZero(epd, 0); | |
| 	} else { | |
| 	    EpdCopy(max, epd); | |
| 	} | |
| 	return(0); | |
|     } | |
|     if (node->ref != 1 && st_lookup(table, node, &res)) { | |
| 	EpdCopy(res, epd); | |
| 	return(0); | |
|     } | |
| 
 | |
|     Nt = cuddT(node); Ne = cuddE(node); | |
| 
 | |
|     status = ddEpdCountMintermAux(Nt,max,&minT,table); | |
|     if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); | |
|     EpdMultiply(&minT, (double)0.5); | |
|     status = ddEpdCountMintermAux(Cudd_Regular(Ne),max,&minE,table); | |
|     if (status == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); | |
|     if (Cudd_IsComplement(Ne)) { | |
| 	EpdSubtract3(max, &minE, epd); | |
| 	EpdCopy(epd, &minE); | |
|     } | |
|     EpdMultiply(&minE, (double)0.5); | |
|     EpdAdd3(&minT, &minE, epd); | |
| 
 | |
|     if (node->ref > 1) { | |
| 	min = EpdAlloc(); | |
| 	if (!min) | |
| 	    return(CUDD_OUT_OF_MEM); | |
| 	EpdCopy(epd, min); | |
| 	if (st_insert(table, (char *)node, (char *)min) == ST_OUT_OF_MEM) { | |
| 	    EpdFree(min); | |
| 	    return(CUDD_OUT_OF_MEM); | |
| 	} | |
|     } | |
| 
 | |
|     return(0); | |
| 
 | |
| } /* end of ddEpdCountMintermAux */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CountPathsToNonZero.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CountPathsToNonZero. | |
|   It is based on the following identity. Let |f| be the | |
|   number of paths of f. Then: | |
|   <xmp> | |
|     |f| = |f0|+|f1| | |
|   </xmp> | |
|   where f0 and f1 are the two cofactors of f.  Returns the number of | |
|   paths of the function rooted at node.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static double | |
| ddCountPathsToNonZero( | |
|   DdNode * N, | |
|   st_table * table) | |
| { | |
| 
 | |
|     DdNode	*node, *Nt, *Ne; | |
|     double	paths, *ppaths, paths1, paths2; | |
|     double	*dummy; | |
| 
 | |
|     node = Cudd_Regular(N); | |
|     if (cuddIsConstant(node)) { | |
| 	return((double) !(Cudd_IsComplement(N) || cuddV(node)==DD_ZERO_VAL)); | |
|     } | |
|     if (st_lookup(table, N, &dummy)) { | |
| 	paths = *dummy; | |
| 	return(paths); | |
|     } | |
| 
 | |
|     Nt = cuddT(node); Ne = cuddE(node); | |
|     if (node != N) { | |
| 	Nt = Cudd_Not(Nt); Ne = Cudd_Not(Ne); | |
|     } | |
| 
 | |
|     paths1 = ddCountPathsToNonZero(Nt,table); | |
|     if (paths1 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     paths2 = ddCountPathsToNonZero(Ne,table); | |
|     if (paths2 == (double)CUDD_OUT_OF_MEM) return((double)CUDD_OUT_OF_MEM); | |
|     paths = paths1 + paths2; | |
| 
 | |
|     ppaths = ALLOC(double,1); | |
|     if (ppaths == NULL) { | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
| 
 | |
|     *ppaths = paths; | |
| 
 | |
|     if (st_add_direct(table,(char *)N, (char *)ppaths) == ST_OUT_OF_MEM) { | |
| 	FREE(ppaths); | |
| 	return((double)CUDD_OUT_OF_MEM); | |
|     } | |
|     return(paths); | |
| 
 | |
| } /* end of ddCountPathsToNonZero */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_Support.] | |
|  | |
|   Description [Performs the recursive step of Cudd_Support. Performs a | |
|   DFS from f. The support is accumulated in supp as a side effect. Uses | |
|   the LSB of the then pointer as visited flag.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [ddClearFlag] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddSupportStep( | |
|   DdNode * f, | |
|   int * support) | |
| { | |
|     if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) | |
| 	return; | |
| 
 | |
|     support[f->index] = 1; | |
|     ddSupportStep(cuddT(f),support); | |
|     ddSupportStep(Cudd_Regular(cuddE(f)),support); | |
|     /* Mark as visited. */ | |
|     f->next = Cudd_Complement(f->next); | |
| 
 | |
| } /* end of ddSupportStep */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs a DFS from f, clearing the LSB of the next | |
|   pointers.] | |
|  | |
|   Description [] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [ddSupportStep ddFindSupport ddLeavesInt ddDagInt] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddClearFlag( | |
|   DdNode * f) | |
| { | |
|     if (!Cudd_IsComplement(f->next)) { | |
| 	return; | |
|     } | |
|     /* Clear visited flag. */ | |
|     f->next = Cudd_Regular(f->next); | |
|     if (cuddIsConstant(f)) { | |
| 	return; | |
|     } | |
|     ddClearFlag(cuddT(f)); | |
|     ddClearFlag(Cudd_Regular(cuddE(f))); | |
|     return; | |
| 
 | |
| } /* end of ddClearFlag */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_CountLeaves.] | |
|  | |
|   Description [Performs the recursive step of Cudd_CountLeaves. Returns | |
|   the number of leaves in the DD rooted at n.] | |
|  | |
|   SideEffects [None] | |
|  | |
|   SeeAlso     [Cudd_CountLeaves] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddLeavesInt( | |
|   DdNode * n) | |
| { | |
|     int tval, eval; | |
| 
 | |
|     if (Cudd_IsComplement(n->next)) { | |
| 	return(0); | |
|     } | |
|     n->next = Cudd_Not(n->next); | |
|     if (cuddIsConstant(n)) { | |
| 	return(1); | |
|     } | |
|     tval = ddLeavesInt(cuddT(n)); | |
|     eval = ddLeavesInt(Cudd_Regular(cuddE(n))); | |
|     return(tval + eval); | |
| 
 | |
| } /* end of ddLeavesInt */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Performs the recursive step of Cudd_bddPickArbitraryMinterms.] | |
|  | |
|   Description [Performs the recursive step of Cudd_bddPickArbitraryMinterms. | |
|   Returns 1 if successful; 0 otherwise.] | |
|  | |
|   SideEffects [none] | |
|  | |
|   SeeAlso [Cudd_bddPickArbitraryMinterms] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddPickArbitraryMinterms( | |
|   DdManager *dd, | |
|   DdNode *node, | |
|   int nvars, | |
|   int nminterms, | |
|   char **string) | |
| { | |
|     DdNode *N, *T, *E; | |
|     DdNode *one, *bzero; | |
|     int    i, t, result; | |
|     double min1, min2; | |
| 
 | |
|     if (string == NULL || node == NULL) return(0); | |
| 
 | |
|     /* The constant 0 function has no on-set cubes. */ | |
|     one = DD_ONE(dd); | |
|     bzero = Cudd_Not(one); | |
|     if (nminterms == 0 || node == bzero) return(1); | |
|     if (node == one) { | |
| 	return(1); | |
|     } | |
| 
 | |
|     N = Cudd_Regular(node); | |
|     T = cuddT(N); E = cuddE(N); | |
|     if (Cudd_IsComplement(node)) { | |
| 	T = Cudd_Not(T); E = Cudd_Not(E); | |
|     } | |
| 
 | |
|     min1 = Cudd_CountMinterm(dd, T, nvars) / 2.0; | |
|     if (min1 == (double)CUDD_OUT_OF_MEM) return(0); | |
|     min2 = Cudd_CountMinterm(dd, E, nvars) / 2.0; | |
|     if (min2 == (double)CUDD_OUT_OF_MEM) return(0); | |
| 
 | |
|     t = (int)((double)nminterms * min1 / (min1 + min2) + 0.5); | |
|     for (i = 0; i < t; i++) | |
| 	string[i][N->index] = '1'; | |
|     for (i = t; i < nminterms; i++) | |
| 	string[i][N->index] = '0'; | |
| 
 | |
|     result = ddPickArbitraryMinterms(dd,T,nvars,t,&string[0]); | |
|     if (result == 0) | |
| 	return(0); | |
|     result = ddPickArbitraryMinterms(dd,E,nvars,nminterms-t,&string[t]); | |
|     return(result); | |
| 
 | |
| } /* end of ddPickArbitraryMinterms */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis    [Finds a representative cube of a BDD.] | |
|  | |
|   Description [Finds a representative cube of a BDD with the weight of | |
|   each variable. From the top variable, if the weight is greater than or | |
|   equal to 0.0, choose THEN branch unless the child is the constant 0. | |
|   Otherwise, choose ELSE branch unless the child is the constant 0.] | |
|  | |
|   SideEffects [Cudd_SubsetWithMaskVars Cudd_bddPickOneCube] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| ddPickRepresentativeCube( | |
|   DdManager *dd, | |
|   DdNode *node, | |
|   double *weight, | |
|   char *string) | |
| { | |
|     DdNode *N, *T, *E; | |
|     DdNode *one, *bzero; | |
| 
 | |
|     if (string == NULL || node == NULL) return(0); | |
| 
 | |
|     /* The constant 0 function has no on-set cubes. */ | |
|     one = DD_ONE(dd); | |
|     bzero = Cudd_Not(one); | |
|     if (node == bzero) return(0); | |
| 
 | |
|     if (node == DD_ONE(dd)) return(1); | |
| 
 | |
|     for (;;) { | |
| 	N = Cudd_Regular(node); | |
| 	if (N == one) | |
| 	    break; | |
| 	T = cuddT(N); | |
| 	E = cuddE(N); | |
| 	if (Cudd_IsComplement(node)) { | |
| 	    T = Cudd_Not(T); | |
| 	    E = Cudd_Not(E); | |
| 	} | |
| 	if (weight[N->index] >= 0.0) { | |
| 	    if (T == bzero) { | |
| 		node = E; | |
| 		string[N->index] = '0'; | |
| 	    } else { | |
| 		node = T; | |
| 		string[N->index] = '1'; | |
| 	    } | |
| 	} else { | |
| 	    if (E == bzero) { | |
| 		node = T; | |
| 		string[N->index] = '1'; | |
| 	    } else { | |
| 		node = E; | |
| 		string[N->index] = '0'; | |
| 	    } | |
| 	} | |
|     } | |
|     return(1); | |
| 
 | |
| } /* end of ddPickRepresentativeCube */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Frees the memory used to store the minterm counts recorded | |
|   in the visited table.] | |
|  | |
|   Description [Frees the memory used to store the minterm counts | |
|   recorded in the visited table. Returns ST_CONTINUE.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static enum st_retval | |
| ddEpdFree( | |
|   char * key, | |
|   char * value, | |
|   char * arg) | |
| { | |
|     EpDouble	*epd; | |
| 
 | |
|     epd = (EpDouble *) value; | |
|     EpdFree(epd); | |
|     return(ST_CONTINUE); | |
| 
 | |
| } /* end of ddEpdFree */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Recursively find the support of f.] | |
|  | |
|   Description [Recursively find the support of f.  This function uses the | |
|   LSB of the next field of the nodes of f as visited flag.  It also uses the | |
|   LSB of the next field of the variables as flag to remember whether a | |
|   certain index has already been seen.  Finally, it uses the manager stack | |
|   to record all seen indices.] | |
|  | |
|   SideEffects [The stack pointer SP is modified by side-effect.  The next | |
|   fields are changed and need to be reset.] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddFindSupport( | |
|   DdManager *dd, | |
|   DdNode *f, | |
|   int *SP) | |
| { | |
|     int index; | |
|     DdNode *var; | |
| 
 | |
|     if (cuddIsConstant(f) || Cudd_IsComplement(f->next)) { | |
| 	return; | |
|     } | |
| 
 | |
|     index = f->index; | |
|     var = dd->vars[index]; | |
|     /* It is possible that var is embedded in f.  That causes no problem, | |
|     ** though, because if we see it after encountering another node with | |
|     ** the same index, nothing is supposed to happen. | |
|     */ | |
|     if (!Cudd_IsComplement(var->next)) { | |
|         var->next = Cudd_Complement(var->next); | |
|         dd->stack[*SP] = (DdNode *)(ptrint) index; | |
|         (*SP)++; | |
|     } | |
|     ddFindSupport(dd, cuddT(f), SP); | |
|     ddFindSupport(dd, Cudd_Regular(cuddE(f)), SP); | |
|     /* Mark as visited. */ | |
|     f->next = Cudd_Complement(f->next); | |
| 
 | |
| } /* end of ddFindSupport */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Clears visited flags for variables.] | |
|  | |
|   Description [Clears visited flags for variables.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static void | |
| ddClearVars( | |
|   DdManager *dd, | |
|   int SP) | |
| { | |
|     int i; | |
| 
 | |
|     for (i = 0; i < SP; i++) { | |
|         int index = (int) (ptrint) dd->stack[i]; | |
|         DdNode *var = dd->vars[index]; | |
|         var->next = Cudd_Regular(var->next); | |
|     } | |
|      | |
| } /* end of ddClearVars */ | |
| 
 | |
| 
 | |
| /**Function******************************************************************** | |
|  | |
|   Synopsis [Compares indices for qsort.] | |
|  | |
|   Description [Compares indices for qsort.  Subtracting these integers | |
|   cannot produce overflow, because they are non-negative.] | |
|  | |
|   SideEffects [None] | |
|  | |
| ******************************************************************************/ | |
| static int | |
| indexCompare( | |
|   const void *a, | |
|   const void *b) | |
| { | |
|     int ia = *((int *) a); | |
|     int ib = *((int *) b); | |
|     return(ia - ib); | |
| 
 | |
| } /* end of indexCompare */
 |