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.
		
		
		
		
		
			
		
			
				
					
					
						
							1331 lines
						
					
					
						
							40 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1331 lines
						
					
					
						
							40 KiB
						
					
					
				
								/**CFile***********************************************************************
							 | 
						|
								
							 | 
						|
								  FileName    [cuddSubsetHB.c]
							 | 
						|
								
							 | 
						|
								  PackageName [cudd]
							 | 
						|
								
							 | 
						|
								  Synopsis    [Procedure to subset the given BDD by choosing the heavier
							 | 
						|
									       branches.]
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  Description [External procedures provided by this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> Cudd_SubsetHeavyBranch()
							 | 
						|
										<li> Cudd_SupersetHeavyBranch()
							 | 
						|
										</ul>
							 | 
						|
									       Internal procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> cuddSubsetHeavyBranch()
							 | 
						|
										</ul>
							 | 
						|
									       Static procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> ResizeCountMintermPages();
							 | 
						|
										<li> ResizeNodeDataPages()
							 | 
						|
										<li> ResizeCountNodePages()
							 | 
						|
										<li> SubsetCountMintermAux()
							 | 
						|
										<li> SubsetCountMinterm()
							 | 
						|
										<li> SubsetCountNodesAux()
							 | 
						|
										<li> SubsetCountNodes()
							 | 
						|
										<li> BuildSubsetBdd()
							 | 
						|
										</ul>
							 | 
						|
										]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddSubsetSP.c]
							 | 
						|
								
							 | 
						|
								  Author      [Kavita Ravi]
							 | 
						|
								
							 | 
						|
								  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.]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								
							 | 
						|
								#ifdef __STDC__
							 | 
						|
								#include <float.h>
							 | 
						|
								#else
							 | 
						|
								#define DBL_MAX_EXP 1024
							 | 
						|
								#endif
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#define	DEFAULT_PAGE_SIZE 2048
							 | 
						|
								#define	DEFAULT_NODE_DATA_PAGE_SIZE 1024
							 | 
						|
								#define INITIAL_PAGES 128
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/* data structure to store the information on each node. It keeps
							 | 
						|
								 * the number of minterms represented by the DAG rooted at this node
							 | 
						|
								 * in terms of the number of variables specified by the user, number
							 | 
						|
								 * of nodes in this DAG and the number of nodes of its child with
							 | 
						|
								 * lesser number of minterms that are not shared by the child with
							 | 
						|
								 * more minterms
							 | 
						|
								 */
							 | 
						|
								struct NodeData {
							 | 
						|
								    double *mintermPointer;
							 | 
						|
								    int *nodesPointer;
							 | 
						|
								    int *lightChildNodesPointer;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								typedef struct NodeData NodeData_t;
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef lint
							 | 
						|
								static char rcsid[] DD_UNUSED = "$Id: cuddSubsetHB.c,v 1.39 2012/02/05 01:07:19 fabio Exp $";
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								static int memOut;
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								static	int		num_calls;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								static	DdNode	        *zero, *one; /* constant functions */
							 | 
						|
								static	double		**mintermPages;	/* pointers to the pages */
							 | 
						|
								static	int		**nodePages; /* pointers to the pages */
							 | 
						|
								static	int		**lightNodePages; /* pointers to the pages */
							 | 
						|
								static	double		*currentMintermPage; /* pointer to the current
							 | 
						|
														   page */
							 | 
						|
								static  double		max; /* to store the 2^n value of the number
							 | 
						|
											      * of variables */
							 | 
						|
								
							 | 
						|
								static	int		*currentNodePage; /* pointer to the current
							 | 
						|
														   page */
							 | 
						|
								static	int		*currentLightNodePage; /* pointer to the
							 | 
						|
														*  current page */
							 | 
						|
								static	int		pageIndex; /* index to next element */
							 | 
						|
								static	int		page; /* index to current page */
							 | 
						|
								static	int		pageSize = DEFAULT_PAGE_SIZE; /* page size */
							 | 
						|
								static  int             maxPages; /* number of page pointers */
							 | 
						|
								
							 | 
						|
								static	NodeData_t	*currentNodeDataPage; /* pointer to the current
							 | 
						|
														 page */
							 | 
						|
								static	int		nodeDataPage; /* index to next element */
							 | 
						|
								static	int		nodeDataPageIndex; /* index to next element */
							 | 
						|
								static	NodeData_t	**nodeDataPages; /* index to current page */
							 | 
						|
								static	int		nodeDataPageSize = DEFAULT_NODE_DATA_PAGE_SIZE;
							 | 
						|
														     /* page size */
							 | 
						|
								static  int             maxNodeDataPages; /* number of page pointers */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**AutomaticStart*************************************************************/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static void ResizeNodeDataPages (void);
							 | 
						|
								static void ResizeCountMintermPages (void);
							 | 
						|
								static void ResizeCountNodePages (void);
							 | 
						|
								static double SubsetCountMintermAux (DdNode *node, double max, st_table *table);
							 | 
						|
								static st_table * SubsetCountMinterm (DdNode *node, int nvars);
							 | 
						|
								static int SubsetCountNodesAux (DdNode *node, st_table *table, double max);
							 | 
						|
								static int SubsetCountNodes (DdNode *node, st_table *table, int nvars);
							 | 
						|
								static void StoreNodes (st_table *storeTable, DdManager *dd, DdNode *node);
							 | 
						|
								static DdNode * BuildSubsetBdd (DdManager *dd, DdNode *node, int *size, st_table *visitedTable, int threshold, st_table *storeTable, st_table *approxTable);
							 | 
						|
								
							 | 
						|
								/**AutomaticEnd***************************************************************/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense subset from a BDD with the heavy branch
							 | 
						|
								  heuristic.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense subset from a BDD. This procedure
							 | 
						|
								  builds a subset by throwing away one of the children of each node,
							 | 
						|
								  starting from the root, until the result is small enough. The child
							 | 
						|
								  that is eliminated from the result is the one that contributes the
							 | 
						|
								  fewer minterms.  Returns a pointer to the BDD of the subset if
							 | 
						|
								  successful. NULL if the procedure runs out of memory. The parameter
							 | 
						|
								  numVars is the maximum number of variables to be used in minterm
							 | 
						|
								  calculation and node count calculation.  The optimal number should
							 | 
						|
								  be as close as possible to the size of the support of f.  However,
							 | 
						|
								  it is safe to pass the value returned by Cudd_ReadSize for numVars
							 | 
						|
								  when the number of variables is under 1023.  If numVars is larger
							 | 
						|
								  than 1023, it will overflow. If a 0 parameter is passed then the
							 | 
						|
								  procedure will compute a value which will avoid overflow but will
							 | 
						|
								  cause underflow with 2046 variables or more.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_SubsetHeavyBranch(
							 | 
						|
								  DdManager * dd /* manager */,
							 | 
						|
								  DdNode * f /* function to be subset */,
							 | 
						|
								  int  numVars /* number of variables in the support of f */,
							 | 
						|
								  int  threshold /* maximum number of nodes in the subset */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset;
							 | 
						|
								
							 | 
						|
								    memOut = 0;
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetHeavyBranch(dd, f, numVars, threshold);
							 | 
						|
								    } while ((dd->reordered == 1) && (!memOut));
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SubsetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense superset from a BDD with the heavy branch
							 | 
						|
								  heuristic.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense superset from a BDD. The procedure is
							 | 
						|
								  identical to the subset procedure except for the fact that it
							 | 
						|
								  receives the complement of the given function. Extracting the subset
							 | 
						|
								  of the complement function is equivalent to extracting the superset
							 | 
						|
								  of the function. This procedure builds a superset by throwing away
							 | 
						|
								  one of the children of each node starting from the root of the
							 | 
						|
								  complement function, until the result is small enough. The child
							 | 
						|
								  that is eliminated from the result is the one that contributes the
							 | 
						|
								  fewer minterms.
							 | 
						|
								  Returns a pointer to the BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory. The
							 | 
						|
								  parameter numVars is the maximum number of variables to be used in
							 | 
						|
								  minterm calculation and node count calculation.  The optimal number
							 | 
						|
								  should be as close as possible to the size of the support of f.
							 | 
						|
								  However, it is safe to pass the value returned by Cudd_ReadSize for
							 | 
						|
								  numVars when the number of variables is under 1023.  If numVars is
							 | 
						|
								  larger than 1023, it will overflow. If a 0 parameter is passed then
							 | 
						|
								  the procedure will compute a value which will avoid overflow but
							 | 
						|
								  will cause underflow with 2046 variables or more.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SubsetHeavyBranch Cudd_SupersetShortPaths Cudd_ReadSize]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_SupersetHeavyBranch(
							 | 
						|
								  DdManager * dd /* manager */,
							 | 
						|
								  DdNode * f /* function to be superset */,
							 | 
						|
								  int  numVars /* number of variables in the support of f */,
							 | 
						|
								  int  threshold /* maximum number of nodes in the superset */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset, *g;
							 | 
						|
								
							 | 
						|
								    g = Cudd_Not(f);
							 | 
						|
								    memOut = 0;
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetHeavyBranch(dd, g, numVars, threshold);
							 | 
						|
								    } while ((dd->reordered == 1) && (!memOut));
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SupersetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [The main procedure that returns a subset by choosing the heavier
							 | 
						|
								  branch in the BDD.]
							 | 
						|
								
							 | 
						|
								  Description [Here a subset BDD is built by throwing away one of the
							 | 
						|
								  children. Starting at root, annotate each node with the number of
							 | 
						|
								  minterms (in terms of the total number of variables specified -
							 | 
						|
								  numVars), number of nodes taken by the DAG rooted at this node and
							 | 
						|
								  number of additional nodes taken by the child that has the lesser
							 | 
						|
								  minterms. The child with the lower number of minterms is thrown away
							 | 
						|
								  and a dyanmic count of the nodes of the subset is kept. Once the
							 | 
						|
								  threshold is reached the subset is returned to the calling
							 | 
						|
								  procedure.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SubsetHeavyBranch]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddSubsetHeavyBranch(
							 | 
						|
								  DdManager * dd /* DD manager */,
							 | 
						|
								  DdNode * f /* current DD */,
							 | 
						|
								  int  numVars /* maximum number of variables */,
							 | 
						|
								  int  threshold /* threshold size for the subset */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    int i, *size;
							 | 
						|
								    st_table *visitedTable;
							 | 
						|
								    int numNodes;
							 | 
						|
								    NodeData_t *currNodeQual;
							 | 
						|
								    DdNode *subset;
							 | 
						|
								    st_table *storeTable, *approxTable;
							 | 
						|
								    DdNode *key, *value;
							 | 
						|
								    st_generator *stGen;
							 | 
						|
								
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot subset, nil object\n");
							 | 
						|
									dd->errorCode = CUDD_INVALID_ARG;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    one	 = Cudd_ReadOne(dd);
							 | 
						|
								    zero = Cudd_Not(one);
							 | 
						|
								
							 | 
						|
								    /* If user does not know numVars value, set it to the maximum
							 | 
						|
								     * exponent that the pow function can take. The -1 is due to the
							 | 
						|
								     * discrepancy in the value that pow takes and the value that
							 | 
						|
								     * log gives.
							 | 
						|
								     */
							 | 
						|
								    if (numVars == 0) {
							 | 
						|
									/* set default value */
							 | 
						|
									numVars = DBL_MAX_EXP - 1;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstant(f)) {
							 | 
						|
									return(f);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    max = pow(2.0, (double)numVars);
							 | 
						|
								
							 | 
						|
								    /* Create visited table where structures for node data are allocated and
							 | 
						|
								       stored in a st_table */
							 | 
						|
								    visitedTable = SubsetCountMinterm(f, numVars);
							 | 
						|
								    if ((visitedTable == NULL) || memOut) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    numNodes = SubsetCountNodes(f, visitedTable, numVars);
							 | 
						|
								    if (memOut) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (st_lookup(visitedTable, f, &currNodeQual) == 0) {
							 | 
						|
									fprintf(dd->err,
							 | 
						|
										"Something is wrong, ought to be node quality table\n");
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    size = ALLOC(int, 1);
							 | 
						|
								    if (size == NULL) {
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    *size = numNodes;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								    /* table to store nodes being created. */
							 | 
						|
								    storeTable = st_init_table(st_ptrcmp, st_ptrhash);
							 | 
						|
								    /* insert the constant */
							 | 
						|
								    cuddRef(one);
							 | 
						|
								    if (st_insert(storeTable, Cudd_ReadOne(dd), NULL) ==
							 | 
						|
									ST_OUT_OF_MEM) {
							 | 
						|
									fprintf(dd->out, "Something wrong, st_table insert failed\n");
							 | 
						|
								    }
							 | 
						|
								    /* table to store approximations of nodes */
							 | 
						|
								    approxTable = st_init_table(st_ptrcmp, st_ptrhash);
							 | 
						|
								    subset = (DdNode *)BuildSubsetBdd(dd, f, size, visitedTable, threshold,
							 | 
						|
												      storeTable, approxTable);
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddRef(subset);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    stGen = st_init_gen(approxTable);
							 | 
						|
								    if (stGen == NULL) {
							 | 
						|
									st_free_table(approxTable);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    while(st_gen(stGen, &key, &value)) {
							 | 
						|
									Cudd_RecursiveDeref(dd, value);
							 | 
						|
								    }
							 | 
						|
								    st_free_gen(stGen); stGen = NULL;
							 | 
						|
								    st_free_table(approxTable);
							 | 
						|
								
							 | 
						|
								    stGen = st_init_gen(storeTable);
							 | 
						|
								    if (stGen == NULL) {
							 | 
						|
									st_free_table(storeTable);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    while(st_gen(stGen, &key, &value)) {
							 | 
						|
									Cudd_RecursiveDeref(dd, key);
							 | 
						|
								    }
							 | 
						|
								    st_free_gen(stGen); stGen = NULL;
							 | 
						|
								    st_free_table(storeTable);
							 | 
						|
								
							 | 
						|
								    for (i = 0; i <= page; i++) {
							 | 
						|
									FREE(mintermPages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(mintermPages);
							 | 
						|
								    for (i = 0; i <= page; i++) {
							 | 
						|
									FREE(nodePages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(nodePages);
							 | 
						|
								    for (i = 0; i <= page; i++) {
							 | 
						|
									FREE(lightNodePages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(lightNodePages);
							 | 
						|
								    for (i = 0; i <= nodeDataPage; i++) {
							 | 
						|
									FREE(nodeDataPages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(nodeDataPages);
							 | 
						|
								    st_free_table(visitedTable);
							 | 
						|
								    FREE(size);
							 | 
						|
								#if 0
							 | 
						|
								    (void) Cudd_DebugCheck(dd);
							 | 
						|
								    (void) Cudd_CheckKeys(dd);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								      if (!Cudd_bddLeq(dd, subset, f)) {
							 | 
						|
									    fprintf(dd->err, "Wrong subset\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    return(NULL);
							 | 
						|
								      }
							 | 
						|
								#endif
							 | 
						|
									cuddDeref(subset);
							 | 
						|
									return(subset);
							 | 
						|
								    } else {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								} /* end of cuddSubsetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Resize the number of pages allocated to store the node data.]
							 | 
						|
								
							 | 
						|
								  Description [Resize the number of pages allocated to store the node data
							 | 
						|
								  The procedure  moves the counter to the next page when the end of
							 | 
						|
								  the page is reached and allocates new pages when necessary.]
							 | 
						|
								
							 | 
						|
								  SideEffects [Changes the size of pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out. ]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ResizeNodeDataPages(void)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    NodeData_t **newNodeDataPages;
							 | 
						|
								
							 | 
						|
								    nodeDataPage++;
							 | 
						|
								    /* If the current page index is larger than the number of pages
							 | 
						|
								     * allocated, allocate a new page array. Page numbers are incremented by
							 | 
						|
								     * INITIAL_PAGES
							 | 
						|
								     */
							 | 
						|
								    if (nodeDataPage == maxNodeDataPages) {
							 | 
						|
									newNodeDataPages = ALLOC(NodeData_t *,maxNodeDataPages + INITIAL_PAGES);
							 | 
						|
									if (newNodeDataPages == NULL) {
							 | 
						|
									    for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < maxNodeDataPages; i++) {
							 | 
						|
										newNodeDataPages[i] = nodeDataPages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    maxNodeDataPages += INITIAL_PAGES;
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    nodeDataPages = newNodeDataPages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    currentNodeDataPage = nodeDataPages[nodeDataPage] =
							 | 
						|
									ALLOC(NodeData_t ,nodeDataPageSize);
							 | 
						|
								    if (currentNodeDataPage == NULL) {
							 | 
						|
									for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									FREE(nodeDataPages);
							 | 
						|
									memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    nodeDataPageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeNodeDataPages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Resize the number of pages allocated to store the minterm
							 | 
						|
								  counts. ]
							 | 
						|
								
							 | 
						|
								  Description [Resize the number of pages allocated to store the minterm
							 | 
						|
								  counts.  The procedure  moves the counter to the next page when the
							 | 
						|
								  end of the page is reached and allocates new pages when necessary.]
							 | 
						|
								
							 | 
						|
								  SideEffects [Changes the size of minterm pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out. ]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ResizeCountMintermPages(void)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    double **newMintermPages;
							 | 
						|
								
							 | 
						|
								    page++;
							 | 
						|
								    /* If the current page index is larger than the number of pages
							 | 
						|
								     * allocated, allocate a new page array. Page numbers are incremented by
							 | 
						|
								     * INITIAL_PAGES
							 | 
						|
								     */
							 | 
						|
								    if (page == maxPages) {
							 | 
						|
									newMintermPages = ALLOC(double *,maxPages + INITIAL_PAGES);
							 | 
						|
									if (newMintermPages == NULL) {
							 | 
						|
									    for (i = 0; i < page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < maxPages; i++) {
							 | 
						|
										newMintermPages[i] = mintermPages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    maxPages += INITIAL_PAGES;
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    mintermPages = newMintermPages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    currentMintermPage = mintermPages[page] = ALLOC(double,pageSize);
							 | 
						|
								    if (currentMintermPage == NULL) {
							 | 
						|
									for (i = 0; i < page; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    pageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeCountMintermPages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Resize the number of pages allocated to store the node counts.]
							 | 
						|
								
							 | 
						|
								  Description [Resize the number of pages allocated to store the node counts.
							 | 
						|
								  The procedure  moves the counter to the next page when the end of
							 | 
						|
								  the page is reached and allocates new pages when necessary.]
							 | 
						|
								
							 | 
						|
								  SideEffects [Changes the size of pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ResizeCountNodePages(void)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    int **newNodePages;
							 | 
						|
								
							 | 
						|
								    page++;
							 | 
						|
								
							 | 
						|
								    /* If the current page index is larger than the number of pages
							 | 
						|
								     * allocated, allocate a new page array. The number of pages is incremented
							 | 
						|
								     * by INITIAL_PAGES.
							 | 
						|
								     */
							 | 
						|
								    if (page == maxPages) {
							 | 
						|
									newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
							 | 
						|
									if (newNodePages == NULL) {
							 | 
						|
									    for (i = 0; i < page; i++) FREE(nodePages[i]);
							 | 
						|
									    FREE(nodePages);
							 | 
						|
									    for (i = 0; i < page; i++) FREE(lightNodePages[i]);
							 | 
						|
									    FREE(lightNodePages);
							 | 
						|
									    memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < maxPages; i++) {
							 | 
						|
										newNodePages[i] = nodePages[i];
							 | 
						|
									    }
							 | 
						|
									    FREE(nodePages);
							 | 
						|
									    nodePages = newNodePages;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									newNodePages = ALLOC(int *,maxPages + INITIAL_PAGES);
							 | 
						|
									if (newNodePages == NULL) {
							 | 
						|
									    for (i = 0; i < page; i++) FREE(nodePages[i]);
							 | 
						|
									    FREE(nodePages);
							 | 
						|
									    for (i = 0; i < page; i++) FREE(lightNodePages[i]);
							 | 
						|
									    FREE(lightNodePages);
							 | 
						|
									    memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < maxPages; i++) {
							 | 
						|
										newNodePages[i] = lightNodePages[i];
							 | 
						|
									    }
							 | 
						|
									    FREE(lightNodePages);
							 | 
						|
									    lightNodePages = newNodePages;
							 | 
						|
									}
							 | 
						|
									/* Increase total page count */
							 | 
						|
									maxPages += INITIAL_PAGES;
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    currentNodePage = nodePages[page] = ALLOC(int,pageSize);
							 | 
						|
								    if (currentNodePage == NULL) {
							 | 
						|
									for (i = 0; i < page; i++) FREE(nodePages[i]);
							 | 
						|
									FREE(nodePages);
							 | 
						|
									for (i = 0; i < page; i++) FREE(lightNodePages[i]);
							 | 
						|
									FREE(lightNodePages);
							 | 
						|
									memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
							 | 
						|
								    if (currentLightNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= page; i++) FREE(nodePages[i]);
							 | 
						|
									FREE(nodePages);
							 | 
						|
									for (i = 0; i < page; i++) FREE(lightNodePages[i]);
							 | 
						|
									FREE(lightNodePages);
							 | 
						|
									memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    pageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeCountNodePages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Recursively counts minterms of each node in the DAG.]
							 | 
						|
								
							 | 
						|
								  Description [Recursively counts minterms of each node in the DAG.
							 | 
						|
								  Similar to the cuddCountMintermAux which recursively counts the
							 | 
						|
								  number of minterms for the dag rooted at each node in terms of the
							 | 
						|
								  total number of variables (max). This procedure creates the node
							 | 
						|
								  data structure and stores the minterm count as part of the node
							 | 
						|
								  data structure. ]
							 | 
						|
								
							 | 
						|
								  SideEffects [Creates structures of type node quality and fills the st_table]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [SubsetCountMinterm]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static double
							 | 
						|
								SubsetCountMintermAux(
							 | 
						|
								  DdNode * node /* function to analyze */,
							 | 
						|
								  double  max /* number of minterms of constant 1 */,
							 | 
						|
								  st_table * table /* visitedTable table */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    DdNode	*N,*Nv,*Nnv; /* nodes to store cofactors  */
							 | 
						|
								    double	min,*pmin; /* minterm count */
							 | 
						|
								    double	min1, min2; /* minterm count */
							 | 
						|
								    NodeData_t *dummy;
							 | 
						|
								    NodeData_t *newEntry;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    num_calls++;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Constant case */
							 | 
						|
								    if (Cudd_IsConstant(node)) {
							 | 
						|
									if (node == zero) {
							 | 
						|
									    return(0.0);
							 | 
						|
									} else {
							 | 
						|
									    return(max);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
								
							 | 
						|
									/* check if entry for this node exists */
							 | 
						|
									if (st_lookup(table, node, &dummy)) {
							 | 
						|
									    min = *(dummy->mintermPointer);
							 | 
						|
									    return(min);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									/* Make the node regular to extract cofactors */
							 | 
						|
									N = Cudd_Regular(node);
							 | 
						|
								
							 | 
						|
									/* store the cofactors */
							 | 
						|
									Nv = Cudd_T(N);
							 | 
						|
									Nnv = Cudd_E(N);
							 | 
						|
								
							 | 
						|
									Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
							 | 
						|
									Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
									min1 =  SubsetCountMintermAux(Nv, max,table)/2.0;
							 | 
						|
									if (memOut) return(0.0);
							 | 
						|
									min2 =  SubsetCountMintermAux(Nnv,max,table)/2.0;
							 | 
						|
									if (memOut) return(0.0);
							 | 
						|
									min = (min1+min2);
							 | 
						|
								
							 | 
						|
									/* if page index is at the bottom, then create a new page */
							 | 
						|
									if (pageIndex == pageSize) ResizeCountMintermPages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									/* point to the correct location in the page */
							 | 
						|
									pmin = currentMintermPage+pageIndex;
							 | 
						|
									pageIndex++;
							 | 
						|
								
							 | 
						|
									/* store the minterm count of this node in the page */
							 | 
						|
									*pmin = min;
							 | 
						|
								
							 | 
						|
									/* Note I allocate the struct here. Freeing taken care of later */
							 | 
						|
									if (nodeDataPageIndex == nodeDataPageSize) ResizeNodeDataPages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									newEntry = currentNodeDataPage + nodeDataPageIndex;
							 | 
						|
									nodeDataPageIndex++;
							 | 
						|
								
							 | 
						|
									/* points to the correct location in the page */
							 | 
						|
									newEntry->mintermPointer = pmin;
							 | 
						|
									/* initialize this field of the Node Quality structure */
							 | 
						|
									newEntry->nodesPointer = NULL;
							 | 
						|
								
							 | 
						|
									/* insert entry for the node in the table */
							 | 
						|
									if (st_insert(table,node, newEntry) == ST_OUT_OF_MEM) {
							 | 
						|
									    memOut = 1;
							 | 
						|
									    for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
									return(min);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountMintermAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Counts minterms of each node in the DAG]
							 | 
						|
								
							 | 
						|
								  Description [Counts minterms of each node in the DAG. Similar to the
							 | 
						|
								  Cudd_CountMinterm procedure except this returns the minterm count for
							 | 
						|
								  all the nodes in the bdd in an st_table.]
							 | 
						|
								
							 | 
						|
								  SideEffects [none]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [SubsetCountMintermAux]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static st_table *
							 | 
						|
								SubsetCountMinterm(
							 | 
						|
								  DdNode * node /* function to be analyzed */,
							 | 
						|
								  int nvars /* number of variables node depends on */)
							 | 
						|
								{
							 | 
						|
								    st_table	*table;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    max = pow(2.0,(double) nvars);
							 | 
						|
								    table = st_init_table(st_ptrcmp,st_ptrhash);
							 | 
						|
								    if (table == NULL) goto OUT_OF_MEM;
							 | 
						|
								    maxPages = INITIAL_PAGES;
							 | 
						|
								    mintermPages = ALLOC(double *,maxPages);
							 | 
						|
								    if (mintermPages == NULL) {
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    page = 0;
							 | 
						|
								    currentMintermPage = ALLOC(double,pageSize);
							 | 
						|
								    mintermPages[page] = currentMintermPage;
							 | 
						|
								    if (currentMintermPage == NULL) {
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    pageIndex = 0;
							 | 
						|
								    maxNodeDataPages = INITIAL_PAGES;
							 | 
						|
								    nodeDataPages = ALLOC(NodeData_t *, maxNodeDataPages);
							 | 
						|
								    if (nodeDataPages == NULL) {
							 | 
						|
									for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    nodeDataPage = 0;
							 | 
						|
								    currentNodeDataPage = ALLOC(NodeData_t ,nodeDataPageSize);
							 | 
						|
								    nodeDataPages[nodeDataPage] = currentNodeDataPage;
							 | 
						|
								    if (currentNodeDataPage == NULL) {
							 | 
						|
									for (i = 0; i <= page ; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									FREE(nodeDataPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    nodeDataPageIndex = 0;
							 | 
						|
								
							 | 
						|
								    (void) SubsetCountMintermAux(node,max,table);
							 | 
						|
								    if (memOut) goto OUT_OF_MEM;
							 | 
						|
								    return(table);
							 | 
						|
								
							 | 
						|
								OUT_OF_MEM:
							 | 
						|
								    memOut = 1;
							 | 
						|
								    return(NULL);
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountMinterm */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Recursively counts the number of nodes under the dag.
							 | 
						|
								  Also counts the number of nodes under the lighter child of
							 | 
						|
								  this node.]
							 | 
						|
								
							 | 
						|
								  Description [Recursively counts the number of nodes under the dag.
							 | 
						|
								  Also counts the number of nodes under the lighter child of
							 | 
						|
								  this node. . Note that the same dag may be the lighter child of two
							 | 
						|
								  different nodes and have different counts. As with the minterm counts,
							 | 
						|
								  the node counts are stored in pages to be space efficient and the
							 | 
						|
								  address for these node counts are stored in an st_table associated
							 | 
						|
								  to each node. ]
							 | 
						|
								
							 | 
						|
								  SideEffects [Updates the node data table with node counts]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [SubsetCountNodes]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								SubsetCountNodesAux(
							 | 
						|
								  DdNode * node /* current node */,
							 | 
						|
								  st_table * table /* table to update node count, also serves as visited table. */,
							 | 
						|
								  double  max /* maximum number of variables */)
							 | 
						|
								{
							 | 
						|
								    int tval, eval, i;
							 | 
						|
								    DdNode *N, *Nv, *Nnv;
							 | 
						|
								    double minNv, minNnv;
							 | 
						|
								    NodeData_t *dummyN, *dummyNv, *dummyNnv, *dummyNBar;
							 | 
						|
								    int *pmin, *pminBar, *val;
							 | 
						|
								
							 | 
						|
								    if ((node == NULL) || Cudd_IsConstant(node))
							 | 
						|
									return(0);
							 | 
						|
								
							 | 
						|
								    /* if this node has been processed do nothing */
							 | 
						|
								    if (st_lookup(table, node, &dummyN) == 1) {
							 | 
						|
									val = dummyN->nodesPointer;
							 | 
						|
									if (val != NULL)
							 | 
						|
									    return(0);
							 | 
						|
								    } else {
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    N  = Cudd_Regular(node);
							 | 
						|
								    Nv = Cudd_T(N);
							 | 
						|
								    Nnv = Cudd_E(N);
							 | 
						|
								
							 | 
						|
								    Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
							 | 
						|
								    Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    /* find the minterm counts for the THEN and ELSE branches */
							 | 
						|
								    if (Cudd_IsConstant(Nv)) {
							 | 
						|
									if (Nv == zero) {
							 | 
						|
									    minNv = 0.0;
							 | 
						|
									} else {
							 | 
						|
									    minNv = max;
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (st_lookup(table, Nv, &dummyNv) == 1)
							 | 
						|
									    minNv = *(dummyNv->mintermPointer);
							 | 
						|
									else {
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsConstant(Nnv)) {
							 | 
						|
									if (Nnv == zero) {
							 | 
						|
									    minNnv = 0.0;
							 | 
						|
									} else {
							 | 
						|
									    minNnv = max;
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (st_lookup(table, Nnv, &dummyNnv) == 1) {
							 | 
						|
									    minNnv = *(dummyNnv->mintermPointer);
							 | 
						|
									}
							 | 
						|
									else {
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /* recur based on which has larger minterm, */
							 | 
						|
								    if (minNv >= minNnv) {
							 | 
						|
									tval = SubsetCountNodesAux(Nv, table, max);
							 | 
						|
									if (memOut) return(0);
							 | 
						|
									eval = SubsetCountNodesAux(Nnv, table, max);
							 | 
						|
									if (memOut) return(0);
							 | 
						|
								
							 | 
						|
									/* store the node count of the lighter child. */
							 | 
						|
									if (pageIndex == pageSize) ResizeCountNodePages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pmin = currentLightNodePage + pageIndex;
							 | 
						|
									*pmin = eval; /* Here the ELSE child is lighter */
							 | 
						|
									dummyN->lightChildNodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    } else {
							 | 
						|
									eval = SubsetCountNodesAux(Nnv, table, max);
							 | 
						|
									if (memOut) return(0);
							 | 
						|
									tval = SubsetCountNodesAux(Nv, table, max);
							 | 
						|
									if (memOut) return(0);
							 | 
						|
								
							 | 
						|
									/* store the node count of the lighter child. */
							 | 
						|
									if (pageIndex == pageSize) ResizeCountNodePages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pmin = currentLightNodePage + pageIndex;
							 | 
						|
									*pmin = tval; /* Here the THEN child is lighter */
							 | 
						|
									dummyN->lightChildNodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								    /* updating the page index for node count storage. */
							 | 
						|
								    pmin = currentNodePage + pageIndex;
							 | 
						|
								    *pmin = tval + eval + 1;
							 | 
						|
								    dummyN->nodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    /* pageIndex is parallel page index for count_nodes and count_lightNodes */
							 | 
						|
								    pageIndex++;
							 | 
						|
								
							 | 
						|
								    /* if this node has been reached first, it belongs to a heavier
							 | 
						|
								       branch. Its complement will be reached later on a lighter branch.
							 | 
						|
								       Hence the complement has zero node count. */
							 | 
						|
								
							 | 
						|
								    if (st_lookup(table, Cudd_Not(node), &dummyNBar) == 1)  {
							 | 
						|
									if (pageIndex == pageSize) ResizeCountNodePages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i < page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pminBar = currentLightNodePage + pageIndex;
							 | 
						|
									*pminBar = 0;
							 | 
						|
									dummyNBar->lightChildNodesPointer = pminBar;
							 | 
						|
									/* The lighter child has less nodes than the parent.
							 | 
						|
									 * So if parent 0 then lighter child zero
							 | 
						|
									 */
							 | 
						|
									if (pageIndex == pageSize) ResizeCountNodePages();
							 | 
						|
									if (memOut) {
							 | 
						|
									    for (i = 0; i < page; i++) FREE(mintermPages[i]);
							 | 
						|
									    FREE(mintermPages);
							 | 
						|
									    for (i = 0; i < nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									    FREE(nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pminBar = currentNodePage + pageIndex;
							 | 
						|
									*pminBar = 0;
							 | 
						|
									dummyNBar->nodesPointer = pminBar ; /* maybe should point to zero */
							 | 
						|
								
							 | 
						|
									pageIndex++;
							 | 
						|
								    }
							 | 
						|
								    return(*pmin);
							 | 
						|
								} /*end of SubsetCountNodesAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Counts the nodes under the current node and its lighter child]
							 | 
						|
								
							 | 
						|
								  Description [Counts the nodes under the current node and its lighter
							 | 
						|
								  child. Calls a recursive procedure to count the number of nodes of
							 | 
						|
								  a DAG rooted at a particular node and the number of nodes taken by its
							 | 
						|
								  lighter child.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [SubsetCountNodesAux]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								SubsetCountNodes(
							 | 
						|
								  DdNode * node /* function to be analyzed */,
							 | 
						|
								  st_table * table /* node quality table */,
							 | 
						|
								  int  nvars /* number of variables node depends on */)
							 | 
						|
								{
							 | 
						|
								    int	num;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    max = pow(2.0,(double) nvars);
							 | 
						|
								    maxPages = INITIAL_PAGES;
							 | 
						|
								    nodePages = ALLOC(int *,maxPages);
							 | 
						|
								    if (nodePages == NULL)  {
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    lightNodePages = ALLOC(int *,maxPages);
							 | 
						|
								    if (lightNodePages == NULL) {
							 | 
						|
									for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									FREE(nodeDataPages);
							 | 
						|
									FREE(nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    page = 0;
							 | 
						|
								    currentNodePage = nodePages[page] = ALLOC(int,pageSize);
							 | 
						|
								    if (currentNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									FREE(nodeDataPages);
							 | 
						|
									FREE(lightNodePages);
							 | 
						|
									FREE(nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    currentLightNodePage = lightNodePages[page] = ALLOC(int,pageSize);
							 | 
						|
								    if (currentLightNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= page; i++) FREE(mintermPages[i]);
							 | 
						|
									FREE(mintermPages);
							 | 
						|
									for (i = 0; i <= nodeDataPage; i++) FREE(nodeDataPages[i]);
							 | 
						|
									FREE(nodeDataPages);
							 | 
						|
									FREE(currentNodePage);
							 | 
						|
									FREE(lightNodePages);
							 | 
						|
									FREE(nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    pageIndex = 0;
							 | 
						|
								    num = SubsetCountNodesAux(node,table,max);
							 | 
						|
								    if (memOut) goto OUT_OF_MEM;
							 | 
						|
								    return(num);
							 | 
						|
								
							 | 
						|
								OUT_OF_MEM:
							 | 
						|
								    memOut = 1;
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountNodes */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Procedure to recursively store nodes that are retained in the subset.]
							 | 
						|
								
							 | 
						|
								  Description [rocedure to recursively store nodes that are retained in the subset.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [StoreNodes]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								StoreNodes(
							 | 
						|
								  st_table * storeTable,
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  DdNode * node)
							 | 
						|
								{
							 | 
						|
								    DdNode *N, *Nt, *Ne;
							 | 
						|
								    if (Cudd_IsConstant(dd)) {
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								    if (st_lookup(storeTable, N, NULL)) {
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    cuddRef(N);
							 | 
						|
								    if (st_insert(storeTable, N, NULL) == ST_OUT_OF_MEM) {
							 | 
						|
									fprintf(dd->err,"Something wrong, st_table insert failed\n");
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    Nt = Cudd_T(N);
							 | 
						|
								    Ne = Cudd_E(N);
							 | 
						|
								
							 | 
						|
								    StoreNodes(storeTable, dd, Nt);
							 | 
						|
								    StoreNodes(storeTable, dd, Ne);
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Builds the subset BDD using the heavy branch method.]
							 | 
						|
								
							 | 
						|
								  Description [The procedure carries out the building of the subset BDD
							 | 
						|
								  starting at the root. Using the three different counts labelling each node,
							 | 
						|
								  the procedure chooses the heavier branch starting from the root and keeps
							 | 
						|
								  track of the number of nodes it discards at each step, thus keeping count
							 | 
						|
								  of the size of the subset BDD dynamically. Once the threshold is satisfied,
							 | 
						|
								  the procedure then calls ITE to build the BDD.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static DdNode *
							 | 
						|
								BuildSubsetBdd(
							 | 
						|
								  DdManager * dd /* DD manager */,
							 | 
						|
								  DdNode * node /* current node */,
							 | 
						|
								  int * size /* current size of the subset */,
							 | 
						|
								  st_table * visitedTable /* visited table storing all node data */,
							 | 
						|
								  int  threshold,
							 | 
						|
								  st_table * storeTable,
							 | 
						|
								  st_table * approxTable)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    DdNode *Nv, *Nnv, *N, *topv, *neW;
							 | 
						|
								    double minNv, minNnv;
							 | 
						|
								    NodeData_t *currNodeQual;
							 | 
						|
								    NodeData_t *currNodeQualT;
							 | 
						|
								    NodeData_t *currNodeQualE;
							 | 
						|
								    DdNode *ThenBranch, *ElseBranch;
							 | 
						|
								    unsigned int topid;
							 | 
						|
								    char *dummy;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    num_calls++;
							 | 
						|
								#endif
							 | 
						|
								    /*If the size of the subset is below the threshold, dont do
							 | 
						|
								      anything. */
							 | 
						|
								    if ((*size) <= threshold) {
							 | 
						|
								      /* store nodes below this, so we can recombine if possible */
							 | 
						|
								      StoreNodes(storeTable, dd, node);
							 | 
						|
								      return(node);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstant(node))
							 | 
						|
									return(node);
							 | 
						|
								
							 | 
						|
								    /* Look up minterm count for this node. */
							 | 
						|
								    if (!st_lookup(visitedTable, node, &currNodeQual)) {
							 | 
						|
									fprintf(dd->err,
							 | 
						|
										"Something is wrong, ought to be in node quality table\n");
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Get children. */
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								    Nv = Cudd_T(N);
							 | 
						|
								    Nnv = Cudd_E(N);
							 | 
						|
								
							 | 
						|
								    /* complement if necessary */
							 | 
						|
								    Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
							 | 
						|
								    Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    if (!Cudd_IsConstant(Nv)) {
							 | 
						|
									/* find out minterms and nodes contributed by then child */
							 | 
						|
									if (!st_lookup(visitedTable, Nv, &currNodeQualT)) {
							 | 
						|
										fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
							 | 
						|
										dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									else {
							 | 
						|
									    minNv = *(((NodeData_t *)currNodeQualT)->mintermPointer);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (Nv == zero) {
							 | 
						|
									    minNv = 0;
							 | 
						|
									} else  {
							 | 
						|
									    minNv = max;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    if (!Cudd_IsConstant(Nnv)) {
							 | 
						|
									/* find out minterms and nodes contributed by else child */
							 | 
						|
									if (!st_lookup(visitedTable, Nnv, &currNodeQualE)) {
							 | 
						|
									    fprintf(dd->out,"Something wrong, couldnt find nodes in node quality table\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    return(NULL);
							 | 
						|
									} else {
							 | 
						|
									    minNnv = *(((NodeData_t *)currNodeQualE)->mintermPointer);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (Nnv == zero) {
							 | 
						|
									    minNnv = 0;
							 | 
						|
									} else {
							 | 
						|
									    minNnv = max;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* keep track of size of subset by subtracting the number of
							 | 
						|
								     * differential nodes contributed by lighter child
							 | 
						|
								     */
							 | 
						|
								    *size = (*(size)) - (int)*(currNodeQual->lightChildNodesPointer);
							 | 
						|
								    if (minNv >= minNnv) { /*SubsetCountNodesAux procedure takes
							 | 
						|
											     the Then branch in case of a tie */
							 | 
						|
								
							 | 
						|
									/* recur with the Then branch */
							 | 
						|
									ThenBranch = (DdNode *)BuildSubsetBdd(dd, Nv, size,
							 | 
						|
									      visitedTable, threshold, storeTable, approxTable);
							 | 
						|
									if (ThenBranch == NULL) {
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									cuddRef(ThenBranch);
							 | 
						|
									/* The Else branch is either a node that already exists in the
							 | 
						|
									 * subset, or one whose approximation has been computed, or
							 | 
						|
									 * Zero.
							 | 
						|
									 */
							 | 
						|
									if (st_lookup(storeTable, Cudd_Regular(Nnv), &dummy)) {
							 | 
						|
									  ElseBranch = Nnv;
							 | 
						|
									  cuddRef(ElseBranch);
							 | 
						|
									} else {
							 | 
						|
									  if (st_lookup(approxTable, Nnv, &dummy)) {
							 | 
						|
									    ElseBranch = (DdNode *)dummy;
							 | 
						|
									    cuddRef(ElseBranch);
							 | 
						|
									  } else {
							 | 
						|
									    ElseBranch = zero;
							 | 
						|
									    cuddRef(ElseBranch);
							 | 
						|
									  }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
									/* recur with the Else branch */
							 | 
						|
									ElseBranch = (DdNode *)BuildSubsetBdd(dd, Nnv, size,
							 | 
						|
										      visitedTable, threshold, storeTable, approxTable);
							 | 
						|
									if (ElseBranch == NULL) {
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									cuddRef(ElseBranch);
							 | 
						|
									/* The Then branch is either a node that already exists in the
							 | 
						|
									 * subset, or one whose approximation has been computed, or
							 | 
						|
									 * Zero.
							 | 
						|
									 */
							 | 
						|
									if (st_lookup(storeTable, Cudd_Regular(Nv), &dummy)) {
							 | 
						|
									  ThenBranch = Nv;
							 | 
						|
									  cuddRef(ThenBranch);
							 | 
						|
									} else {
							 | 
						|
									  if (st_lookup(approxTable, Nv, &dummy)) {
							 | 
						|
									    ThenBranch = (DdNode *)dummy;
							 | 
						|
									    cuddRef(ThenBranch);
							 | 
						|
									  } else {
							 | 
						|
									    ThenBranch = zero;
							 | 
						|
									    cuddRef(ThenBranch);
							 | 
						|
									  }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* construct the Bdd with the top variable and the two children */
							 | 
						|
								    topid = Cudd_NodeReadIndex(N);
							 | 
						|
								    topv = Cudd_ReadVars(dd, topid);
							 | 
						|
								    cuddRef(topv);
							 | 
						|
								    neW =  cuddBddIteRecur(dd, topv, ThenBranch, ElseBranch);
							 | 
						|
								    if (neW != NULL) {
							 | 
						|
								      cuddRef(neW);
							 | 
						|
								    }
							 | 
						|
								    Cudd_RecursiveDeref(dd, topv);
							 | 
						|
								    Cudd_RecursiveDeref(dd, ThenBranch);
							 | 
						|
								    Cudd_RecursiveDeref(dd, ElseBranch);
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    if (neW == NULL)
							 | 
						|
									return(NULL);
							 | 
						|
								    else {
							 | 
						|
									/* store this node in the store table */
							 | 
						|
									if (!st_lookup(storeTable, Cudd_Regular(neW), &dummy)) {
							 | 
						|
									  cuddRef(neW);
							 | 
						|
									  if (st_insert(storeTable, Cudd_Regular(neW), NULL) ==
							 | 
						|
								              ST_OUT_OF_MEM)
							 | 
						|
								              return (NULL);
							 | 
						|
									}
							 | 
						|
									/* store the approximation for this node */
							 | 
						|
									if (N !=  Cudd_Regular(neW)) {
							 | 
						|
									    if (st_lookup(approxTable, node, &dummy)) {
							 | 
						|
										fprintf(dd->err, "This node should not be in the approximated table\n");
							 | 
						|
									    } else {
							 | 
						|
										cuddRef(neW);
							 | 
						|
										if (st_insert(approxTable, node, neW) ==
							 | 
						|
								                    ST_OUT_OF_MEM)
							 | 
						|
										    return(NULL);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									cuddDeref(neW);
							 | 
						|
									return(neW);
							 | 
						|
								    }
							 | 
						|
								} /* end of BuildSubsetBdd */
							 |