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.
		
		
		
		
		
			
		
			
				
					
					
						
							1310 lines
						
					
					
						
							40 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1310 lines
						
					
					
						
							40 KiB
						
					
					
				
								/**
							 | 
						|
								  @file
							 | 
						|
								
							 | 
						|
								  @ingroup cudd
							 | 
						|
								
							 | 
						|
								  @brief Procedure to subset the given %BDD by choosing the heavier
							 | 
						|
								  branches.
							 | 
						|
								
							 | 
						|
								  @see cuddSubsetSP.c
							 | 
						|
								
							 | 
						|
								  @author Kavita Ravi
							 | 
						|
								
							 | 
						|
								  @copyright@parblock
							 | 
						|
								  Copyright (c) 1995-2015, Regents of the University of Colorado
							 | 
						|
								
							 | 
						|
								  All rights reserved.
							 | 
						|
								
							 | 
						|
								  Redistribution and use in source and binary forms, with or without
							 | 
						|
								  modification, are permitted provided that the following conditions
							 | 
						|
								  are met:
							 | 
						|
								
							 | 
						|
								  Redistributions of source code must retain the above copyright
							 | 
						|
								  notice, this list of conditions and the following disclaimer.
							 | 
						|
								
							 | 
						|
								  Redistributions in binary form must reproduce the above copyright
							 | 
						|
								  notice, this list of conditions and the following disclaimer in the
							 | 
						|
								  documentation and/or other materials provided with the distribution.
							 | 
						|
								
							 | 
						|
								  Neither the name of the University of Colorado nor the names of its
							 | 
						|
								  contributors may be used to endorse or promote products derived from
							 | 
						|
								  this software without specific prior written permission.
							 | 
						|
								
							 | 
						|
								  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
							 | 
						|
								  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
							 | 
						|
								  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
							 | 
						|
								  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
							 | 
						|
								  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
							 | 
						|
								  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
							 | 
						|
								  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
							 | 
						|
								  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
							 | 
						|
								  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
							 | 
						|
								  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
							 | 
						|
								  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
							 | 
						|
								  POSSIBILITY OF SUCH DAMAGE.
							 | 
						|
								  @endparblock
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								
							 | 
						|
								#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
							 | 
						|
								
							 | 
						|
								#undef max
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								typedef struct NodeData NodeData_t;
							 | 
						|
								
							 | 
						|
								typedef struct SubsetInfo SubsetInfo_t;
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * @brief Data structure to store the information on each node.
							 | 
						|
								
							 | 
						|
								 * @details 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;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * @brief Miscellaneous info.
							 | 
						|
								 */
							 | 
						|
								struct SubsetInfo {
							 | 
						|
								    DdNode	*zero, *one; /**< constant functions */
							 | 
						|
								    double	**mintermPages;	/**< pointers to the pages */
							 | 
						|
								    int		**nodePages; /**< pointers to the pages */
							 | 
						|
								    int		**lightNodePages; /**< pointers to the pages */
							 | 
						|
								    double	*currentMintermPage; /**< pointer to the current page */
							 | 
						|
								    double	max; /**< to store the 2^n value of the number of variables */
							 | 
						|
								    int		*currentNodePage; /**< pointer to the current page */
							 | 
						|
								    int		*currentLightNodePage; /**< pointer to the current page */
							 | 
						|
								    int		pageIndex; /**< index to next element */
							 | 
						|
								    int		page; /**< index to current page */
							 | 
						|
								    int		pageSize; /**< page size */
							 | 
						|
								    int         maxPages; /**< number of page pointers */
							 | 
						|
								    NodeData_t	*currentNodeDataPage; /**< pointer to the current page */
							 | 
						|
								    int		nodeDataPage; /**< index to next element */
							 | 
						|
								    int		nodeDataPageIndex; /**< index to next element */
							 | 
						|
								    NodeData_t	**nodeDataPages; /**< index to current page */
							 | 
						|
								    int		nodeDataPageSize; /**< page size */
							 | 
						|
								    int         maxNodeDataPages; /**< number of page pointers */
							 | 
						|
								    int memOut;
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    int		num_calls;
							 | 
						|
								#endif
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/** \cond */
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static void ResizeNodeDataPages (SubsetInfo_t * info);
							 | 
						|
								static void ResizeCountMintermPages (SubsetInfo_t * info);
							 | 
						|
								static void ResizeCountNodePages (SubsetInfo_t * info);
							 | 
						|
								static double SubsetCountMintermAux (DdNode *node, double max, st_table *table, SubsetInfo_t * info);
							 | 
						|
								static st_table * SubsetCountMinterm (DdNode *node, int nvars, SubsetInfo_t * info);
							 | 
						|
								static int SubsetCountNodesAux (DdNode *node, st_table *table, double max, SubsetInfo_t * info);
							 | 
						|
								static int SubsetCountNodes (DdNode *node, st_table *table, int nvars, SubsetInfo_t * info);
							 | 
						|
								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, SubsetInfo_t * info);
							 | 
						|
								
							 | 
						|
								/** \endcond */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense subset from a %BDD with the heavy branch
							 | 
						|
								  heuristic.
							 | 
						|
								
							 | 
						|
								  @details 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.  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.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the subset if successful. NULL if
							 | 
						|
								  the procedure runs out of memory.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see 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;
							 | 
						|
								
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetHeavyBranch(dd, f, numVars, threshold);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SubsetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Extracts a dense superset from a %BDD with the heavy branch
							 | 
						|
								  heuristic.
							 | 
						|
								
							 | 
						|
								  @details 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.  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.
							 | 
						|
								
							 | 
						|
								  @return a pointer to the %BDD of the superset if successful. NULL if
							 | 
						|
								  intermediate result causes the procedure to run out of memory.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see 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);
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetHeavyBranch(dd, g, numVars, threshold);
							 | 
						|
								    } while (dd->reordered == 1);
							 | 
						|
								    if (dd->errorCode == CUDD_TIMEOUT_EXPIRED && dd->timeoutHandler) {
							 | 
						|
								        dd->timeoutHandler(dd, dd->tohArg);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SupersetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief The main procedure that returns a subset by choosing the heavier
							 | 
						|
								  branch in the %BDD.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see 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;
							 | 
						|
								    SubsetInfo_t info;
							 | 
						|
								
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot subset, nil object\n");
							 | 
						|
									dd->errorCode = CUDD_INVALID_ARG;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* 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_IsConstantInt(f)) {
							 | 
						|
									return(f);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info.one  = Cudd_ReadOne(dd);
							 | 
						|
								    info.zero = Cudd_Not(info.one);
							 | 
						|
								    info.mintermPages = NULL;
							 | 
						|
								    info.nodePages = info.lightNodePages = NULL;
							 | 
						|
								    info.currentMintermPage = NULL;
							 | 
						|
								    info.max = pow(2.0, (double)numVars);
							 | 
						|
								    info.currentNodePage = info.currentLightNodePage = NULL;
							 | 
						|
								    info.pageIndex = info.page = 0;
							 | 
						|
								    info.pageSize = DEFAULT_PAGE_SIZE;
							 | 
						|
								    info.maxPages = 0;
							 | 
						|
								    info.currentNodeDataPage = NULL;
							 | 
						|
								    info.nodeDataPage = info.nodeDataPageIndex = 0;
							 | 
						|
								    info.nodeDataPages = NULL;
							 | 
						|
								    info.nodeDataPageSize = DEFAULT_NODE_DATA_PAGE_SIZE;
							 | 
						|
								    info.maxNodeDataPages = 0;
							 | 
						|
								    info.memOut = 0;
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    info.num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Create visited table where structures for node data are allocated and
							 | 
						|
								       stored in a st_table */
							 | 
						|
								    visitedTable = SubsetCountMinterm(f, numVars, &info);
							 | 
						|
								    if ((visitedTable == NULL) || info.memOut) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    numNodes = SubsetCountNodes(f, visitedTable, numVars, &info);
							 | 
						|
								    if (info.memOut) {
							 | 
						|
									(void) fprintf(dd->err, "Out-of-memory; Cannot subset\n");
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (st_lookup(visitedTable, f, (void **) &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;
							 | 
						|
								
							 | 
						|
								    /* table to store nodes being created. */
							 | 
						|
								    storeTable = st_init_table(st_ptrcmp, st_ptrhash);
							 | 
						|
								    /* insert the constant */
							 | 
						|
								    cuddRef(info.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, &info);
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddRef(subset);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (info.memOut) {
							 | 
						|
								        dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
								        dd->reordered = 0;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    stGen = st_init_gen(approxTable);
							 | 
						|
								    if (stGen == NULL) {
							 | 
						|
									st_free_table(approxTable);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    while(st_gen(stGen, (void **) &key, (void **) &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, (void **) &key, (void **) &value)) {
							 | 
						|
									Cudd_RecursiveDeref(dd, key);
							 | 
						|
								    }
							 | 
						|
								    st_free_gen(stGen); stGen = NULL;
							 | 
						|
								    st_free_table(storeTable);
							 | 
						|
								
							 | 
						|
								    for (i = 0; i <= info.page; i++) {
							 | 
						|
									FREE(info.mintermPages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(info.mintermPages);
							 | 
						|
								    for (i = 0; i <= info.page; i++) {
							 | 
						|
									FREE(info.nodePages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(info.nodePages);
							 | 
						|
								    for (i = 0; i <= info.page; i++) {
							 | 
						|
									FREE(info.lightNodePages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(info.lightNodePages);
							 | 
						|
								    for (i = 0; i <= info.nodeDataPage; i++) {
							 | 
						|
									FREE(info.nodeDataPages[i]);
							 | 
						|
								    }
							 | 
						|
								    FREE(info.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);
							 | 
						|
								
							 | 
						|
								} /* end of cuddSubsetHeavyBranch */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Resize the number of pages allocated to store the node data.
							 | 
						|
								
							 | 
						|
								  @details The procedure moves the counter to the next page when the
							 | 
						|
								  end of the page is reached and allocates new pages when necessary.
							 | 
						|
								
							 | 
						|
								  @sideeffect Changes the size of pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out. 
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static void
							 | 
						|
								ResizeNodeDataPages(SubsetInfo_t * info)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    NodeData_t **newNodeDataPages;
							 | 
						|
								
							 | 
						|
								    info->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 (info->nodeDataPage == info->maxNodeDataPages) {
							 | 
						|
									newNodeDataPages = ALLOC(NodeData_t *, info->maxNodeDataPages + INITIAL_PAGES);
							 | 
						|
									if (newNodeDataPages == NULL) {
							 | 
						|
									    for (i = 0; i < info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    info->memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < info->maxNodeDataPages; i++) {
							 | 
						|
										newNodeDataPages[i] = info->nodeDataPages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    info->maxNodeDataPages += INITIAL_PAGES;
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    info->nodeDataPages = newNodeDataPages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    info->currentNodeDataPage = info->nodeDataPages[info->nodeDataPage] =
							 | 
						|
									ALLOC(NodeData_t ,info->nodeDataPageSize);
							 | 
						|
								    if (info->currentNodeDataPage == NULL) {
							 | 
						|
									for (i = 0; i < info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									FREE(info->nodeDataPages);
							 | 
						|
									info->memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    info->nodeDataPageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeNodeDataPages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Resize the number of pages allocated to store the minterm
							 | 
						|
								  counts. 
							 | 
						|
								
							 | 
						|
								  @details The procedure  moves the counter to the next page when the
							 | 
						|
								  end of the page is reached and allocates new pages when necessary.
							 | 
						|
								
							 | 
						|
								  @sideeffect Changes the size of minterm pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out. 
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static void
							 | 
						|
								ResizeCountMintermPages(SubsetInfo_t * info)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    double **newMintermPages;
							 | 
						|
								
							 | 
						|
								    info->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 (info->page == info->maxPages) {
							 | 
						|
									newMintermPages = ALLOC(double *, info->maxPages + INITIAL_PAGES);
							 | 
						|
									if (newMintermPages == NULL) {
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    info->memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < info->maxPages; i++) {
							 | 
						|
										newMintermPages[i] = info->mintermPages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    info->maxPages += INITIAL_PAGES;
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    info->mintermPages = newMintermPages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    info->currentMintermPage = info->mintermPages[info->page] = ALLOC(double,info->pageSize);
							 | 
						|
								    if (info->currentMintermPage == NULL) {
							 | 
						|
									for (i = 0; i < info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									info->memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    info->pageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeCountMintermPages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Resize the number of pages allocated to store the node counts.
							 | 
						|
								
							 | 
						|
								  @details The procedure moves the counter to the next page when the
							 | 
						|
								  end of the page is reached and allocates new pages when necessary.
							 | 
						|
								
							 | 
						|
								  @sideeffect Changes the size of pages, page, page index, maximum
							 | 
						|
								  number of pages freeing stuff in case of memory out.
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static void
							 | 
						|
								ResizeCountNodePages(SubsetInfo_t * info)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    int **newNodePages;
							 | 
						|
								
							 | 
						|
								    info->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 (info->page == info->maxPages) {
							 | 
						|
									newNodePages = ALLOC(int *, info->maxPages + INITIAL_PAGES);
							 | 
						|
									if (newNodePages == NULL) {
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->nodePages[i]);
							 | 
						|
									    FREE(info->nodePages);
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->lightNodePages[i]);
							 | 
						|
									    FREE(info->lightNodePages);
							 | 
						|
									    info->memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < info->maxPages; i++) {
							 | 
						|
										newNodePages[i] = info->nodePages[i];
							 | 
						|
									    }
							 | 
						|
									    FREE(info->nodePages);
							 | 
						|
									    info->nodePages = newNodePages;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									newNodePages = ALLOC(int *, info->maxPages + INITIAL_PAGES);
							 | 
						|
									if (newNodePages == NULL) {
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->nodePages[i]);
							 | 
						|
									    FREE(info->nodePages);
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->lightNodePages[i]);
							 | 
						|
									    FREE(info->lightNodePages);
							 | 
						|
									    info->memOut = 1;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < info->maxPages; i++) {
							 | 
						|
										newNodePages[i] = info->lightNodePages[i];
							 | 
						|
									    }
							 | 
						|
									    FREE(info->lightNodePages);
							 | 
						|
									    info->lightNodePages = newNodePages;
							 | 
						|
									}
							 | 
						|
									/* Increase total page count */
							 | 
						|
									info->maxPages += INITIAL_PAGES;
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    info->currentNodePage = info->nodePages[info->page] = ALLOC(int,info->pageSize);
							 | 
						|
								    if (info->currentNodePage == NULL) {
							 | 
						|
									for (i = 0; i < info->page; i++) FREE(info->nodePages[i]);
							 | 
						|
									FREE(info->nodePages);
							 | 
						|
									for (i = 0; i < info->page; i++) FREE(info->lightNodePages[i]);
							 | 
						|
									FREE(info->lightNodePages);
							 | 
						|
									info->memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    info->currentLightNodePage = info->lightNodePages[info->page]
							 | 
						|
								        = ALLOC(int,info->pageSize);
							 | 
						|
								    if (info->currentLightNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= info->page; i++) FREE(info->nodePages[i]);
							 | 
						|
									FREE(info->nodePages);
							 | 
						|
									for (i = 0; i < info->page; i++) FREE(info->lightNodePages[i]);
							 | 
						|
									FREE(info->lightNodePages);
							 | 
						|
									info->memOut = 1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    info->pageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeCountNodePages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Recursively counts minterms of each node in the DAG.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect Creates structures of type node quality and fills the st_table
							 | 
						|
								
							 | 
						|
								  @see SubsetCountMinterm
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static double
							 | 
						|
								SubsetCountMintermAux(
							 | 
						|
								  DdNode * node /**< function to analyze */,
							 | 
						|
								  double  max /**< number of minterms of constant 1 */,
							 | 
						|
								  st_table * table /**< visitedTable table */,
							 | 
						|
								  SubsetInfo_t * info /**< miscellaneous info */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    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
							 | 
						|
								    info->num_calls++;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Constant case */
							 | 
						|
								    if (Cudd_IsConstantInt(node)) {
							 | 
						|
									if (node == info->zero) {
							 | 
						|
									    return(0.0);
							 | 
						|
									} else {
							 | 
						|
									    return(max);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
								
							 | 
						|
									/* check if entry for this node exists */
							 | 
						|
								        if (st_lookup(table, node, (void **) &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,info)/2.0;
							 | 
						|
									if (info->memOut) return(0.0);
							 | 
						|
									min2 =  SubsetCountMintermAux(Nnv,max,table,info)/2.0;
							 | 
						|
									if (info->memOut) return(0.0);
							 | 
						|
									min = (min1+min2);
							 | 
						|
								
							 | 
						|
									/* if page index is at the bottom, then create a new page */
							 | 
						|
									if (info->pageIndex == info->pageSize) ResizeCountMintermPages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									/* point to the correct location in the page */
							 | 
						|
									pmin = info->currentMintermPage + info->pageIndex;
							 | 
						|
									info->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 (info->nodeDataPageIndex == info->nodeDataPageSize)
							 | 
						|
								            ResizeNodeDataPages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									newEntry = info->currentNodeDataPage + info->nodeDataPageIndex;
							 | 
						|
									info->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) {
							 | 
						|
									    info->memOut = 1;
							 | 
						|
									    for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0.0);
							 | 
						|
									}
							 | 
						|
									return(min);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountMintermAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Counts minterms of each node in the DAG
							 | 
						|
								
							 | 
						|
								  @details Similar to the Cudd_CountMinterm procedure except this
							 | 
						|
								  returns the minterm count for all the nodes in the bdd in an
							 | 
						|
								  st_table.
							 | 
						|
								
							 | 
						|
								  @sideeffect none
							 | 
						|
								
							 | 
						|
								  @see SubsetCountMintermAux
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static st_table *
							 | 
						|
								SubsetCountMinterm(
							 | 
						|
								  DdNode * node /**< function to be analyzed */,
							 | 
						|
								  int nvars /**< number of variables node depends on */,
							 | 
						|
								  SubsetInfo_t * info /**< miscellaneous info */)
							 | 
						|
								{
							 | 
						|
								    st_table	*table;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    info->num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    info->max = pow(2.0,(double) nvars);
							 | 
						|
								    table = st_init_table(st_ptrcmp,st_ptrhash);
							 | 
						|
								    if (table == NULL) goto OUT_OF_MEM;
							 | 
						|
								    info->maxPages = INITIAL_PAGES;
							 | 
						|
								    info->mintermPages = ALLOC(double *,info->maxPages);
							 | 
						|
								    if (info->mintermPages == NULL) {
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    info->page = 0;
							 | 
						|
								    info->currentMintermPage = ALLOC(double,info->pageSize);
							 | 
						|
								    info->mintermPages[info->page] = info->currentMintermPage;
							 | 
						|
								    if (info->currentMintermPage == NULL) {
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    info->pageIndex = 0;
							 | 
						|
								    info->maxNodeDataPages = INITIAL_PAGES;
							 | 
						|
								    info->nodeDataPages = ALLOC(NodeData_t *, info->maxNodeDataPages);
							 | 
						|
								    if (info->nodeDataPages == NULL) {
							 | 
						|
									for (i = 0; i <= info->page ; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    info->nodeDataPage = 0;
							 | 
						|
								    info->currentNodeDataPage = ALLOC(NodeData_t ,info->nodeDataPageSize);
							 | 
						|
								    info->nodeDataPages[info->nodeDataPage] = info->currentNodeDataPage;
							 | 
						|
								    if (info->currentNodeDataPage == NULL) {
							 | 
						|
									for (i = 0; i <= info->page ; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									FREE(info->nodeDataPages);
							 | 
						|
									st_free_table(table);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    info->nodeDataPageIndex = 0;
							 | 
						|
								
							 | 
						|
								    (void) SubsetCountMintermAux(node,info->max,table,info);
							 | 
						|
								    if (info->memOut) goto OUT_OF_MEM;
							 | 
						|
								    return(table);
							 | 
						|
								
							 | 
						|
								OUT_OF_MEM:
							 | 
						|
								    info->memOut = 1;
							 | 
						|
								    return(NULL);
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountMinterm */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Recursively counts the number of nodes under the dag.
							 | 
						|
								  Also counts the number of nodes under the lighter child of
							 | 
						|
								  this node.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect Updates the node data table with node counts
							 | 
						|
								
							 | 
						|
								  @see 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 */,
							 | 
						|
								  SubsetInfo_t * info)
							 | 
						|
								{
							 | 
						|
								    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_IsConstantInt(node))
							 | 
						|
									return(0);
							 | 
						|
								
							 | 
						|
								    /* if this node has been processed do nothing */
							 | 
						|
								    if (st_lookup(table, node, (void **) &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_IsConstantInt(Nv)) {
							 | 
						|
									if (Nv == info->zero) {
							 | 
						|
									    minNv = 0.0;
							 | 
						|
									} else {
							 | 
						|
									    minNv = max;
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (st_lookup(table, Nv, (void **) &dummyNv) == 1)
							 | 
						|
									    minNv = *(dummyNv->mintermPointer);
							 | 
						|
									else {
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsConstantInt(Nnv)) {
							 | 
						|
									if (Nnv == info->zero) {
							 | 
						|
									    minNnv = 0.0;
							 | 
						|
									} else {
							 | 
						|
									    minNnv = max;
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									if (st_lookup(table, Nnv, (void **) &dummyNnv) == 1) {
							 | 
						|
									    minNnv = *(dummyNnv->mintermPointer);
							 | 
						|
									}
							 | 
						|
									else {
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /* recur based on which has larger minterm, */
							 | 
						|
								    if (minNv >= minNnv) {
							 | 
						|
									tval = SubsetCountNodesAux(Nv, table, max, info);
							 | 
						|
									if (info->memOut) return(0);
							 | 
						|
									eval = SubsetCountNodesAux(Nnv, table, max, info);
							 | 
						|
									if (info->memOut) return(0);
							 | 
						|
								
							 | 
						|
									/* store the node count of the lighter child. */
							 | 
						|
									if (info->pageIndex == info->pageSize) ResizeCountNodePages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pmin = info->currentLightNodePage + info->pageIndex;
							 | 
						|
									*pmin = eval; /* Here the ELSE child is lighter */
							 | 
						|
									dummyN->lightChildNodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    } else {
							 | 
						|
									eval = SubsetCountNodesAux(Nnv, table, max, info);
							 | 
						|
									if (info->memOut) return(0);
							 | 
						|
									tval = SubsetCountNodesAux(Nv, table, max, info);
							 | 
						|
									if (info->memOut) return(0);
							 | 
						|
								
							 | 
						|
									/* store the node count of the lighter child. */
							 | 
						|
									if (info->pageIndex == info->pageSize) ResizeCountNodePages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pmin = info->currentLightNodePage + info->pageIndex;
							 | 
						|
									*pmin = tval; /* Here the THEN child is lighter */
							 | 
						|
									dummyN->lightChildNodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								    /* updating the page index for node count storage. */
							 | 
						|
								    pmin = info->currentNodePage + info->pageIndex;
							 | 
						|
								    *pmin = tval + eval + 1;
							 | 
						|
								    dummyN->nodesPointer = pmin;
							 | 
						|
								
							 | 
						|
								    /* pageIndex is parallel page index for count_nodes and count_lightNodes */
							 | 
						|
								    info->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), (void **) &dummyNBar) == 1)  {
							 | 
						|
									if (info->pageIndex == info->pageSize) ResizeCountNodePages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    for (i = 0; i < info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pminBar = info->currentLightNodePage + info->pageIndex;
							 | 
						|
									*pminBar = 0;
							 | 
						|
									dummyNBar->lightChildNodesPointer = pminBar;
							 | 
						|
									/* The lighter child has less nodes than the parent.
							 | 
						|
									 * So if parent 0 then lighter child zero
							 | 
						|
									 */
							 | 
						|
									if (info->pageIndex == info->pageSize) ResizeCountNodePages(info);
							 | 
						|
									if (info->memOut) {
							 | 
						|
									    for (i = 0; i < info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									    FREE(info->mintermPages);
							 | 
						|
									    for (i = 0; i < info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									    FREE(info->nodeDataPages);
							 | 
						|
									    st_free_table(table);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									pminBar = info->currentNodePage + info->pageIndex;
							 | 
						|
									*pminBar = 0;
							 | 
						|
									dummyNBar->nodesPointer = pminBar ; /* maybe should point to zero */
							 | 
						|
								
							 | 
						|
									info->pageIndex++;
							 | 
						|
								    }
							 | 
						|
								    return(*pmin);
							 | 
						|
								} /*end of SubsetCountNodesAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Counts the nodes under the current node and its lighter child.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see SubsetCountNodesAux
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static int
							 | 
						|
								SubsetCountNodes(
							 | 
						|
								  DdNode * node /**< function to be analyzed */,
							 | 
						|
								  st_table * table /**< node quality table */,
							 | 
						|
								  int  nvars /**< number of variables node depends on */,
							 | 
						|
								  SubsetInfo_t * info /**< miscellaneous info */)
							 | 
						|
								{
							 | 
						|
								    int	num;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    info->num_calls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    info->max = pow(2.0,(double) nvars);
							 | 
						|
								    info->maxPages = INITIAL_PAGES;
							 | 
						|
								    info->nodePages = ALLOC(int *, info->maxPages);
							 | 
						|
								    if (info->nodePages == NULL)  {
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info->lightNodePages = ALLOC(int *, info->maxPages);
							 | 
						|
								    if (info->lightNodePages == NULL) {
							 | 
						|
									for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									FREE(info->nodeDataPages);
							 | 
						|
									FREE(info->nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info->page = 0;
							 | 
						|
								    info->currentNodePage = info->nodePages[info->page] =
							 | 
						|
								        ALLOC(int,info->pageSize);
							 | 
						|
								    if (info->currentNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									FREE(info->nodeDataPages);
							 | 
						|
									FREE(info->lightNodePages);
							 | 
						|
									FREE(info->nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info->currentLightNodePage = info->lightNodePages[info->page] =
							 | 
						|
								        ALLOC(int,info->pageSize);
							 | 
						|
								    if (info->currentLightNodePage == NULL) {
							 | 
						|
									for (i = 0; i <= info->page; i++) FREE(info->mintermPages[i]);
							 | 
						|
									FREE(info->mintermPages);
							 | 
						|
									for (i = 0; i <= info->nodeDataPage; i++) FREE(info->nodeDataPages[i]);
							 | 
						|
									FREE(info->nodeDataPages);
							 | 
						|
									FREE(info->currentNodePage);
							 | 
						|
									FREE(info->lightNodePages);
							 | 
						|
									FREE(info->nodePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    info->pageIndex = 0;
							 | 
						|
								    num = SubsetCountNodesAux(node,table,info->max,info);
							 | 
						|
								    if (info->memOut) goto OUT_OF_MEM;
							 | 
						|
								    return(num);
							 | 
						|
								
							 | 
						|
								OUT_OF_MEM:
							 | 
						|
								    info->memOut = 1;
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of SubsetCountNodes */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Procedure to recursively store nodes that are retained in the subset.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								  @see StoreNodes
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								static void
							 | 
						|
								StoreNodes(
							 | 
						|
								  st_table * storeTable,
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  DdNode * node)
							 | 
						|
								{
							 | 
						|
								    DdNode *N, *Nt, *Ne;
							 | 
						|
								    if (Cudd_IsConstantInt(dd)) {
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								    if (st_is_member(storeTable, N)) {
							 | 
						|
									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;
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								  @brief Builds the subset %BDD using the heavy branch method.
							 | 
						|
								
							 | 
						|
								  @details 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.
							 | 
						|
								
							 | 
						|
								  @sideeffect None
							 | 
						|
								
							 | 
						|
								*/
							 | 
						|
								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 /**< subsetting threshold */,
							 | 
						|
								  st_table * storeTable /**< store table */,
							 | 
						|
								  st_table * approxTable /**< approximation table */,
							 | 
						|
								  SubsetInfo_t * info /**< miscellaneous info */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    DdNode *Nv, *Nnv, *N, *topv, *neW;
							 | 
						|
								    double minNv, minNnv;
							 | 
						|
								    NodeData_t *currNodeQual;
							 | 
						|
								    NodeData_t *currNodeQualT;
							 | 
						|
								    NodeData_t *currNodeQualE;
							 | 
						|
								    DdNode *ThenBranch, *ElseBranch;
							 | 
						|
								    int topid;
							 | 
						|
								    void *dummy;
							 | 
						|
								
							 | 
						|
								#ifdef DEBUG
							 | 
						|
								    info->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_IsConstantInt(node))
							 | 
						|
									return(node);
							 | 
						|
								
							 | 
						|
								    /* Look up minterm count for this node. */
							 | 
						|
								    if (!st_lookup(visitedTable, node, (void **) &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_IsConstantInt(Nv)) {
							 | 
						|
									/* find out minterms and nodes contributed by then child */
							 | 
						|
									if (!st_lookup(visitedTable, Nv, (void **) &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 == info->zero) {
							 | 
						|
									    minNv = 0;
							 | 
						|
									} else  {
							 | 
						|
									    minNv = info->max;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    if (!Cudd_IsConstantInt(Nnv)) {
							 | 
						|
									/* find out minterms and nodes contributed by else child */
							 | 
						|
									if (!st_lookup(visitedTable, Nnv, (void **) &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 == info->zero) {
							 | 
						|
									    minNnv = 0;
							 | 
						|
									} else {
							 | 
						|
									    minNnv = info->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, info);
							 | 
						|
									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 = info->zero;
							 | 
						|
								                cuddRef(ElseBranch);
							 | 
						|
								            }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
									/* recur with the Else branch */
							 | 
						|
									ElseBranch = (DdNode *)BuildSubsetBdd(dd, Nnv, size, visitedTable,
							 | 
						|
								                                              threshold, storeTable,
							 | 
						|
								                                              approxTable, info);
							 | 
						|
									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 = info->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 */
							 |