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.
		
		
		
		
		
			
		
			
				
					
					
						
							1660 lines
						
					
					
						
							55 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1660 lines
						
					
					
						
							55 KiB
						
					
					
				
								/**CFile***********************************************************************
							 | 
						|
								
							 | 
						|
								  FileName    [cuddSubsetSP.c]
							 | 
						|
								
							 | 
						|
								  PackageName [cudd]
							 | 
						|
								
							 | 
						|
								  Synopsis [Procedure to subset the given BDD choosing the shortest paths
							 | 
						|
									    (largest cubes) in the BDD.]
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  Description  [External procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> Cudd_SubsetShortPaths()
							 | 
						|
										<li> Cudd_SupersetShortPaths()
							 | 
						|
										</ul>
							 | 
						|
										Internal procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> cuddSubsetShortPaths()
							 | 
						|
										</ul>
							 | 
						|
										Static procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> BuildSubsetBdd()
							 | 
						|
										<li> CreatePathTable()
							 | 
						|
										<li> AssessPathLength()
							 | 
						|
										<li> CreateTopDist()
							 | 
						|
										<li> CreateBotDist()
							 | 
						|
										<li> ResizeNodeDistPages()
							 | 
						|
										<li> ResizeQueuePages()
							 | 
						|
										<li> stPathTableDdFree()
							 | 
						|
										</ul>
							 | 
						|
										]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddSubsetHB.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.]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#define DEFAULT_PAGE_SIZE 2048 /* page size to store the BFS queue element type */
							 | 
						|
								#define DEFAULT_NODE_DIST_PAGE_SIZE 2048 /*  page size to store NodeDist_t type */
							 | 
						|
								#define MAXSHORTINT	((DdHalfWord) ~0) /* constant defined to store
							 | 
						|
													   * maximum distance of a node
							 | 
						|
													   * from the root or the constant
							 | 
						|
													   */
							 | 
						|
								#define INITIAL_PAGES 128 /* number of initial pages for the
							 | 
						|
											   * queue/NodeDist_t type */
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/* structure created to store subset results for each node and distances with
							 | 
						|
								 * odd and even parity of the node from the root and sink. Main data structure
							 | 
						|
								 * in this procedure.
							 | 
						|
								 */
							 | 
						|
								struct NodeDist {
							 | 
						|
								    DdHalfWord oddTopDist;
							 | 
						|
								    DdHalfWord evenTopDist;
							 | 
						|
								    DdHalfWord oddBotDist;
							 | 
						|
								    DdHalfWord evenBotDist;
							 | 
						|
								    DdNode *regResult;
							 | 
						|
								    DdNode *compResult;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/* assorted information needed by the BuildSubsetBdd procedure. */
							 | 
						|
								struct AssortedInfo {
							 | 
						|
								    unsigned int maxpath;
							 | 
						|
								    int findShortestPath;
							 | 
						|
								    int thresholdReached;
							 | 
						|
								    st_table *maxpathTable;
							 | 
						|
								    int threshold;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								struct GlobalInfo {
							 | 
						|
								    struct NodeDist **nodeDistPages; /* pointers to the pages */
							 | 
						|
								    int		nodeDistPageIndex; /* index to next element */
							 | 
						|
								    int		nodeDistPage; /* index to current page */
							 | 
						|
								    int		nodeDistPageSize; /* page size */
							 | 
						|
								    int		maxNodeDistPages; /* number of page pointers */
							 | 
						|
								    struct NodeDist *currentNodeDistPage; /* current page */
							 | 
						|
								    DdNode      ***queuePages; /* pointers to the pages */
							 | 
						|
								    int		queuePageIndex;	/* index to next element */
							 | 
						|
								    int		queuePage; /* index to current page */
							 | 
						|
								    int		queuePageSize; /* page size */
							 | 
						|
								    int		maxQueuePages; /* number of page pointers */
							 | 
						|
								    DdNode      **currentQueuePage; /* current page */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    int         numCalls;
							 | 
						|
								    int         hits;
							 | 
						|
								    int         thishit;
							 | 
						|
								#endif
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								typedef struct NodeDist NodeDist_t;
							 | 
						|
								typedef struct GlobalInfo GlobalInfo_t;
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef lint
							 | 
						|
								static char rcsid[] DD_UNUSED = "$Id: cuddSubsetSP.c,v 1.36 2012/02/05 01:07:19 fabio Exp $";
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifdef __cplusplus
							 | 
						|
								extern "C" {
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/**AutomaticStart*************************************************************/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static void ResizeNodeDistPages (DdManager *dd, GlobalInfo_t *gInfo);
							 | 
						|
								static void ResizeQueuePages (DdManager *dd, GlobalInfo_t *gInfo);
							 | 
						|
								static void CreateTopDist (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, int parentPage, int parentQueueIndex, int topLen, DdNode **childPage, int childQueueIndex, int numParents, FILE *fp);
							 | 
						|
								static int CreateBotDist (DdNode *node, st_table *pathTable, unsigned int *pathLengthArray, FILE *fp);
							 | 
						|
								static st_table * CreatePathTable (DdManager *dd, GlobalInfo_t *gInfo, DdNode *node, unsigned int *pathLengthArray, FILE *fp);
							 | 
						|
								static unsigned int AssessPathLength (unsigned int *pathLengthArray, int threshold, int numVars, unsigned int *excess, FILE *fp);
							 | 
						|
								static DdNode * BuildSubsetBdd (DdManager *dd, GlobalInfo_t *gInfo, st_table *pathTable, DdNode *node, struct AssortedInfo *info, st_table *subsetNodeTable);
							 | 
						|
								static enum st_retval stPathTableDdFree (char *key, char *value, char *arg);
							 | 
						|
								
							 | 
						|
								/**AutomaticEnd***************************************************************/
							 | 
						|
								
							 | 
						|
								#ifdef __cplusplus
							 | 
						|
								}
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of Exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense subset from a BDD with the shortest paths
							 | 
						|
								  heuristic.]
							 | 
						|
								
							 | 
						|
								  Description [Extracts a dense subset from a BDD.  This procedure
							 | 
						|
								  tries to preserve the shortest paths of the input BDD, because they
							 | 
						|
								  give many minterms and contribute few nodes.  This procedure may
							 | 
						|
								  increase the number of nodes in trying to create the subset or
							 | 
						|
								  reduce the number of nodes due to recombination as compared to the
							 | 
						|
								  original BDD. Hence the threshold may not be strictly adhered to. In
							 | 
						|
								  practice, recombination overshadows the increase in the number of
							 | 
						|
								  nodes and results in small BDDs as compared to the threshold. The
							 | 
						|
								  hardlimit specifies whether threshold needs to be strictly adhered
							 | 
						|
								  to. If it is set to 1, the procedure ensures that result is never
							 | 
						|
								  larger than the specified limit but may be considerably less than
							 | 
						|
								  the threshold.  Returns a pointer to the BDD for the subset if
							 | 
						|
								  successful; NULL otherwise.  The value for numVars should be as
							 | 
						|
								  close as possible to the size of the support of f for better
							 | 
						|
								  efficiency. However, it is safe to pass the value returned by
							 | 
						|
								  Cudd_ReadSize for numVars. If 0 is passed, then the value returned
							 | 
						|
								  by Cudd_ReadSize is used.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SupersetShortPaths Cudd_SubsetHeavyBranch Cudd_ReadSize]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_SubsetShortPaths(
							 | 
						|
								  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 */,
							 | 
						|
								  int  hardlimit /* flag: 1 if threshold is a hard limit */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset;
							 | 
						|
								
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetShortPaths(dd, f, numVars, threshold, hardlimit);
							 | 
						|
								    } while(dd->reordered == 1);
							 | 
						|
								
							 | 
						|
								    return(subset);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SubsetShortPaths */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Extracts a dense superset from a BDD with the shortest paths
							 | 
						|
								  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 tries to preserve the shortest
							 | 
						|
								  paths of the complement BDD, because they give many minterms and
							 | 
						|
								  contribute few nodes.  This procedure may increase the number of
							 | 
						|
								  nodes in trying to create the superset or reduce the number of nodes
							 | 
						|
								  due to recombination as compared to the original BDD. Hence the
							 | 
						|
								  threshold may not be strictly adhered to. In practice, recombination
							 | 
						|
								  overshadows the increase in the number of nodes and results in small
							 | 
						|
								  BDDs as compared to the threshold.  The hardlimit specifies whether
							 | 
						|
								  threshold needs to be strictly adhered to. If it is set to 1, the
							 | 
						|
								  procedure ensures that result is never larger than the specified
							 | 
						|
								  limit but may be considerably less than the threshold. Returns a
							 | 
						|
								  pointer to the BDD for the superset if successful; NULL
							 | 
						|
								  otherwise. The value for numVars should be as close as possible to
							 | 
						|
								  the size of the support of f for better efficiency.  However, it is
							 | 
						|
								  safe to pass the value returned by Cudd_ReadSize for numVar.  If 0
							 | 
						|
								  is passed, then the value returned by Cudd_ReadSize is used.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SubsetShortPaths Cudd_SupersetHeavyBranch Cudd_ReadSize]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								Cudd_SupersetShortPaths(
							 | 
						|
								  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 subset */,
							 | 
						|
								  int  hardlimit /* flag: 1 if threshold is a hard limit */)
							 | 
						|
								{
							 | 
						|
								    DdNode *subset, *g;
							 | 
						|
								
							 | 
						|
								    g = Cudd_Not(f);
							 | 
						|
								    do {
							 | 
						|
									dd->reordered = 0;
							 | 
						|
									subset = cuddSubsetShortPaths(dd, g, numVars, threshold, hardlimit);
							 | 
						|
								    } while(dd->reordered == 1);
							 | 
						|
								
							 | 
						|
								    return(Cudd_NotCond(subset, (subset != NULL)));
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_SupersetShortPaths */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [The outermost procedure to return a subset of the given BDD
							 | 
						|
								  with the shortest path lengths.]
							 | 
						|
								
							 | 
						|
								  Description [The outermost procedure to return a subset of the given
							 | 
						|
								  BDD with the largest cubes. The path lengths are calculated, the maximum
							 | 
						|
								  allowable path length is determined and the number of nodes of this
							 | 
						|
								  path length that can be used to build a subset. If the threshold is
							 | 
						|
								  larger than the size of the original BDD, the original BDD is
							 | 
						|
								  returned. ]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_SubsetShortPaths]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddSubsetShortPaths(
							 | 
						|
								  DdManager * dd /* DD manager */,
							 | 
						|
								  DdNode * f /* function to be subset */,
							 | 
						|
								  int  numVars /* total number of variables in consideration */,
							 | 
						|
								  int  threshold /* maximum number of nodes allowed in the subset */,
							 | 
						|
								  int  hardlimit /* flag determining whether threshold should be respected strictly */)
							 | 
						|
								{
							 | 
						|
								    GlobalInfo_t gInfo;
							 | 
						|
								    st_table *pathTable;
							 | 
						|
								    DdNode *N, *subset;
							 | 
						|
								
							 | 
						|
								    unsigned int  *pathLengthArray;
							 | 
						|
								    unsigned int maxpath, oddLen, evenLen, pathLength, *excess;
							 | 
						|
								    int i;
							 | 
						|
								    NodeDist_t	*nodeStat;
							 | 
						|
								    struct AssortedInfo *info;
							 | 
						|
								    st_table *subsetNodeTable;
							 | 
						|
								
							 | 
						|
								    gInfo.nodeDistPageSize = DEFAULT_NODE_DIST_PAGE_SIZE;
							 | 
						|
								    gInfo.queuePageSize = DEFAULT_PAGE_SIZE;
							 | 
						|
								
							 | 
						|
								    if (numVars == 0) {
							 | 
						|
								      /* set default value */
							 | 
						|
								      numVars = Cudd_ReadSize(dd);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (threshold > numVars) {
							 | 
						|
									threshold = threshold - numVars;
							 | 
						|
								    }
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									fprintf(dd->err, "Cannot partition, nil object\n");
							 | 
						|
									dd->errorCode = CUDD_INVALID_ARG;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    if (Cudd_IsConstant(f))
							 | 
						|
									return (f);
							 | 
						|
								
							 | 
						|
								    pathLengthArray = ALLOC(unsigned int, numVars+1);
							 | 
						|
								    for (i = 0; i < numVars+1; i++) pathLengthArray[i] = 0;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    gInfo.numCalls = 0;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    pathTable = CreatePathTable(dd, &gInfo, f, pathLengthArray, dd->err);
							 | 
						|
								
							 | 
						|
								    if ((pathTable == NULL) || (dd->errorCode == CUDD_MEMORY_OUT)) {
							 | 
						|
									if (pathTable != NULL)
							 | 
						|
									    st_free_table(pathTable);
							 | 
						|
									FREE(pathLengthArray);
							 | 
						|
									return (NIL(DdNode));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    excess = ALLOC(unsigned int, 1);
							 | 
						|
								    *excess = 0;
							 | 
						|
								    maxpath = AssessPathLength(pathLengthArray, threshold, numVars, excess,
							 | 
						|
											       dd->err);
							 | 
						|
								
							 | 
						|
								    if (maxpath != (unsigned) (numVars + 1)) {
							 | 
						|
								
							 | 
						|
									info = ALLOC(struct AssortedInfo, 1);
							 | 
						|
									info->maxpath = maxpath;
							 | 
						|
									info->findShortestPath = 0;
							 | 
						|
									info->thresholdReached = *excess;
							 | 
						|
									info->maxpathTable = st_init_table(st_ptrcmp, st_ptrhash);
							 | 
						|
									info->threshold = threshold;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									(void) fprintf(dd->out, "Path length array\n");
							 | 
						|
									for (i = 0; i < (numVars+1); i++) {
							 | 
						|
									    if (pathLengthArray[i])
							 | 
						|
										(void) fprintf(dd->out, "%d ",i);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(dd->out, "\n");
							 | 
						|
									for (i = 0; i < (numVars+1); i++) {
							 | 
						|
									    if (pathLengthArray[i])
							 | 
						|
										(void) fprintf(dd->out, "%d ",pathLengthArray[i]);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(dd->out, "\n");
							 | 
						|
									(void) fprintf(dd->out, "Maxpath  = %d, Thresholdreached = %d\n",
							 | 
						|
										       maxpath, info->thresholdReached);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
									N = Cudd_Regular(f);
							 | 
						|
									if (!st_lookup(pathTable, N, &nodeStat)) {
							 | 
						|
									    fprintf(dd->err, "Something wrong, root node must be in table\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    FREE(excess);
							 | 
						|
									    FREE(info);
							 | 
						|
									    return(NULL);
							 | 
						|
									} else {
							 | 
						|
									    if ((nodeStat->oddTopDist != MAXSHORTINT) &&
							 | 
						|
										(nodeStat->oddBotDist != MAXSHORTINT))
							 | 
						|
										oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
							 | 
						|
									    else
							 | 
						|
										oddLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
									    if ((nodeStat->evenTopDist != MAXSHORTINT) &&
							 | 
						|
										(nodeStat->evenBotDist != MAXSHORTINT))
							 | 
						|
										evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
							 | 
						|
									    else
							 | 
						|
										evenLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
									    pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
							 | 
						|
									    if (pathLength > maxpath) {
							 | 
						|
										(void) fprintf(dd->err, "All computations are bogus, since root has path length greater than max path length within threshold %u, %u\n", maxpath, pathLength);
							 | 
						|
										dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									gInfo.numCalls = 0;
							 | 
						|
									gInfo.hits = 0;
							 | 
						|
									gInfo.thishit = 0;
							 | 
						|
								#endif
							 | 
						|
									/* initialize a table to store computed nodes */
							 | 
						|
									if (hardlimit) {
							 | 
						|
									    subsetNodeTable = st_init_table(st_ptrcmp, st_ptrhash);
							 | 
						|
									} else {
							 | 
						|
									    subsetNodeTable = NIL(st_table);
							 | 
						|
									}
							 | 
						|
									subset = BuildSubsetBdd(dd, &gInfo, pathTable, f, info, subsetNodeTable);
							 | 
						|
									if (subset != NULL) {
							 | 
						|
									    cuddRef(subset);
							 | 
						|
									}
							 | 
						|
									/* record the number of times a computed result for a node is hit */
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									(void) fprintf(dd->out, "Hits = %d, New==Node = %d, NumCalls = %d\n",
							 | 
						|
										gInfo.hits, gInfo.thishit, gInfo.numCalls);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
									if (subsetNodeTable != NIL(st_table)) {
							 | 
						|
									    st_free_table(subsetNodeTable);
							 | 
						|
									}
							 | 
						|
									st_free_table(info->maxpathTable);
							 | 
						|
									st_foreach(pathTable, stPathTableDdFree, (char *)dd);
							 | 
						|
								
							 | 
						|
									FREE(info);
							 | 
						|
								
							 | 
						|
								    } else {/* if threshold larger than size of dd */
							 | 
						|
									subset = f;
							 | 
						|
									cuddRef(subset);
							 | 
						|
								    }
							 | 
						|
								    FREE(excess);
							 | 
						|
								    st_free_table(pathTable);
							 | 
						|
								    FREE(pathLengthArray);
							 | 
						|
								    for (i = 0; i <= gInfo.nodeDistPage; i++) FREE(gInfo.nodeDistPages[i]);
							 | 
						|
								    FREE(gInfo.nodeDistPages);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* check containment of subset in f */
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									if (!Cudd_bddLeq(dd, subset, f)) {
							 | 
						|
									    (void) fprintf(dd->err, "Wrong partition\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (subset != NULL) {
							 | 
						|
									cuddDeref(subset);
							 | 
						|
									return(subset);
							 | 
						|
								    } else {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								} /* end of cuddSubsetShortPaths */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Resize the number of pages allocated to store the distances
							 | 
						|
								  related to each node.]
							 | 
						|
								
							 | 
						|
								  Description [Resize the number of pages allocated to store the distances
							 | 
						|
								  related to each node. 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
							 | 
						|
								ResizeNodeDistPages(
							 | 
						|
								  DdManager *dd /* DD manager */,
							 | 
						|
								  GlobalInfo_t *gInfo /* global information */)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    NodeDist_t **newNodeDistPages;
							 | 
						|
								
							 | 
						|
								    /* move to next page */
							 | 
						|
								    gInfo->nodeDistPage++;
							 | 
						|
								
							 | 
						|
								    /* 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 (gInfo->nodeDistPage == gInfo->maxNodeDistPages) {
							 | 
						|
									newNodeDistPages = ALLOC(NodeDist_t *,gInfo->maxNodeDistPages + INITIAL_PAGES);
							 | 
						|
									if (newNodeDistPages == NULL) {
							 | 
						|
									    for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
							 | 
						|
									    FREE(gInfo->nodeDistPages);
							 | 
						|
									    dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < gInfo->maxNodeDistPages; i++) {
							 | 
						|
										newNodeDistPages[i] = gInfo->nodeDistPages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    gInfo->maxNodeDistPages += INITIAL_PAGES;
							 | 
						|
									    FREE(gInfo->nodeDistPages);
							 | 
						|
									    gInfo->nodeDistPages = newNodeDistPages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
							 | 
						|
								        ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
							 | 
						|
								    if (gInfo->currentNodeDistPage == NULL) {
							 | 
						|
									for (i = 0; i < gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
							 | 
						|
									FREE(gInfo->nodeDistPages);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    gInfo->nodeDistPageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeNodeDistPages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Resize the number of pages allocated to store nodes in the BFS
							 | 
						|
								  traversal of the Bdd  .]
							 | 
						|
								
							 | 
						|
								  Description [Resize the number of pages allocated to store nodes in the BFS
							 | 
						|
								  traversal of the Bdd. 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
							 | 
						|
								ResizeQueuePages(
							 | 
						|
								  DdManager *dd /* DD manager */,
							 | 
						|
								  GlobalInfo_t *gInfo /* global information */)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    DdNode ***newQueuePages;
							 | 
						|
								
							 | 
						|
								    gInfo->queuePage++;
							 | 
						|
								    /* 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 (gInfo->queuePage == gInfo->maxQueuePages) {
							 | 
						|
									newQueuePages = ALLOC(DdNode **,gInfo->maxQueuePages + INITIAL_PAGES);
							 | 
						|
									if (newQueuePages == NULL) {
							 | 
						|
									    for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
									    FREE(gInfo->queuePages);
							 | 
						|
									    dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return;
							 | 
						|
									} else {
							 | 
						|
									    for (i = 0; i < gInfo->maxQueuePages; i++) {
							 | 
						|
										newQueuePages[i] = gInfo->queuePages[i];
							 | 
						|
									    }
							 | 
						|
									    /* Increase total page count */
							 | 
						|
									    gInfo->maxQueuePages += INITIAL_PAGES;
							 | 
						|
									    FREE(gInfo->queuePages);
							 | 
						|
									    gInfo->queuePages = newQueuePages;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Allocate a new page */
							 | 
						|
								    gInfo->currentQueuePage = gInfo->queuePages[gInfo->queuePage] =
							 | 
						|
								        ALLOC(DdNode *,gInfo->queuePageSize);
							 | 
						|
								    if (gInfo->currentQueuePage == NULL) {
							 | 
						|
									for (i = 0; i < gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
									FREE(gInfo->queuePages);
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    /* reset page index */
							 | 
						|
								    gInfo->queuePageIndex = 0;
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ResizeQueuePages */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [ Labels each node with its shortest distance from the root]
							 | 
						|
								
							 | 
						|
								  Description [ Labels each node with its shortest distance from the root.
							 | 
						|
								  This is done in a BFS search of the BDD. The nodes are processed
							 | 
						|
								  in a queue implemented as pages(array) to reduce memory fragmentation.
							 | 
						|
								  An entry is created for each node visited. The distance from the root
							 | 
						|
								  to the node with the corresponding  parity is updated. The procedure
							 | 
						|
								  is called recursively each recusion level handling nodes at a given
							 | 
						|
								  level from the root.]
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								  SideEffects [Creates entries in the pathTable]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [CreatePathTable CreateBotDist]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								CreateTopDist(
							 | 
						|
								  DdManager *dd /* DD manager */,
							 | 
						|
								  GlobalInfo_t *gInfo /* global information */,
							 | 
						|
								  st_table * pathTable /* hast table to store path lengths */,
							 | 
						|
								  int  parentPage /* the pointer to the page on which the first parent in the queue is to be found. */,
							 | 
						|
								  int  parentQueueIndex /* pointer to the first parent on the page */,
							 | 
						|
								  int  topLen /* current distance from the root */,
							 | 
						|
								  DdNode ** childPage /* pointer to the page on which the first child is to be added. */,
							 | 
						|
								  int  childQueueIndex /* pointer to the first child */,
							 | 
						|
								  int  numParents /* number of parents to process in this recursive call */,
							 | 
						|
								  FILE *fp /* where to write messages */)
							 | 
						|
								{
							 | 
						|
								    NodeDist_t *nodeStat;
							 | 
						|
								    DdNode *N, *Nv, *Nnv, *node, *child, *regChild;
							 | 
						|
								    int  i;
							 | 
						|
								    int processingDone, childrenCount;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    gInfo->numCalls++;
							 | 
						|
								
							 | 
						|
								    /* assume this procedure comes in with only the root node*/
							 | 
						|
								    /* set queue index to the next available entry for addition */
							 | 
						|
								    /* set queue page to page of addition */
							 | 
						|
								    if ((gInfo->queuePages[parentPage] == childPage) && (parentQueueIndex ==
							 | 
						|
														  childQueueIndex)) {
							 | 
						|
									fprintf(fp, "Should not happen that they are equal\n");
							 | 
						|
								    }
							 | 
						|
								    assert(gInfo->queuePageIndex == childQueueIndex);
							 | 
						|
								    assert(gInfo->currentQueuePage == childPage);
							 | 
						|
								#endif
							 | 
						|
								    /* number children added to queue is initialized , needed for
							 | 
						|
								     * numParents in the next call
							 | 
						|
								     */
							 | 
						|
								    childrenCount = 0;
							 | 
						|
								    /* process all the nodes in this level */
							 | 
						|
								    while (numParents) {
							 | 
						|
									numParents--;
							 | 
						|
									if (parentQueueIndex == gInfo->queuePageSize) {
							 | 
						|
									    parentPage++;
							 | 
						|
									    parentQueueIndex = 0;
							 | 
						|
									}
							 | 
						|
									/* a parent to process */
							 | 
						|
									node = *(gInfo->queuePages[parentPage] + parentQueueIndex);
							 | 
						|
									parentQueueIndex++;
							 | 
						|
									/* get its children */
							 | 
						|
									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));
							 | 
						|
								
							 | 
						|
									processingDone = 2;
							 | 
						|
									while (processingDone) {
							 | 
						|
									    /* processing the THEN and the ELSE children, the THEN
							 | 
						|
									     * child first
							 | 
						|
									     */
							 | 
						|
									    if (processingDone == 2) {
							 | 
						|
										child = Nv;
							 | 
						|
									    } else {
							 | 
						|
										child = Nnv;
							 | 
						|
									    }
							 | 
						|
								
							 | 
						|
									    regChild = Cudd_Regular(child);
							 | 
						|
									    /* dont process if the child is a constant */
							 | 
						|
									    if (!Cudd_IsConstant(child)) {
							 | 
						|
										/* check is already visited, if not add a new entry in
							 | 
						|
										 * the path Table
							 | 
						|
										 */
							 | 
						|
										if (!st_lookup(pathTable, regChild, &nodeStat)) {
							 | 
						|
										    /* if not in table, has never been visited */
							 | 
						|
										    /* create entry for table */
							 | 
						|
										    if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize)
							 | 
						|
											ResizeNodeDistPages(dd, gInfo);
							 | 
						|
										    if (dd->errorCode == CUDD_MEMORY_OUT) {
							 | 
						|
											for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
											FREE(gInfo->queuePages);
							 | 
						|
											st_free_table(pathTable);
							 | 
						|
											return;
							 | 
						|
										    }
							 | 
						|
										    /* New entry for child in path Table is created here */
							 | 
						|
										    nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
							 | 
						|
										    gInfo->nodeDistPageIndex++;
							 | 
						|
								
							 | 
						|
										    /* Initialize fields of the node data */
							 | 
						|
										    nodeStat->oddTopDist = MAXSHORTINT;
							 | 
						|
										    nodeStat->evenTopDist = MAXSHORTINT;
							 | 
						|
										    nodeStat->evenBotDist = MAXSHORTINT;
							 | 
						|
										    nodeStat->oddBotDist = MAXSHORTINT;
							 | 
						|
										    nodeStat->regResult = NULL;
							 | 
						|
										    nodeStat->compResult = NULL;
							 | 
						|
										    /* update the table entry element, the distance keeps
							 | 
						|
										     * track of the parity of the path from the root
							 | 
						|
										     */
							 | 
						|
										    if (Cudd_IsComplement(child)) {
							 | 
						|
											nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
							 | 
						|
										    } else {
							 | 
						|
											nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
							 | 
						|
										    }
							 | 
						|
								
							 | 
						|
										    /* insert entry element for child in the table */
							 | 
						|
										    if (st_insert(pathTable, regChild,
							 | 
						|
												  nodeStat) == ST_OUT_OF_MEM) {
							 | 
						|
											dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
											for (i = 0; i <= gInfo->nodeDistPage; i++)
							 | 
						|
											    FREE(gInfo->nodeDistPages[i]);
							 | 
						|
											FREE(gInfo->nodeDistPages);
							 | 
						|
											for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
											FREE(gInfo->queuePages);
							 | 
						|
											st_free_table(pathTable);
							 | 
						|
											return;
							 | 
						|
										    }
							 | 
						|
								
							 | 
						|
										    /* Create list element for this child to process its children.
							 | 
						|
										     * If this node has been processed already, then it appears
							 | 
						|
										     * in the path table and hence is never added to the list
							 | 
						|
										     * again.
							 | 
						|
										     */
							 | 
						|
								
							 | 
						|
										    if (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
							 | 
						|
										    if (dd->errorCode == CUDD_MEMORY_OUT) {
							 | 
						|
											for (i = 0; i <= gInfo->nodeDistPage; i++)
							 | 
						|
											    FREE(gInfo->nodeDistPages[i]);
							 | 
						|
											FREE(gInfo->nodeDistPages);
							 | 
						|
											st_free_table(pathTable);
							 | 
						|
											return;
							 | 
						|
										    }
							 | 
						|
										    *(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
							 | 
						|
										    gInfo->queuePageIndex++;
							 | 
						|
								
							 | 
						|
										    childrenCount++;
							 | 
						|
										} else {
							 | 
						|
										    /* if not been met in a path with this parity before */
							 | 
						|
										    /* put in list */
							 | 
						|
										    if (((Cudd_IsComplement(child)) && (nodeStat->oddTopDist ==
							 | 
						|
											  MAXSHORTINT)) || ((!Cudd_IsComplement(child)) &&
							 | 
						|
												  (nodeStat->evenTopDist == MAXSHORTINT))) {
							 | 
						|
								
							 | 
						|
											if (gInfo->queuePageIndex == gInfo->queuePageSize) ResizeQueuePages(dd, gInfo);
							 | 
						|
											if (dd->errorCode == CUDD_MEMORY_OUT) {
							 | 
						|
											    for (i = 0; i <= gInfo->nodeDistPage; i++)
							 | 
						|
												FREE(gInfo->nodeDistPages[i]);
							 | 
						|
											    FREE(gInfo->nodeDistPages);
							 | 
						|
											    st_free_table(pathTable);
							 | 
						|
											    return;
							 | 
						|
								
							 | 
						|
											}
							 | 
						|
											*(gInfo->currentQueuePage + gInfo->queuePageIndex) = child;
							 | 
						|
											gInfo->queuePageIndex++;
							 | 
						|
								
							 | 
						|
											/* update the distance with the appropriate parity */
							 | 
						|
											if (Cudd_IsComplement(child)) {
							 | 
						|
											    nodeStat->oddTopDist = (DdHalfWord) topLen + 1;
							 | 
						|
											} else {
							 | 
						|
											    nodeStat->evenTopDist = (DdHalfWord) topLen + 1;
							 | 
						|
											}
							 | 
						|
											childrenCount++;
							 | 
						|
										    }
							 | 
						|
								
							 | 
						|
										} /* end of else (not found in st_table) */
							 | 
						|
									    } /*end of if Not constant child */
							 | 
						|
									    processingDone--;
							 | 
						|
									} /*end of while processing Nv, Nnv */
							 | 
						|
								    }  /*end of while numParents */
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    assert(gInfo->queuePages[parentPage] == childPage);
							 | 
						|
								    assert(parentQueueIndex == childQueueIndex);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (childrenCount != 0) {
							 | 
						|
									topLen++;
							 | 
						|
									childPage = gInfo->currentQueuePage;
							 | 
						|
									childQueueIndex = gInfo->queuePageIndex;
							 | 
						|
									CreateTopDist(dd, gInfo, pathTable, parentPage, parentQueueIndex, topLen,
							 | 
						|
										      childPage, childQueueIndex, childrenCount, fp);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of CreateTopDist */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [ Labels each node with the shortest distance from the constant.]
							 | 
						|
								
							 | 
						|
								  Description [Labels each node with the shortest distance from the constant.
							 | 
						|
								  This is done in a DFS search of the BDD. Each node has an odd
							 | 
						|
								  and even parity distance from the sink (since there exists paths to both
							 | 
						|
								  zero and one) which is less than MAXSHORTINT. At each node these distances
							 | 
						|
								  are updated using the minimum distance of its children from the constant.
							 | 
						|
								  SInce now both the length from the root and child is known, the minimum path
							 | 
						|
								  length(length of the shortest path between the root and the constant that
							 | 
						|
								  this node lies on) of this node can be calculated and used to update the
							 | 
						|
								  pathLengthArray]
							 | 
						|
								
							 | 
						|
								  SideEffects [Updates Path Table and path length array]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [CreatePathTable CreateTopDist AssessPathLength]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								CreateBotDist(
							 | 
						|
								  DdNode * node /* current node */,
							 | 
						|
								  st_table * pathTable /* path table with path lengths */,
							 | 
						|
								  unsigned int * pathLengthArray /* array that stores number of nodes belonging to a particular path length. */,
							 | 
						|
								  FILE *fp /* where to write messages */)
							 | 
						|
								{
							 | 
						|
								    DdNode *N, *Nv, *Nnv;
							 | 
						|
								    DdNode *realChild;
							 | 
						|
								    DdNode *child, *regChild;
							 | 
						|
								    NodeDist_t *nodeStat, *nodeStatChild;
							 | 
						|
								    unsigned int  oddLen, evenLen, pathLength;
							 | 
						|
								    DdHalfWord botDist;
							 | 
						|
								    int processingDone;
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsConstant(node))
							 | 
						|
									return(1);
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								    /* each node has one table entry */
							 | 
						|
								    /* update as you go down the min dist of each node from
							 | 
						|
								       the root in each (odd and even) parity */
							 | 
						|
								    if (!st_lookup(pathTable, N, &nodeStat)) {
							 | 
						|
									fprintf(fp, "Something wrong, the entry doesn't exist\n");
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* compute length of odd parity distances */
							 | 
						|
								    if ((nodeStat->oddTopDist != MAXSHORTINT) &&
							 | 
						|
									(nodeStat->oddBotDist != MAXSHORTINT))
							 | 
						|
									oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
							 | 
						|
								    else
							 | 
						|
									oddLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
								    /* compute length of even parity distances */
							 | 
						|
								    if (!((nodeStat->evenTopDist == MAXSHORTINT) ||
							 | 
						|
									  (nodeStat->evenBotDist == MAXSHORTINT)))
							 | 
						|
									evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
							 | 
						|
								    else
							 | 
						|
									evenLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
								    /* assign pathlength to minimum of the two */
							 | 
						|
								    pathLength = (oddLen <= evenLen) ? oddLen : evenLen;
							 | 
						|
								
							 | 
						|
								    Nv = Cudd_T(N);
							 | 
						|
								    Nnv = Cudd_E(N);
							 | 
						|
								
							 | 
						|
								    /* process each child */
							 | 
						|
								    processingDone = 0;
							 | 
						|
								    while (processingDone != 2) {
							 | 
						|
									if (!processingDone) {
							 | 
						|
									    child = Nv;
							 | 
						|
									} else {
							 | 
						|
									    child = Nnv;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									realChild = Cudd_NotCond(child, Cudd_IsComplement(node));
							 | 
						|
									regChild = Cudd_Regular(child);
							 | 
						|
									if (Cudd_IsConstant(realChild)) {
							 | 
						|
									    /* Found a minterm; count parity and shortest distance
							 | 
						|
									    ** from the constant.
							 | 
						|
									    */
							 | 
						|
									    if (Cudd_IsComplement(child))
							 | 
						|
										nodeStat->oddBotDist = 1;
							 | 
						|
									    else
							 | 
						|
										nodeStat->evenBotDist = 1;
							 | 
						|
									} else {
							 | 
						|
									    /* If node not in table, recur. */
							 | 
						|
									    if (!st_lookup(pathTable, regChild, &nodeStatChild)) {
							 | 
						|
										fprintf(fp, "Something wrong, node in table should have been created in top dist proc.\n");
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
								
							 | 
						|
									    if (nodeStatChild->oddBotDist == MAXSHORTINT) {
							 | 
						|
										if (nodeStatChild->evenBotDist == MAXSHORTINT) {
							 | 
						|
										    if (!CreateBotDist(realChild, pathTable, pathLengthArray, fp))
							 | 
						|
											return(0);
							 | 
						|
										} else {
							 | 
						|
										    fprintf(fp, "Something wrong, both bot nodeStats should be there\n");
							 | 
						|
										    return(0);
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
								
							 | 
						|
									    /* Update shortest distance from the constant depending on
							 | 
						|
									    **  parity. */
							 | 
						|
								
							 | 
						|
									    if (Cudd_IsComplement(child)) {
							 | 
						|
										/* If parity on the edge then add 1 to even distance
							 | 
						|
										** of child to get odd parity distance and add 1 to
							 | 
						|
										** odd distance of child to get even parity
							 | 
						|
										** distance. Change distance of current node only if
							 | 
						|
										** the calculated distance is less than existing
							 | 
						|
										** distance. */
							 | 
						|
										if (nodeStatChild->oddBotDist != MAXSHORTINT)
							 | 
						|
										    botDist = nodeStatChild->oddBotDist + 1;
							 | 
						|
										else
							 | 
						|
										    botDist = MAXSHORTINT;
							 | 
						|
										if (nodeStat->evenBotDist > botDist )
							 | 
						|
										    nodeStat->evenBotDist = botDist;
							 | 
						|
								
							 | 
						|
										if (nodeStatChild->evenBotDist != MAXSHORTINT)
							 | 
						|
										    botDist = nodeStatChild->evenBotDist + 1;
							 | 
						|
										else
							 | 
						|
										    botDist = MAXSHORTINT;
							 | 
						|
										if (nodeStat->oddBotDist > botDist)
							 | 
						|
										    nodeStat->oddBotDist = botDist;
							 | 
						|
								
							 | 
						|
									    } else {
							 | 
						|
										/* If parity on the edge then add 1 to even distance
							 | 
						|
										** of child to get even parity distance and add 1 to
							 | 
						|
										** odd distance of child to get odd parity distance.
							 | 
						|
										** Change distance of current node only if the
							 | 
						|
										** calculated distance is lesser than existing
							 | 
						|
										** distance. */
							 | 
						|
										if (nodeStatChild->evenBotDist != MAXSHORTINT)
							 | 
						|
										    botDist = nodeStatChild->evenBotDist + 1;
							 | 
						|
										else
							 | 
						|
										    botDist = MAXSHORTINT;
							 | 
						|
										if (nodeStat->evenBotDist > botDist)
							 | 
						|
										    nodeStat->evenBotDist = botDist;
							 | 
						|
								
							 | 
						|
										if (nodeStatChild->oddBotDist != MAXSHORTINT)
							 | 
						|
										    botDist = nodeStatChild->oddBotDist + 1;
							 | 
						|
										else
							 | 
						|
										    botDist = MAXSHORTINT;
							 | 
						|
										if (nodeStat->oddBotDist > botDist)
							 | 
						|
										    nodeStat->oddBotDist = botDist;
							 | 
						|
									    }
							 | 
						|
									} /* end of else (if not constant child ) */
							 | 
						|
									processingDone++;
							 | 
						|
								    } /* end of while processing Nv, Nnv */
							 | 
						|
								
							 | 
						|
								    /* Compute shortest path length on the fly. */
							 | 
						|
								    if ((nodeStat->oddTopDist != MAXSHORTINT) &&
							 | 
						|
									(nodeStat->oddBotDist != MAXSHORTINT))
							 | 
						|
									oddLen = (nodeStat->oddTopDist + nodeStat->oddBotDist);
							 | 
						|
								    else
							 | 
						|
									oddLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
								    if ((nodeStat->evenTopDist != MAXSHORTINT) &&
							 | 
						|
									(nodeStat->evenBotDist != MAXSHORTINT))
							 | 
						|
									evenLen = (nodeStat->evenTopDist +nodeStat->evenBotDist);
							 | 
						|
								    else
							 | 
						|
									evenLen = MAXSHORTINT;
							 | 
						|
								
							 | 
						|
								    /* Update path length array that has number of nodes of a particular
							 | 
						|
								    ** path length. */
							 | 
						|
								    if (oddLen < pathLength ) {
							 | 
						|
									if (pathLength != MAXSHORTINT)
							 | 
						|
									    pathLengthArray[pathLength]--;
							 | 
						|
									if (oddLen != MAXSHORTINT)
							 | 
						|
									    pathLengthArray[oddLen]++;
							 | 
						|
									pathLength = oddLen;
							 | 
						|
								    }
							 | 
						|
								    if (evenLen < pathLength ) {
							 | 
						|
									if (pathLength != MAXSHORTINT)
							 | 
						|
									    pathLengthArray[pathLength]--;
							 | 
						|
									if (evenLen != MAXSHORTINT)
							 | 
						|
									    pathLengthArray[evenLen]++;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /*end of CreateBotDist */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [ The outer procedure to label each node with its shortest
							 | 
						|
								  distance from the root and constant]
							 | 
						|
								
							 | 
						|
								  Description [ The outer procedure to label each node with its shortest
							 | 
						|
								  distance from the root and constant. Calls CreateTopDist and CreateBotDist.
							 | 
						|
								  The basis for computing the distance between root and constant is that
							 | 
						|
								  the distance may be the sum of even distances from the node to the root
							 | 
						|
								  and constant or the sum of odd distances from the node to the root and
							 | 
						|
								  constant.  Both CreateTopDist and CreateBotDist create the odd and
							 | 
						|
								  even parity distances from the root and constant respectively.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [CreateTopDist CreateBotDist]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static st_table *
							 | 
						|
								CreatePathTable(
							 | 
						|
								  DdManager *dd /* DD manager */,
							 | 
						|
								  GlobalInfo_t *gInfo /* global information */,
							 | 
						|
								  DdNode * node /* root of function */,
							 | 
						|
								  unsigned int * pathLengthArray /* array of path lengths to store nodes labeled with the various path lengths */,
							 | 
						|
								  FILE *fp /* where to write messages */)
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    st_table *pathTable;
							 | 
						|
								    NodeDist_t *nodeStat;
							 | 
						|
								    DdHalfWord topLen;
							 | 
						|
								    DdNode *N;
							 | 
						|
								    int i, numParents;
							 | 
						|
								    int insertValue;
							 | 
						|
								    DdNode **childPage;
							 | 
						|
								    int parentPage;
							 | 
						|
								    int childQueueIndex, parentQueueIndex;
							 | 
						|
								
							 | 
						|
								    /* Creating path Table for storing data about nodes */
							 | 
						|
								    pathTable = st_init_table(st_ptrcmp,st_ptrhash);
							 | 
						|
								
							 | 
						|
								    /* initializing pages for info about each node */
							 | 
						|
								    gInfo->maxNodeDistPages = INITIAL_PAGES;
							 | 
						|
								    gInfo->nodeDistPages = ALLOC(NodeDist_t *, gInfo->maxNodeDistPages);
							 | 
						|
								    if (gInfo->nodeDistPages == NULL) {
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    gInfo->nodeDistPage = 0;
							 | 
						|
								    gInfo->currentNodeDistPage = gInfo->nodeDistPages[gInfo->nodeDistPage] =
							 | 
						|
									ALLOC(NodeDist_t, gInfo->nodeDistPageSize);
							 | 
						|
								    if (gInfo->currentNodeDistPage == NULL) {
							 | 
						|
									for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
							 | 
						|
									FREE(gInfo->nodeDistPages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    gInfo->nodeDistPageIndex = 0;
							 | 
						|
								
							 | 
						|
								    /* Initializing pages for the BFS search queue, implemented as an array. */
							 | 
						|
								    gInfo->maxQueuePages = INITIAL_PAGES;
							 | 
						|
								    gInfo->queuePages = ALLOC(DdNode **, gInfo->maxQueuePages);
							 | 
						|
								    if (gInfo->queuePages == NULL) {
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    gInfo->queuePage = 0;
							 | 
						|
								    gInfo->currentQueuePage  = gInfo->queuePages[gInfo->queuePage] =
							 | 
						|
								        ALLOC(DdNode *, gInfo->queuePageSize);
							 | 
						|
								    if (gInfo->currentQueuePage == NULL) {
							 | 
						|
									for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
									FREE(gInfo->queuePages);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								    gInfo->queuePageIndex = 0;
							 | 
						|
								
							 | 
						|
								    /* Enter the root node into the queue to start with. */
							 | 
						|
								    parentPage = gInfo->queuePage;
							 | 
						|
								    parentQueueIndex = gInfo->queuePageIndex;
							 | 
						|
								    topLen = 0;
							 | 
						|
								    *(gInfo->currentQueuePage + gInfo->queuePageIndex) = node;
							 | 
						|
								    gInfo->queuePageIndex++;
							 | 
						|
								    childPage = gInfo->currentQueuePage;
							 | 
						|
								    childQueueIndex = gInfo->queuePageIndex;
							 | 
						|
								
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								
							 | 
						|
								    if (gInfo->nodeDistPageIndex == gInfo->nodeDistPageSize) ResizeNodeDistPages(dd, gInfo);
							 | 
						|
								    if (dd->errorCode == CUDD_MEMORY_OUT) {
							 | 
						|
									for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
							 | 
						|
									FREE(gInfo->nodeDistPages);
							 | 
						|
									for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
									FREE(gInfo->queuePages);
							 | 
						|
									st_free_table(pathTable);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    nodeStat = gInfo->currentNodeDistPage + gInfo->nodeDistPageIndex;
							 | 
						|
								    gInfo->nodeDistPageIndex++;
							 | 
						|
								
							 | 
						|
								    nodeStat->oddTopDist = MAXSHORTINT;
							 | 
						|
								    nodeStat->evenTopDist = MAXSHORTINT;
							 | 
						|
								    nodeStat->evenBotDist = MAXSHORTINT;
							 | 
						|
								    nodeStat->oddBotDist = MAXSHORTINT;
							 | 
						|
								    nodeStat->regResult = NULL;
							 | 
						|
								    nodeStat->compResult = NULL;
							 | 
						|
								
							 | 
						|
								    insertValue = st_insert(pathTable, N, nodeStat);
							 | 
						|
								    if (insertValue == ST_OUT_OF_MEM) {
							 | 
						|
									dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									for (i = 0; i <= gInfo->nodeDistPage; i++) FREE(gInfo->nodeDistPages[i]);
							 | 
						|
									FREE(gInfo->nodeDistPages);
							 | 
						|
									for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
									FREE(gInfo->queuePages);
							 | 
						|
									st_free_table(pathTable);
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    } else if (insertValue == 1) {
							 | 
						|
									fprintf(fp, "Something wrong, the entry exists but didnt show up in st_lookup\n");
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (Cudd_IsComplement(node)) {
							 | 
						|
									nodeStat->oddTopDist = 0;
							 | 
						|
								    } else {
							 | 
						|
									nodeStat->evenTopDist = 0;
							 | 
						|
								    }
							 | 
						|
								    numParents = 1;
							 | 
						|
								    /* call the function that counts the distance of each node from the
							 | 
						|
								     * root
							 | 
						|
								     */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    gInfo->numCalls = 0;
							 | 
						|
								#endif
							 | 
						|
								    CreateTopDist(dd, gInfo, pathTable, parentPage, parentQueueIndex, (int) topLen,
							 | 
						|
										  childPage, childQueueIndex, numParents, fp);
							 | 
						|
								    if (dd->errorCode == CUDD_MEMORY_OUT) {
							 | 
						|
									fprintf(fp, "Out of Memory and cant count path lengths\n");
							 | 
						|
									goto OUT_OF_MEM;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    gInfo->numCalls = 0;
							 | 
						|
								#endif
							 | 
						|
								    /* call the function that counts the distance of each node from the
							 | 
						|
								     * constant
							 | 
						|
								     */
							 | 
						|
								    if (!CreateBotDist(node, pathTable, pathLengthArray, fp)) return(NULL);
							 | 
						|
								
							 | 
						|
								    /* free BFS queue pages as no longer required */
							 | 
						|
								    for (i = 0; i <= gInfo->queuePage; i++) FREE(gInfo->queuePages[i]);
							 | 
						|
								    FREE(gInfo->queuePages);
							 | 
						|
								    return(pathTable);
							 | 
						|
								
							 | 
						|
								OUT_OF_MEM:
							 | 
						|
								    (void) fprintf(fp, "Out of Memory, cannot allocate pages\n");
							 | 
						|
								    dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
								    return(NULL);
							 | 
						|
								
							 | 
						|
								} /*end of CreatePathTable */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Chooses the maximum allowable path length of nodes under the
							 | 
						|
								  threshold.]
							 | 
						|
								
							 | 
						|
								  Description [Chooses the maximum allowable path length under each node.
							 | 
						|
								  The corner cases are when the threshold is larger than the number
							 | 
						|
								  of nodes in the BDD iself, in which case 'numVars + 1' is returned.
							 | 
						|
								  If all nodes of a particular path length are needed, then the
							 | 
						|
								  maxpath returned is the next one with excess nodes = 0;]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static unsigned int
							 | 
						|
								AssessPathLength(
							 | 
						|
								  unsigned int * pathLengthArray /* array determining number of nodes belonging to the different path lengths */,
							 | 
						|
								  int  threshold /* threshold to determine maximum allowable nodes in the subset */,
							 | 
						|
								  int  numVars /* maximum number of variables */,
							 | 
						|
								  unsigned int * excess /* number of nodes labeled maxpath required in the subset */,
							 | 
						|
								  FILE *fp /* where to write messages */)
							 | 
						|
								{
							 | 
						|
								    unsigned int i, maxpath;
							 | 
						|
								    int temp;
							 | 
						|
								
							 | 
						|
								    temp = threshold;
							 | 
						|
								    i = 0;
							 | 
						|
								    maxpath = 0;
							 | 
						|
								    /* quit loop if i reaches max number of variables or if temp reaches
							 | 
						|
								     * below zero
							 | 
						|
								     */
							 | 
						|
								    while ((i < (unsigned) numVars+1) && (temp > 0)) {
							 | 
						|
									if (pathLengthArray[i] > 0) {
							 | 
						|
									    maxpath = i;
							 | 
						|
									    temp = temp - pathLengthArray[i];
							 | 
						|
									}
							 | 
						|
									i++;
							 | 
						|
								    }
							 | 
						|
								    /* if all nodes of max path are needed */
							 | 
						|
								    if (temp >= 0) {
							 | 
						|
									maxpath++; /* now maxpath  becomes the next maxppath or max number
							 | 
						|
										      of variables */
							 | 
						|
									*excess = 0;
							 | 
						|
								    } else { /* normal case when subset required is less than size of
							 | 
						|
										original BDD */
							 | 
						|
									*excess = temp + pathLengthArray[maxpath];
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (maxpath == 0) {
							 | 
						|
									fprintf(fp, "Path Length array seems to be all zeroes, check\n");
							 | 
						|
								    }
							 | 
						|
								    return(maxpath);
							 | 
						|
								
							 | 
						|
								} /* end of AssessPathLength */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Builds the BDD with nodes labeled with path length less than or equal to maxpath]
							 | 
						|
								
							 | 
						|
								  Description [Builds the BDD with nodes labeled with path length
							 | 
						|
								  under maxpath and as many nodes labeled maxpath as determined by the
							 | 
						|
								  threshold. The procedure uses the path table to determine which nodes
							 | 
						|
								  in the original bdd need to be retained. This procedure picks a
							 | 
						|
								  shortest path (tie break decided by taking the child with the shortest
							 | 
						|
								  distance to the constant) and recurs down the path till it reaches the
							 | 
						|
								  constant. the procedure then starts building the subset upward from
							 | 
						|
								  the constant. All nodes labeled by path lengths less than the given
							 | 
						|
								  maxpath are used to build the subset.  However, in the case of nodes
							 | 
						|
								  that have label equal to maxpath, as many are chosen as required by
							 | 
						|
								  the threshold. This number is stored in the info structure in the
							 | 
						|
								  field thresholdReached. This field is decremented whenever a node
							 | 
						|
								  labeled maxpath is encountered and the nodes labeled maxpath are
							 | 
						|
								  aggregated in a maxpath table. As soon as the thresholdReached count
							 | 
						|
								  goes to 0, the shortest path from this node to the constant is found.
							 | 
						|
								  The extraction of nodes with the above labeling is based on the fact
							 | 
						|
								  that each node, labeled with a path length, P, has at least one child
							 | 
						|
								  labeled P or less. So extracting all nodes labeled a given path length
							 | 
						|
								  P ensures complete paths between the root and the constant. Extraction
							 | 
						|
								  of a partial number of nodes with a given path length may result in
							 | 
						|
								  incomplete paths and hence the additional number of nodes are grabbed
							 | 
						|
								  to complete the path. Since the Bdd is built bottom-up, other nodes
							 | 
						|
								  labeled maxpath do lie on complete paths.  The procedure may cause the
							 | 
						|
								  subset to have a larger or smaller number of nodes than the specified
							 | 
						|
								  threshold. The increase in the number of nodes is caused by the
							 | 
						|
								  building of a subset and the reduction by recombination. However in
							 | 
						|
								  most cases, the recombination overshadows the increase and the
							 | 
						|
								  procedure returns a result with lower number of nodes than specified.
							 | 
						|
								  The subsetNodeTable is NIL when there is no hard limit on the number
							 | 
						|
								  of nodes. Further efforts towards keeping the subset closer to the
							 | 
						|
								  threshold number were abandoned in favour of keeping the procedure
							 | 
						|
								  simple and fast.]
							 | 
						|
								
							 | 
						|
								  SideEffects [SubsetNodeTable is changed if it is not NIL.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static DdNode *
							 | 
						|
								BuildSubsetBdd(
							 | 
						|
								  DdManager * dd /* DD manager */,
							 | 
						|
								  GlobalInfo_t *gInfo /* global information */,
							 | 
						|
								  st_table * pathTable /* path table with path lengths and computed results */,
							 | 
						|
								  DdNode * node /* current node */,
							 | 
						|
								  struct AssortedInfo * info /* assorted information structure */,
							 | 
						|
								  st_table * subsetNodeTable /* table storing computed results */)
							 | 
						|
								{
							 | 
						|
								    DdNode *N, *Nv, *Nnv;
							 | 
						|
								    DdNode *ThenBranch, *ElseBranch, *childBranch;
							 | 
						|
								    DdNode *child, *regChild, *regNnv, *regNv;
							 | 
						|
								    NodeDist_t *nodeStatNv, *nodeStat, *nodeStatNnv;
							 | 
						|
								    DdNode *neW, *topv, *regNew;
							 | 
						|
								    char *entry;
							 | 
						|
								    unsigned int topid;
							 | 
						|
								    unsigned int childPathLength, oddLen, evenLen, NnvPathLength, NvPathLength;
							 | 
						|
								    unsigned int NvBotDist, NnvBotDist;
							 | 
						|
								    int tiebreakChild;
							 | 
						|
								    int  processingDone, thenDone, elseDone;
							 | 
						|
								
							 | 
						|
								    DdNode *zero = Cudd_Not(DD_ONE(dd));
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    gInfo->numCalls++;
							 | 
						|
								#endif
							 | 
						|
								    if (Cudd_IsConstant(node))
							 | 
						|
									return(node);
							 | 
						|
								
							 | 
						|
								    N = Cudd_Regular(node);
							 | 
						|
								    /* Find node in table. */
							 | 
						|
								    if (!st_lookup(pathTable, N, &nodeStat)) {
							 | 
						|
									(void) fprintf(dd->err, "Something wrong, node must be in table \n");
							 | 
						|
									dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    /* If the node in the table has been visited, then return the corresponding
							 | 
						|
								    ** Dd. Since a node can become a subset of itself, its
							 | 
						|
								    ** complement (that is te same node reached by a different parity) will
							 | 
						|
								    ** become a superset of the original node and result in some minterms
							 | 
						|
								    ** that were not in the original set. Hence two different results are
							 | 
						|
								    ** maintained, corresponding to the odd and even parities.
							 | 
						|
								    */
							 | 
						|
								
							 | 
						|
								    /* If this node is reached with an odd parity, get odd parity results. */
							 | 
						|
								    if (Cudd_IsComplement(node)) {
							 | 
						|
									if  (nodeStat->compResult != NULL) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    gInfo->hits++;
							 | 
						|
								#endif
							 | 
						|
									    return(nodeStat->compResult);
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									/* if this node is reached with an even parity, get even parity
							 | 
						|
									 * results
							 | 
						|
									 */
							 | 
						|
									if (nodeStat->regResult != NULL) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    gInfo->hits++;
							 | 
						|
								#endif
							 | 
						|
									    return(nodeStat->regResult);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /* get children */
							 | 
						|
								    Nv = Cudd_T(N);
							 | 
						|
								    Nnv = Cudd_E(N);
							 | 
						|
								
							 | 
						|
								    Nv = Cudd_NotCond(Nv, Cudd_IsComplement(node));
							 | 
						|
								    Nnv = Cudd_NotCond(Nnv, Cudd_IsComplement(node));
							 | 
						|
								
							 | 
						|
								    /* no child processed */
							 | 
						|
								    processingDone = 0;
							 | 
						|
								    /* then child not processed */
							 | 
						|
								    thenDone = 0;
							 | 
						|
								    ThenBranch = NULL;
							 | 
						|
								    /* else child not processed */
							 | 
						|
								    elseDone = 0;
							 | 
						|
								    ElseBranch = NULL;
							 | 
						|
								    /* if then child constant, branch is the child */
							 | 
						|
								    if (Cudd_IsConstant(Nv)) {
							 | 
						|
									/*shortest path found */
							 | 
						|
									if ((Nv == DD_ONE(dd)) && (info->findShortestPath)) {
							 | 
						|
									    info->findShortestPath = 0;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									ThenBranch = Nv;
							 | 
						|
									cuddRef(ThenBranch);
							 | 
						|
									if (ThenBranch == NULL) {
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									thenDone++;
							 | 
						|
									processingDone++;
							 | 
						|
									NvBotDist = MAXSHORTINT;
							 | 
						|
								    } else {
							 | 
						|
									/* Derive regular child for table lookup. */
							 | 
						|
									regNv = Cudd_Regular(Nv);
							 | 
						|
									/* Get node data for shortest path length. */
							 | 
						|
									if (!st_lookup(pathTable, regNv, &nodeStatNv) ) {
							 | 
						|
									    (void) fprintf(dd->err, "Something wrong, node must be in table\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									/* Derive shortest path length for child. */
							 | 
						|
									if ((nodeStatNv->oddTopDist != MAXSHORTINT) &&
							 | 
						|
									    (nodeStatNv->oddBotDist != MAXSHORTINT)) {
							 | 
						|
									    oddLen = (nodeStatNv->oddTopDist + nodeStatNv->oddBotDist);
							 | 
						|
									} else {
							 | 
						|
									    oddLen = MAXSHORTINT;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if ((nodeStatNv->evenTopDist != MAXSHORTINT) &&
							 | 
						|
									    (nodeStatNv->evenBotDist != MAXSHORTINT)) {
							 | 
						|
									    evenLen = (nodeStatNv->evenTopDist +nodeStatNv->evenBotDist);
							 | 
						|
									} else {
							 | 
						|
									    evenLen = MAXSHORTINT;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									NvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
							 | 
						|
									NvBotDist = (oddLen <= evenLen) ? nodeStatNv->oddBotDist:
							 | 
						|
														   nodeStatNv->evenBotDist;
							 | 
						|
								    }
							 | 
						|
								    /* if else child constant, branch is the child */
							 | 
						|
								    if (Cudd_IsConstant(Nnv)) {
							 | 
						|
									/*shortest path found */
							 | 
						|
									if ((Nnv == DD_ONE(dd)) && (info->findShortestPath)) {
							 | 
						|
									    info->findShortestPath = 0;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									ElseBranch = Nnv;
							 | 
						|
									cuddRef(ElseBranch);
							 | 
						|
									if (ElseBranch == NULL) {
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									elseDone++;
							 | 
						|
									processingDone++;
							 | 
						|
									NnvBotDist = MAXSHORTINT;
							 | 
						|
								    } else {
							 | 
						|
									/* Derive regular child for table lookup. */
							 | 
						|
									regNnv = Cudd_Regular(Nnv);
							 | 
						|
									/* Get node data for shortest path length. */
							 | 
						|
									if (!st_lookup(pathTable, regNnv, &nodeStatNnv) ) {
							 | 
						|
									    (void) fprintf(dd->err, "Something wrong, node must be in table\n");
							 | 
						|
									    dd->errorCode = CUDD_INTERNAL_ERROR;
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									/* Derive shortest path length for child. */
							 | 
						|
									if ((nodeStatNnv->oddTopDist != MAXSHORTINT) &&
							 | 
						|
									    (nodeStatNnv->oddBotDist != MAXSHORTINT)) {
							 | 
						|
									    oddLen = (nodeStatNnv->oddTopDist + nodeStatNnv->oddBotDist);
							 | 
						|
									} else {
							 | 
						|
									    oddLen = MAXSHORTINT;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if ((nodeStatNnv->evenTopDist != MAXSHORTINT) &&
							 | 
						|
									    (nodeStatNnv->evenBotDist != MAXSHORTINT)) {
							 | 
						|
									    evenLen = (nodeStatNnv->evenTopDist +nodeStatNnv->evenBotDist);
							 | 
						|
									} else {
							 | 
						|
									    evenLen = MAXSHORTINT;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									NnvPathLength = (oddLen <= evenLen) ? oddLen : evenLen;
							 | 
						|
									NnvBotDist = (oddLen <= evenLen) ? nodeStatNnv->oddBotDist :
							 | 
						|
														   nodeStatNnv->evenBotDist;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    tiebreakChild = (NvBotDist <= NnvBotDist) ? 1 : 0;
							 | 
						|
								    /* while both children not processed */
							 | 
						|
								    while (processingDone != 2) {
							 | 
						|
									if (!processingDone) {
							 | 
						|
									    /* if no child processed */
							 | 
						|
									    /* pick the child with shortest path length and record which one
							 | 
						|
									     * picked
							 | 
						|
									     */
							 | 
						|
									    if ((NvPathLength < NnvPathLength) ||
							 | 
						|
										((NvPathLength == NnvPathLength) && (tiebreakChild == 1))) {
							 | 
						|
										child = Nv;
							 | 
						|
										regChild = regNv;
							 | 
						|
										thenDone = 1;
							 | 
						|
										childPathLength = NvPathLength;
							 | 
						|
									    } else {
							 | 
						|
										child = Nnv;
							 | 
						|
										regChild = regNnv;
							 | 
						|
										elseDone = 1;
							 | 
						|
										childPathLength = NnvPathLength;
							 | 
						|
									    } /* then path length less than else path length */
							 | 
						|
									} else {
							 | 
						|
									    /* if one child processed, process the other */
							 | 
						|
									    if (thenDone) {
							 | 
						|
										child = Nnv;
							 | 
						|
										regChild = regNnv;
							 | 
						|
										elseDone = 1;
							 | 
						|
										childPathLength = NnvPathLength;
							 | 
						|
									    } else {
							 | 
						|
										child = Nv;
							 | 
						|
										regChild = regNv;
							 | 
						|
										thenDone = 1;
							 | 
						|
										childPathLength = NvPathLength;
							 | 
						|
									    } /* end of else pick the Then child if ELSE child processed */
							 | 
						|
									} /* end of else one child has been processed */
							 | 
						|
								
							 | 
						|
									/* ignore (replace with constant 0) all nodes which lie on paths larger
							 | 
						|
									 * than the maximum length of the path required
							 | 
						|
									 */
							 | 
						|
									if (childPathLength > info->maxpath) {
							 | 
						|
									    /* record nodes visited */
							 | 
						|
									    childBranch = zero;
							 | 
						|
									} else {
							 | 
						|
									    if (childPathLength < info->maxpath) {
							 | 
						|
										if (info->findShortestPath) {
							 | 
						|
										    info->findShortestPath = 0;
							 | 
						|
										}
							 | 
						|
										childBranch = BuildSubsetBdd(dd, gInfo, pathTable, child, info,
							 | 
						|
													     subsetNodeTable);
							 | 
						|
								
							 | 
						|
									    } else { /* Case: path length of node = maxpath */
							 | 
						|
										/* If the node labeled with maxpath is found in the
							 | 
						|
										** maxpathTable, use it to build the subset BDD.  */
							 | 
						|
										if (st_lookup(info->maxpathTable, regChild, &entry)) {
							 | 
						|
										    /* When a node that is already been chosen is hit,
							 | 
						|
										    ** the quest for a complete path is over.  */
							 | 
						|
										    if (info->findShortestPath) {
							 | 
						|
											info->findShortestPath = 0;
							 | 
						|
										    }
							 | 
						|
										    childBranch = BuildSubsetBdd(dd, gInfo, pathTable, child, info,
							 | 
						|
														 subsetNodeTable);
							 | 
						|
										} else {
							 | 
						|
										    /* If node is not found in the maxpathTable and
							 | 
						|
										    ** the threshold has been reached, then if the
							 | 
						|
										    ** path needs to be completed, continue. Else
							 | 
						|
										    ** replace the node with a zero.  */
							 | 
						|
										    if (info->thresholdReached <= 0) {
							 | 
						|
											if (info->findShortestPath) {
							 | 
						|
											    if (st_insert(info->maxpathTable, regChild,
							 | 
						|
													  NULL) == ST_OUT_OF_MEM) {
							 | 
						|
												dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
												(void) fprintf(dd->err, "OUT of memory\n");
							 | 
						|
												info->thresholdReached = 0;
							 | 
						|
												childBranch = zero;
							 | 
						|
											    } else {
							 | 
						|
												info->thresholdReached--;
							 | 
						|
												childBranch = BuildSubsetBdd(dd, gInfo, pathTable,
							 | 
						|
														    child, info,subsetNodeTable);
							 | 
						|
											    }
							 | 
						|
											} else { /* not find shortest path, we dont need this
							 | 
						|
												    node */
							 | 
						|
											    childBranch = zero;
							 | 
						|
											}
							 | 
						|
										    } else { /* Threshold hasn't been reached,
							 | 
						|
											     ** need the node. */
							 | 
						|
											if (st_insert(info->maxpathTable, regChild,
							 | 
						|
												      NULL) == ST_OUT_OF_MEM) {
							 | 
						|
											    dd->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
											    (void) fprintf(dd->err, "OUT of memory\n");
							 | 
						|
											    info->thresholdReached = 0;
							 | 
						|
											    childBranch = zero;
							 | 
						|
											} else {
							 | 
						|
											    info->thresholdReached--;
							 | 
						|
											    if (info->thresholdReached <= 0) {
							 | 
						|
												info->findShortestPath = 1;
							 | 
						|
											    }
							 | 
						|
											    childBranch = BuildSubsetBdd(dd, gInfo, pathTable,
							 | 
						|
														 child, info, subsetNodeTable);
							 | 
						|
								
							 | 
						|
											} /* end of st_insert successful */
							 | 
						|
										    } /* end of threshold hasnt been reached yet */
							 | 
						|
										} /* end of else node not found in maxpath table */
							 | 
						|
									    } /* end of if (path length of node = maxpath) */
							 | 
						|
									} /* end if !(childPathLength > maxpath) */
							 | 
						|
									if (childBranch == NULL) {
							 | 
						|
									    /* deref other stuff incase reordering has taken place */
							 | 
						|
									    if (ThenBranch != NULL) {
							 | 
						|
										Cudd_RecursiveDeref(dd, ThenBranch);
							 | 
						|
										ThenBranch = NULL;
							 | 
						|
									    }
							 | 
						|
									    if (ElseBranch != NULL) {
							 | 
						|
										Cudd_RecursiveDeref(dd, ElseBranch);
							 | 
						|
										ElseBranch = NULL;
							 | 
						|
									    }
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									cuddRef(childBranch);
							 | 
						|
								
							 | 
						|
									if (child == Nv) {
							 | 
						|
									    ThenBranch = childBranch;
							 | 
						|
									} else {
							 | 
						|
									    ElseBranch = childBranch;
							 | 
						|
									}
							 | 
						|
									processingDone++;
							 | 
						|
								
							 | 
						|
								    } /*end of while processing Nv, Nnv */
							 | 
						|
								
							 | 
						|
								    info->findShortestPath = 0;
							 | 
						|
								    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);
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /* Hard Limit of threshold has been imposed */
							 | 
						|
								    if (subsetNodeTable != NIL(st_table)) {
							 | 
						|
									/* check if a new node is created */
							 | 
						|
									regNew = Cudd_Regular(neW);
							 | 
						|
									/* subset node table keeps all new nodes that have been created to keep
							 | 
						|
									 * a running count of how many nodes have been built in the subset.
							 | 
						|
									 */
							 | 
						|
									if (!st_lookup(subsetNodeTable, regNew, &entry)) {
							 | 
						|
									    if (!Cudd_IsConstant(regNew)) {
							 | 
						|
										if (st_insert(subsetNodeTable, regNew,
							 | 
						|
											      NULL) == ST_OUT_OF_MEM) {
							 | 
						|
										    (void) fprintf(dd->err, "Out of memory\n");
							 | 
						|
										    return (NULL);
							 | 
						|
										}
							 | 
						|
										if (st_count(subsetNodeTable) > info->threshold) {
							 | 
						|
										    info->thresholdReached = 0;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    if (neW == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    } else {
							 | 
						|
									/*store computed result in regular form*/
							 | 
						|
									if (Cudd_IsComplement(node)) {
							 | 
						|
									    nodeStat->compResult = neW;
							 | 
						|
									    cuddRef(nodeStat->compResult);
							 | 
						|
									    /* if the new node is the same as the corresponding node in the
							 | 
						|
									     * original bdd then its complement need not be computed as it
							 | 
						|
									     * cannot be larger than the node itself
							 | 
						|
									     */
							 | 
						|
									    if (neW == node) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										gInfo->thishit++;
							 | 
						|
								#endif
							 | 
						|
										/* if a result for the node has already been computed, then
							 | 
						|
										 * it can only be smaller than teh node itself. hence store
							 | 
						|
										 * the node result in order not to break recombination
							 | 
						|
										 */
							 | 
						|
										if (nodeStat->regResult != NULL) {
							 | 
						|
										    Cudd_RecursiveDeref(dd, nodeStat->regResult);
							 | 
						|
										}
							 | 
						|
										nodeStat->regResult = Cudd_Not(neW);
							 | 
						|
										cuddRef(nodeStat->regResult);
							 | 
						|
									    }
							 | 
						|
								
							 | 
						|
									} else {
							 | 
						|
									    nodeStat->regResult = neW;
							 | 
						|
									    cuddRef(nodeStat->regResult);
							 | 
						|
									    if (neW == node) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
										gInfo->thishit++;
							 | 
						|
								#endif
							 | 
						|
										if (nodeStat->compResult != NULL) {
							 | 
						|
										    Cudd_RecursiveDeref(dd, nodeStat->compResult);
							 | 
						|
										}
							 | 
						|
										nodeStat->compResult = Cudd_Not(neW);
							 | 
						|
										cuddRef(nodeStat->compResult);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									cuddDeref(neW);
							 | 
						|
									return(neW);
							 | 
						|
								    } /* end of else i.e. Subset != NULL */
							 | 
						|
								} /* end of BuildSubsetBdd */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis     [Procedure to free te result dds stored in the NodeDist pages.]
							 | 
						|
								
							 | 
						|
								  Description [None]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static enum st_retval
							 | 
						|
								stPathTableDdFree(
							 | 
						|
								  char * key,
							 | 
						|
								  char * value,
							 | 
						|
								  char * arg)
							 | 
						|
								{
							 | 
						|
								    NodeDist_t *nodeStat;
							 | 
						|
								    DdManager *dd;
							 | 
						|
								
							 | 
						|
								    nodeStat = (NodeDist_t *)value;
							 | 
						|
								    dd = (DdManager *)arg;
							 | 
						|
								    if (nodeStat->regResult != NULL) {
							 | 
						|
									Cudd_RecursiveDeref(dd, nodeStat->regResult);
							 | 
						|
								    }
							 | 
						|
								    if (nodeStat->compResult != NULL) {
							 | 
						|
									Cudd_RecursiveDeref(dd, nodeStat->compResult);
							 | 
						|
								    }
							 | 
						|
								    return(ST_CONTINUE);
							 | 
						|
								
							 | 
						|
								} /* end of stPathTableFree */
							 |