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.
		
		
		
		
		
			
		
			
				
					
					
						
							3213 lines
						
					
					
						
							94 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							3213 lines
						
					
					
						
							94 KiB
						
					
					
				
								/**CFile***********************************************************************
							 | 
						|
								
							 | 
						|
								  FileName    [cuddTable.c]
							 | 
						|
								
							 | 
						|
								  PackageName [cudd]
							 | 
						|
								
							 | 
						|
								  Synopsis    [Unique table management functions.]
							 | 
						|
								
							 | 
						|
								  Description [External procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> Cudd_Prime()
							 | 
						|
								                <li> Cudd_Reserve()
							 | 
						|
										</ul>
							 | 
						|
									Internal procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> cuddAllocNode()
							 | 
						|
										<li> cuddInitTable()
							 | 
						|
										<li> cuddFreeTable()
							 | 
						|
										<li> cuddGarbageCollect()
							 | 
						|
										<li> cuddZddGetNode()
							 | 
						|
										<li> cuddZddGetNodeIVO()
							 | 
						|
										<li> cuddUniqueInter()
							 | 
						|
										<li> cuddUniqueInterIVO()
							 | 
						|
										<li> cuddUniqueInterZdd()
							 | 
						|
										<li> cuddUniqueConst()
							 | 
						|
										<li> cuddRehash()
							 | 
						|
										<li> cuddShrinkSubtable()
							 | 
						|
										<li> cuddInsertSubtables()
							 | 
						|
										<li> cuddDestroySubtables()
							 | 
						|
										<li> cuddResizeTableZdd()
							 | 
						|
										<li> cuddSlowTableGrowth()
							 | 
						|
										</ul>
							 | 
						|
									Static procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> ddRehashZdd()
							 | 
						|
										<li> ddResizeTable()
							 | 
						|
										<li> cuddFindParent()
							 | 
						|
										<li> cuddOrderedInsert()
							 | 
						|
										<li> cuddOrderedThread()
							 | 
						|
										<li> cuddRotateLeft()
							 | 
						|
										<li> cuddRotateRight()
							 | 
						|
										<li> cuddDoRebalance()
							 | 
						|
										<li> cuddCheckCollisionOrdering()
							 | 
						|
										</ul>]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								  Author      [Fabio Somenzi]
							 | 
						|
								
							 | 
						|
								  Copyright   [Copyright (c) 1995-2012, Regents of the University of Colorado
							 | 
						|
								
							 | 
						|
								  All rights reserved.
							 | 
						|
								
							 | 
						|
								  Redistribution and use in source and binary forms, with or without
							 | 
						|
								  modification, are permitted provided that the following conditions
							 | 
						|
								  are met:
							 | 
						|
								
							 | 
						|
								  Redistributions of source code must retain the above copyright
							 | 
						|
								  notice, this list of conditions and the following disclaimer.
							 | 
						|
								
							 | 
						|
								  Redistributions in binary form must reproduce the above copyright
							 | 
						|
								  notice, this list of conditions and the following disclaimer in the
							 | 
						|
								  documentation and/or other materials provided with the distribution.
							 | 
						|
								
							 | 
						|
								  Neither the name of the University of Colorado nor the names of its
							 | 
						|
								  contributors may be used to endorse or promote products derived from
							 | 
						|
								  this software without specific prior written permission.
							 | 
						|
								
							 | 
						|
								  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
							 | 
						|
								  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
							 | 
						|
								  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
							 | 
						|
								  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
							 | 
						|
								  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
							 | 
						|
								  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
							 | 
						|
								  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
							 | 
						|
								  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
							 | 
						|
								  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
							 | 
						|
								  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
							 | 
						|
								  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
							 | 
						|
								  POSSIBILITY OF SUCH DAMAGE.]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								/* Constants for red/black trees. */
							 | 
						|
								#define DD_STACK_SIZE 128
							 | 
						|
								#define DD_RED   0
							 | 
						|
								#define DD_BLACK 1
							 | 
						|
								#define DD_PAGE_SIZE 8192
							 | 
						|
								#define DD_PAGE_MASK ~(DD_PAGE_SIZE - 1)
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/* This is a hack for when CUDD_VALUE_TYPE is double */
							 | 
						|
								typedef union hack {
							 | 
						|
								    CUDD_VALUE_TYPE value;
							 | 
						|
								    unsigned int bits[2];
							 | 
						|
								} hack;
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef lint
							 | 
						|
								static char rcsid[] DD_UNUSED = "$Id: cuddTable.c,v 1.126 2012/02/05 01:07:19 fabio Exp $";
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								/* Macros for red/black trees. */
							 | 
						|
								#define DD_INSERT_COMPARE(x,y) \
							 | 
						|
									(((ptruint) (x) & DD_PAGE_MASK) - ((ptruint) (y) & DD_PAGE_MASK))
							 | 
						|
								#define DD_COLOR(p)  ((p)->index)
							 | 
						|
								#define DD_IS_BLACK(p) ((p)->index == DD_BLACK)
							 | 
						|
								#define DD_IS_RED(p) ((p)->index == DD_RED)
							 | 
						|
								#define DD_LEFT(p) cuddT(p)
							 | 
						|
								#define DD_RIGHT(p) cuddE(p)
							 | 
						|
								#define DD_NEXT(p) ((p)->next)
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**AutomaticStart*************************************************************/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static void ddRehashZdd (DdManager *unique, int i);
							 | 
						|
								static int ddResizeTable (DdManager *unique, int index, int amount);
							 | 
						|
								static int cuddFindParent (DdManager *table, DdNode *node);
							 | 
						|
								DD_INLINE static void ddFixLimits (DdManager *unique);
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								static void cuddOrderedInsert (DdNodePtr *root, DdNodePtr node);
							 | 
						|
								static DdNode * cuddOrderedThread (DdNode *root, DdNode *list);
							 | 
						|
								static void cuddRotateLeft (DdNodePtr *nodeP);
							 | 
						|
								static void cuddRotateRight (DdNodePtr *nodeP);
							 | 
						|
								static void cuddDoRebalance (DdNodePtr **stack, int stackN);
							 | 
						|
								#endif
							 | 
						|
								static void ddPatchTree (DdManager *dd, MtrNode *treenode);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								static int cuddCheckCollisionOrdering (DdManager *unique, int i, int j);
							 | 
						|
								#endif
							 | 
						|
								static void ddReportRefMess (DdManager *unique, int i, const char *caller);
							 | 
						|
								
							 | 
						|
								/**AutomaticEnd***************************************************************/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Returns the next prime >= p.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								unsigned int
							 | 
						|
								Cudd_Prime(
							 | 
						|
								  unsigned int  p)
							 | 
						|
								{
							 | 
						|
								    int i,pn;
							 | 
						|
								
							 | 
						|
								    p--;
							 | 
						|
								    do {
							 | 
						|
									p++;
							 | 
						|
									if (p&1) {
							 | 
						|
									    pn = 1;
							 | 
						|
									    i = 3;
							 | 
						|
									    while ((unsigned) (i * i) <= p) {
							 | 
						|
										if (p % i == 0) {
							 | 
						|
										    pn = 0;
							 | 
						|
										    break;
							 | 
						|
										}
							 | 
						|
										i += 2;
							 | 
						|
									    }
							 | 
						|
									} else {
							 | 
						|
									    pn = 0;
							 | 
						|
									}
							 | 
						|
								    } while (!pn);
							 | 
						|
								    return(p);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_Prime */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Expand manager without creating variables.]
							 | 
						|
								
							 | 
						|
								  Description [Expand a manager by a specified number of subtables without
							 | 
						|
								  actually creating new variables.  This function can be used to reduce the
							 | 
						|
								  frequency of resizing when an estimate of the number of variables is
							 | 
						|
								  available.  One would call this function instead of passing the number
							 | 
						|
								  of variables to Cudd_Init if variables should not be created right away
							 | 
						|
								  of if the estimate on their number became available only after the manager
							 | 
						|
								  has been created.  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_Init]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								Cudd_Reserve(
							 | 
						|
								  DdManager *manager,
							 | 
						|
								  int amount)
							 | 
						|
								{
							 | 
						|
								    int currentSize = manager->size;
							 | 
						|
								    if (amount < 0)
							 | 
						|
								        return(0);
							 | 
						|
								    if (currentSize + amount < currentSize) /* overflow */
							 | 
						|
								        return(0);
							 | 
						|
								    if (amount <= manager->maxSize - manager->size)
							 | 
						|
								        return(1);
							 | 
						|
								    return ddResizeTable(manager, -1, amount);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_Reserve */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Fast storage allocation for DdNodes in the table.]
							 | 
						|
								
							 | 
						|
								  Description [Fast storage allocation for DdNodes in the table. The
							 | 
						|
								  first 4 bytes of a chunk contain a pointer to the next block; the
							 | 
						|
								  rest contains DD_MEM_CHUNK spaces for DdNodes.  Returns a pointer to
							 | 
						|
								  a new node if successful; NULL is memory is full.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddDynamicAllocNode]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddAllocNode(
							 | 
						|
								  DdManager * unique)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    DdNodePtr *mem;
							 | 
						|
								    DdNode *list, *node;
							 | 
						|
								    extern DD_OOMFP MMoutOfMemory;
							 | 
						|
								    DD_OOMFP saveHandler;
							 | 
						|
								
							 | 
						|
								    if (unique->nextFree == NULL) {	/* free list is empty */
							 | 
						|
									/* Check for exceeded limits. */
							 | 
						|
									if ((unique->keys - unique->dead) + (unique->keysZ - unique->deadZ) >
							 | 
						|
									    unique->maxLive) {
							 | 
						|
									    unique->errorCode = CUDD_TOO_MANY_NODES;
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
								        if (util_cpu_time() - unique->startTime > unique->timeLimit) {
							 | 
						|
								            unique->errorCode = CUDD_TIMEOUT_EXPIRED;
							 | 
						|
								            return(NULL);
							 | 
						|
								        }
							 | 
						|
									if (unique->stash == NULL || unique->memused > unique->maxmemhard) {
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									    mem = NULL;
							 | 
						|
									}
							 | 
						|
									if (unique->nextFree == NULL) {
							 | 
						|
									    if (unique->memused > unique->maxmemhard) {
							 | 
						|
										unique->errorCode = CUDD_MAX_MEM_EXCEEDED;
							 | 
						|
										return(NULL);
							 | 
						|
									    }
							 | 
						|
									    /* Try to allocate a new block. */
							 | 
						|
									    saveHandler = MMoutOfMemory;
							 | 
						|
									    MMoutOfMemory = Cudd_OutOfMem;
							 | 
						|
									    mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
							 | 
						|
									    MMoutOfMemory = saveHandler;
							 | 
						|
									    if (mem == NULL) {
							 | 
						|
										/* No more memory: Try collecting garbage. If this succeeds,
							 | 
						|
										** we end up with mem still NULL, but unique->nextFree !=
							 | 
						|
										** NULL. */
							 | 
						|
										if (cuddGarbageCollect(unique,1) == 0) {
							 | 
						|
										    /* Last resort: Free the memory stashed away, if there
							 | 
						|
										    ** any. If this succeeeds, mem != NULL and
							 | 
						|
										    ** unique->nextFree still NULL. */
							 | 
						|
										    if (unique->stash != NULL) {
							 | 
						|
											FREE(unique->stash);
							 | 
						|
											unique->stash = NULL;
							 | 
						|
											/* Inhibit resizing of tables. */
							 | 
						|
											cuddSlowTableGrowth(unique);
							 | 
						|
											/* Now try again. */
							 | 
						|
											mem = (DdNodePtr *) ALLOC(DdNode,DD_MEM_CHUNK + 1);
							 | 
						|
										    }
							 | 
						|
										    if (mem == NULL) {
							 | 
						|
											/* Out of luck. Call the default handler to do
							 | 
						|
											** whatever it specifies for a failed malloc.
							 | 
						|
											** If this handler returns, then set error code,
							 | 
						|
											** print warning, and return. */
							 | 
						|
											(*MMoutOfMemory)(sizeof(DdNode)*(DD_MEM_CHUNK + 1));
							 | 
						|
											unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
											(void) fprintf(unique->err,
							 | 
						|
												       "cuddAllocNode: out of memory");
							 | 
						|
											(void) fprintf(unique->err, "Memory in use = %lu\n",
							 | 
						|
												       unique->memused);
							 | 
						|
								#endif
							 | 
						|
											return(NULL);
							 | 
						|
										    }
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									    if (mem != NULL) {	/* successful allocation; slice memory */
							 | 
						|
										ptruint offset;
							 | 
						|
										unique->memused += (DD_MEM_CHUNK + 1) * sizeof(DdNode);
							 | 
						|
										mem[0] = (DdNodePtr) unique->memoryList;
							 | 
						|
										unique->memoryList = mem;
							 | 
						|
								
							 | 
						|
										/* Here we rely on the fact that a DdNode is as large
							 | 
						|
										** as 4 pointers.  */
							 | 
						|
										offset = (ptruint) mem & (sizeof(DdNode) - 1);
							 | 
						|
										mem += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
							 | 
						|
										assert(((ptruint) mem & (sizeof(DdNode) - 1)) == 0);
							 | 
						|
										list = (DdNode *) mem;
							 | 
						|
								
							 | 
						|
										i = 1;
							 | 
						|
										do {
							 | 
						|
										    list[i - 1].ref = 0;
							 | 
						|
										    list[i - 1].next = &list[i];
							 | 
						|
										} while (++i < DD_MEM_CHUNK);
							 | 
						|
								
							 | 
						|
										list[DD_MEM_CHUNK-1].ref = 0;
							 | 
						|
										list[DD_MEM_CHUNK-1].next = NULL;
							 | 
						|
								
							 | 
						|
										unique->nextFree = &list[0];
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    unique->allocated++;
							 | 
						|
								    node = unique->nextFree;
							 | 
						|
								    unique->nextFree = node->next;
							 | 
						|
								    return(node);
							 | 
						|
								
							 | 
						|
								} /* end of cuddAllocNode */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Creates and initializes the unique table.]
							 | 
						|
								
							 | 
						|
								  Description [Creates and initializes the unique table. Returns a pointer
							 | 
						|
								  to the table if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_Init cuddFreeTable]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdManager *
							 | 
						|
								cuddInitTable(
							 | 
						|
								  unsigned int numVars  /* Initial number of BDD variables (and subtables) */,
							 | 
						|
								  unsigned int numVarsZ /* Initial number of ZDD variables (and subtables) */,
							 | 
						|
								  unsigned int numSlots /* Initial size of the BDD subtables */,
							 | 
						|
								  unsigned int looseUpTo /* Limit for fast table growth */)
							 | 
						|
								{
							 | 
						|
								    DdManager	*unique = ALLOC(DdManager,1);
							 | 
						|
								    int		i, j;
							 | 
						|
								    DdNodePtr	*nodelist;
							 | 
						|
								    DdNode	*sentinel;
							 | 
						|
								    unsigned int slots;
							 | 
						|
								    int shift;
							 | 
						|
								
							 | 
						|
								    if (unique == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    sentinel = &(unique->sentinel);
							 | 
						|
								    sentinel->ref = 0;
							 | 
						|
								    sentinel->index = 0;
							 | 
						|
								    cuddT(sentinel) = NULL;
							 | 
						|
								    cuddE(sentinel) = NULL;
							 | 
						|
								    sentinel->next = NULL;
							 | 
						|
								    unique->epsilon = DD_EPSILON;
							 | 
						|
								    unique->size = numVars;
							 | 
						|
								    unique->sizeZ = numVarsZ;
							 | 
						|
								    unique->maxSize = ddMax(DD_DEFAULT_RESIZE, numVars);
							 | 
						|
								    unique->maxSizeZ = ddMax(DD_DEFAULT_RESIZE, numVarsZ);
							 | 
						|
								
							 | 
						|
								    /* Adjust the requested number of slots to a power of 2. */
							 | 
						|
								    slots = 8;
							 | 
						|
								    while (slots < numSlots) {
							 | 
						|
									slots <<= 1;
							 | 
						|
								    }
							 | 
						|
								    unique->initSlots = slots;
							 | 
						|
								    shift = sizeof(int) * 8 - cuddComputeFloorLog2(slots);
							 | 
						|
								
							 | 
						|
								    unique->slots = (numVars + numVarsZ + 1) * slots;
							 | 
						|
								    unique->keys = 0;
							 | 
						|
								    unique->maxLive = ~0;	/* very large number */
							 | 
						|
								    unique->keysZ = 0;
							 | 
						|
								    unique->dead = 0;
							 | 
						|
								    unique->deadZ = 0;
							 | 
						|
								    unique->gcFrac = DD_GC_FRAC_HI;
							 | 
						|
								    unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
							 | 
						|
								    unique->looseUpTo = looseUpTo;
							 | 
						|
								    unique->gcEnabled = 1;
							 | 
						|
								    unique->allocated = 0;
							 | 
						|
								    unique->reclaimed = 0;
							 | 
						|
								    unique->subtables = ALLOC(DdSubtable,unique->maxSize);
							 | 
						|
								    if (unique->subtables == NULL) {
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->subtableZ = ALLOC(DdSubtable,unique->maxSizeZ);
							 | 
						|
								    if (unique->subtableZ == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->perm = ALLOC(int,unique->maxSize);
							 | 
						|
								    if (unique->perm == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->invperm = ALLOC(int,unique->maxSize);
							 | 
						|
								    if (unique->invperm == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->permZ = ALLOC(int,unique->maxSizeZ);
							 | 
						|
								    if (unique->permZ == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->invpermZ = ALLOC(int,unique->maxSizeZ);
							 | 
						|
								    if (unique->invpermZ == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									FREE(unique->permZ);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->map = NULL;
							 | 
						|
								    unique->stack = ALLOC(DdNodePtr,ddMax(unique->maxSize,unique->maxSizeZ)+1);
							 | 
						|
								    if (unique->stack == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									FREE(unique->permZ);
							 | 
						|
									FREE(unique->invpermZ);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->stack[0] = NULL; /* to suppress harmless UMR */
							 | 
						|
								
							 | 
						|
								#ifndef DD_NO_DEATH_ROW
							 | 
						|
								    unique->deathRowDepth = 1 << cuddComputeFloorLog2(unique->looseUpTo >> 2);
							 | 
						|
								    unique->deathRow = ALLOC(DdNodePtr,unique->deathRowDepth);
							 | 
						|
								    if (unique->deathRow == NULL) {
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									FREE(unique->permZ);
							 | 
						|
									FREE(unique->invpermZ);
							 | 
						|
									FREE(unique->stack);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    for (i = 0; i < unique->deathRowDepth; i++) {
							 | 
						|
									unique->deathRow[i] = NULL;
							 | 
						|
								    }
							 | 
						|
								    unique->nextDead = 0;
							 | 
						|
								    unique->deadMask = unique->deathRowDepth - 1;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    for (i = 0; (unsigned) i < numVars; i++) {
							 | 
						|
									unique->subtables[i].slots = slots;
							 | 
						|
									unique->subtables[i].shift = shift;
							 | 
						|
									unique->subtables[i].keys = 0;
							 | 
						|
									unique->subtables[i].dead = 0;
							 | 
						|
									unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									unique->subtables[i].bindVar = 0;
							 | 
						|
									unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
							 | 
						|
									unique->subtables[i].pairIndex = 0;
							 | 
						|
									unique->subtables[i].varHandled = 0;
							 | 
						|
									unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
							 | 
						|
								
							 | 
						|
									nodelist = unique->subtables[i].nodelist = ALLOC(DdNodePtr,slots);
							 | 
						|
									if (nodelist == NULL) {
							 | 
						|
									    for (j = 0; j < i; j++) {
							 | 
						|
										FREE(unique->subtables[j].nodelist);
							 | 
						|
									    }
							 | 
						|
									    FREE(unique->subtables);
							 | 
						|
									    FREE(unique->subtableZ);
							 | 
						|
									    FREE(unique->perm);
							 | 
						|
									    FREE(unique->invperm);
							 | 
						|
									    FREE(unique->permZ);
							 | 
						|
									    FREE(unique->invpermZ);
							 | 
						|
									    FREE(unique->stack);
							 | 
						|
									    FREE(unique);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									    nodelist[j] = sentinel;
							 | 
						|
									}
							 | 
						|
									unique->perm[i] = i;
							 | 
						|
									unique->invperm[i] = i;
							 | 
						|
								    }
							 | 
						|
								    for (i = 0; (unsigned) i < numVarsZ; i++) {
							 | 
						|
									unique->subtableZ[i].slots = slots;
							 | 
						|
									unique->subtableZ[i].shift = shift;
							 | 
						|
									unique->subtableZ[i].keys = 0;
							 | 
						|
									unique->subtableZ[i].dead = 0;
							 | 
						|
									unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									nodelist = unique->subtableZ[i].nodelist = ALLOC(DdNodePtr,slots);
							 | 
						|
									if (nodelist == NULL) {
							 | 
						|
									    for (j = 0; (unsigned) j < numVars; j++) {
							 | 
						|
										FREE(unique->subtables[j].nodelist);
							 | 
						|
									    }
							 | 
						|
									    FREE(unique->subtables);
							 | 
						|
									    for (j = 0; j < i; j++) {
							 | 
						|
										FREE(unique->subtableZ[j].nodelist);
							 | 
						|
									    }
							 | 
						|
									    FREE(unique->subtableZ);
							 | 
						|
									    FREE(unique->perm);
							 | 
						|
									    FREE(unique->invperm);
							 | 
						|
									    FREE(unique->permZ);
							 | 
						|
									    FREE(unique->invpermZ);
							 | 
						|
									    FREE(unique->stack);
							 | 
						|
									    FREE(unique);
							 | 
						|
									    return(NULL);
							 | 
						|
									}
							 | 
						|
									for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									    nodelist[j] = NULL;
							 | 
						|
									}
							 | 
						|
									unique->permZ[i] = i;
							 | 
						|
									unique->invpermZ[i] = i;
							 | 
						|
								    }
							 | 
						|
								    unique->constants.slots = slots;
							 | 
						|
								    unique->constants.shift = shift;
							 | 
						|
								    unique->constants.keys = 0;
							 | 
						|
								    unique->constants.dead = 0;
							 | 
						|
								    unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
								    nodelist = unique->constants.nodelist = ALLOC(DdNodePtr,slots);
							 | 
						|
								    if (nodelist == NULL) {
							 | 
						|
									for (j = 0; (unsigned) j < numVars; j++) {
							 | 
						|
									    FREE(unique->subtables[j].nodelist);
							 | 
						|
									}
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									for (j = 0; (unsigned) j < numVarsZ; j++) {
							 | 
						|
									    FREE(unique->subtableZ[j].nodelist);
							 | 
						|
									}
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									FREE(unique->permZ);
							 | 
						|
									FREE(unique->invpermZ);
							 | 
						|
									FREE(unique->stack);
							 | 
						|
									FREE(unique);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									nodelist[j] = NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    unique->memoryList = NULL;
							 | 
						|
								    unique->nextFree = NULL;
							 | 
						|
								
							 | 
						|
								    unique->memused = sizeof(DdManager) + (unique->maxSize + unique->maxSizeZ)
							 | 
						|
									* (sizeof(DdSubtable) + 2 * sizeof(int)) + (numVars + 1) *
							 | 
						|
									slots * sizeof(DdNodePtr) +
							 | 
						|
									(ddMax(unique->maxSize,unique->maxSizeZ) + 1) * sizeof(DdNodePtr);
							 | 
						|
								#ifndef DD_NO_DEATH_ROW
							 | 
						|
								    unique->memused += unique->deathRowDepth * sizeof(DdNodePtr);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Initialize fields concerned with automatic dynamic reordering. */
							 | 
						|
								    unique->reordered = 0;
							 | 
						|
								    unique->reorderings = 0;
							 | 
						|
								    unique->maxReorderings = ~0;
							 | 
						|
								    unique->siftMaxVar = DD_SIFT_MAX_VAR;
							 | 
						|
								    unique->siftMaxSwap = DD_SIFT_MAX_SWAPS;
							 | 
						|
								    unique->maxGrowth = DD_MAX_REORDER_GROWTH;
							 | 
						|
								    unique->maxGrowthAlt = 2.0 * DD_MAX_REORDER_GROWTH;
							 | 
						|
								    unique->reordCycle = 0;	/* do not use alternate threshold */
							 | 
						|
								    unique->autoDyn = 0;	/* initially disabled */
							 | 
						|
								    unique->autoDynZ = 0;	/* initially disabled */
							 | 
						|
								    unique->autoMethod = CUDD_REORDER_SIFT;
							 | 
						|
								    unique->autoMethodZ = CUDD_REORDER_SIFT;
							 | 
						|
								    unique->realign = 0;	/* initially disabled */
							 | 
						|
								    unique->realignZ = 0;	/* initially disabled */
							 | 
						|
								    unique->nextDyn = DD_FIRST_REORDER;
							 | 
						|
								    unique->countDead = ~0;
							 | 
						|
								    unique->tree = NULL;
							 | 
						|
								    unique->treeZ = NULL;
							 | 
						|
								    unique->groupcheck = CUDD_GROUP_CHECK7;
							 | 
						|
								    unique->recomb = DD_DEFAULT_RECOMB;
							 | 
						|
								    unique->symmviolation = 0;
							 | 
						|
								    unique->arcviolation = 0;
							 | 
						|
								    unique->populationSize = 0;
							 | 
						|
								    unique->numberXovers = 0;
							 | 
						|
								    unique->randomizeOrder = 0;
							 | 
						|
								    unique->linear = NULL;
							 | 
						|
								    unique->linearSize = 0;
							 | 
						|
								
							 | 
						|
								    /* Initialize ZDD universe. */
							 | 
						|
								    unique->univ = (DdNodePtr *)NULL;
							 | 
						|
								
							 | 
						|
								    /* Initialize auxiliary fields. */
							 | 
						|
								    unique->localCaches = NULL;
							 | 
						|
								    unique->preGCHook = NULL;
							 | 
						|
								    unique->postGCHook = NULL;
							 | 
						|
								    unique->preReorderingHook = NULL;
							 | 
						|
								    unique->postReorderingHook = NULL;
							 | 
						|
								    unique->out = stdout;
							 | 
						|
								    unique->err = stderr;
							 | 
						|
								    unique->errorCode = CUDD_NO_ERROR;
							 | 
						|
								    unique->startTime = util_cpu_time();
							 | 
						|
								    unique->timeLimit = ~0UL;
							 | 
						|
								
							 | 
						|
								    /* Initialize statistical counters. */
							 | 
						|
								    unique->maxmemhard = ~ 0UL;
							 | 
						|
								    unique->garbageCollections = 0;
							 | 
						|
								    unique->GCTime = 0;
							 | 
						|
								    unique->reordTime = 0;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    unique->nodesDropped = 0;
							 | 
						|
								    unique->nodesFreed = 0;
							 | 
						|
								#endif
							 | 
						|
								    unique->peakLiveNodes = 0;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
								    unique->uniqueLookUps = 0;
							 | 
						|
								    unique->uniqueLinks = 0;
							 | 
						|
								#endif
							 | 
						|
								#ifdef DD_COUNT
							 | 
						|
								    unique->recursiveCalls = 0;
							 | 
						|
								    unique->swapSteps = 0;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    unique->nextSample = 250000;
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return(unique);
							 | 
						|
								
							 | 
						|
								} /* end of cuddInitTable */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Frees the resources associated to a unique table.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddInitTable]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								void
							 | 
						|
								cuddFreeTable(
							 | 
						|
								  DdManager * unique)
							 | 
						|
								{
							 | 
						|
								    DdNodePtr *next;
							 | 
						|
								    DdNodePtr *memlist = unique->memoryList;
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								    if (unique->univ != NULL) cuddZddFreeUniv(unique);
							 | 
						|
								    while (memlist != NULL) {
							 | 
						|
									next = (DdNodePtr *) memlist[0];	/* link to next block */
							 | 
						|
									FREE(memlist);
							 | 
						|
									memlist = next;
							 | 
						|
								    }
							 | 
						|
								    unique->nextFree = NULL;
							 | 
						|
								    unique->memoryList = NULL;
							 | 
						|
								
							 | 
						|
								    for (i = 0; i < unique->size; i++) {
							 | 
						|
									FREE(unique->subtables[i].nodelist);
							 | 
						|
								    }
							 | 
						|
								    for (i = 0; i < unique->sizeZ; i++) {
							 | 
						|
									FREE(unique->subtableZ[i].nodelist);
							 | 
						|
								    }
							 | 
						|
								    FREE(unique->constants.nodelist);
							 | 
						|
								    FREE(unique->subtables);
							 | 
						|
								    FREE(unique->subtableZ);
							 | 
						|
								    FREE(unique->acache);
							 | 
						|
								    FREE(unique->perm);
							 | 
						|
								    FREE(unique->permZ);
							 | 
						|
								    FREE(unique->invperm);
							 | 
						|
								    FREE(unique->invpermZ);
							 | 
						|
								    FREE(unique->vars);
							 | 
						|
								    if (unique->map != NULL) FREE(unique->map);
							 | 
						|
								    FREE(unique->stack);
							 | 
						|
								#ifndef DD_NO_DEATH_ROW
							 | 
						|
								    FREE(unique->deathRow);
							 | 
						|
								#endif
							 | 
						|
								    if (unique->tree != NULL) Mtr_FreeTree(unique->tree);
							 | 
						|
								    if (unique->treeZ != NULL) Mtr_FreeTree(unique->treeZ);
							 | 
						|
								    if (unique->linear != NULL) FREE(unique->linear);
							 | 
						|
								    while (unique->preGCHook != NULL)
							 | 
						|
									Cudd_RemoveHook(unique,unique->preGCHook->f,CUDD_PRE_GC_HOOK);
							 | 
						|
								    while (unique->postGCHook != NULL)
							 | 
						|
									Cudd_RemoveHook(unique,unique->postGCHook->f,CUDD_POST_GC_HOOK);
							 | 
						|
								    while (unique->preReorderingHook != NULL)
							 | 
						|
									Cudd_RemoveHook(unique,unique->preReorderingHook->f,
							 | 
						|
											CUDD_PRE_REORDERING_HOOK);
							 | 
						|
								    while (unique->postReorderingHook != NULL)
							 | 
						|
									Cudd_RemoveHook(unique,unique->postReorderingHook->f,
							 | 
						|
											CUDD_POST_REORDERING_HOOK);
							 | 
						|
								    FREE(unique);
							 | 
						|
								
							 | 
						|
								} /* end of cuddFreeTable */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Performs garbage collection on the unique tables.]
							 | 
						|
								
							 | 
						|
								  Description [Performs garbage collection on the BDD and ZDD unique tables.
							 | 
						|
								  If clearCache is 0, the cache is not cleared. This should only be
							 | 
						|
								  specified if the cache has been cleared right before calling
							 | 
						|
								  cuddGarbageCollect. (As in the case of dynamic reordering.)
							 | 
						|
								  Returns the total number of deleted nodes.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								cuddGarbageCollect(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  clearCache)
							 | 
						|
								{
							 | 
						|
								    DdHook	*hook;
							 | 
						|
								    DdCache	*cache = unique->cache;
							 | 
						|
								    DdNode	*sentinel = &(unique->sentinel);
							 | 
						|
								    DdNodePtr	*nodelist;
							 | 
						|
								    int		i, j, deleted, totalDeleted, totalDeletedZ;
							 | 
						|
								    DdCache	*c;
							 | 
						|
								    DdNode	*node,*next;
							 | 
						|
								    DdNodePtr	*lastP;
							 | 
						|
								    int		slots;
							 | 
						|
								    unsigned long localTime;
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								    DdNodePtr	tree;
							 | 
						|
								#else
							 | 
						|
								    DdNodePtr *memListTrav, *nxtNode;
							 | 
						|
								    DdNode *downTrav, *sentry;
							 | 
						|
								    int k;
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								#ifndef DD_NO_DEATH_ROW
							 | 
						|
								    cuddClearDeathRow(unique);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    hook = unique->preGCHook;
							 | 
						|
								    while (hook != NULL) {
							 | 
						|
									int res = (hook->f)(unique,"DD",NULL);
							 | 
						|
									if (res == 0) return(0);
							 | 
						|
									hook = hook->next;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (unique->dead + unique->deadZ == 0) {
							 | 
						|
									hook = unique->postGCHook;
							 | 
						|
									while (hook != NULL) {
							 | 
						|
									    int res = (hook->f)(unique,"DD",NULL);
							 | 
						|
									    if (res == 0) return(0);
							 | 
						|
									    hook = hook->next;
							 | 
						|
									}
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* If many nodes are being reclaimed, we want to resize the tables
							 | 
						|
								    ** more aggressively, to reduce the frequency of garbage collection.
							 | 
						|
								    */
							 | 
						|
								    if (clearCache && unique->gcFrac == DD_GC_FRAC_LO &&
							 | 
						|
									unique->slots <= unique->looseUpTo && unique->stash != NULL) {
							 | 
						|
									unique->minDead = (unsigned) (DD_GC_FRAC_HI * (double) unique->slots);
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_HI);
							 | 
						|
									(void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
							 | 
						|
								#endif
							 | 
						|
									unique->gcFrac = DD_GC_FRAC_HI;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    localTime = util_cpu_time();
							 | 
						|
								
							 | 
						|
								    unique->garbageCollections++;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
								    (void) fprintf(unique->err,
							 | 
						|
										   "garbage collecting (%d dead BDD nodes out of %d, min %d)...",
							 | 
						|
										   unique->dead, unique->keys, unique->minDead);
							 | 
						|
								    (void) fprintf(unique->err,
							 | 
						|
										   "                   (%d dead ZDD nodes out of %d)...",
							 | 
						|
										   unique->deadZ, unique->keysZ);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Remove references to garbage collected nodes from the cache. */
							 | 
						|
								    if (clearCache) {
							 | 
						|
									slots = unique->cacheSlots;
							 | 
						|
									for (i = 0; i < slots; i++) {
							 | 
						|
									    c = &cache[i];
							 | 
						|
									    if (c->data != NULL) {
							 | 
						|
										if (cuddClean(c->f)->ref == 0 ||
							 | 
						|
										cuddClean(c->g)->ref == 0 ||
							 | 
						|
										(((ptruint)c->f & 0x2) && Cudd_Regular(c->h)->ref == 0) ||
							 | 
						|
										(c->data != DD_NON_CONSTANT &&
							 | 
						|
										Cudd_Regular(c->data)->ref == 0)) {
							 | 
						|
										    c->data = NULL;
							 | 
						|
										    unique->cachedeletions++;
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									cuddLocalCacheClearDead(unique);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Now return dead nodes to free list. Count them for sanity check. */
							 | 
						|
								    totalDeleted = 0;
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								    tree = NULL;
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    for (i = 0; i < unique->size; i++) {
							 | 
						|
									if (unique->subtables[i].dead == 0) continue;
							 | 
						|
									nodelist = unique->subtables[i].nodelist;
							 | 
						|
								
							 | 
						|
									deleted = 0;
							 | 
						|
									slots = unique->subtables[i].slots;
							 | 
						|
									for (j = 0; j < slots; j++) {
							 | 
						|
									    lastP = &(nodelist[j]);
							 | 
						|
									    node = *lastP;
							 | 
						|
									    while (node != sentinel) {
							 | 
						|
										next = node->next;
							 | 
						|
										if (node->ref == 0) {
							 | 
						|
										    deleted++;
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
										    cuddOrderedInsert(&tree,node);
							 | 
						|
								#endif
							 | 
						|
								#else
							 | 
						|
										    cuddDeallocNode(unique,node);
							 | 
						|
								#endif
							 | 
						|
										} else {
							 | 
						|
										    *lastP = node;
							 | 
						|
										    lastP = &(node->next);
							 | 
						|
										}
							 | 
						|
										node = next;
							 | 
						|
									    }
							 | 
						|
									    *lastP = sentinel;
							 | 
						|
									}
							 | 
						|
									if ((unsigned) deleted != unique->subtables[i].dead) {
							 | 
						|
									    ddReportRefMess(unique, i, "cuddGarbageCollect");
							 | 
						|
									}
							 | 
						|
									totalDeleted += deleted;
							 | 
						|
									unique->subtables[i].keys -= deleted;
							 | 
						|
									unique->subtables[i].dead = 0;
							 | 
						|
								    }
							 | 
						|
								    if (unique->constants.dead != 0) {
							 | 
						|
									nodelist = unique->constants.nodelist;
							 | 
						|
									deleted = 0;
							 | 
						|
									slots = unique->constants.slots;
							 | 
						|
									for (j = 0; j < slots; j++) {
							 | 
						|
									    lastP = &(nodelist[j]);
							 | 
						|
									    node = *lastP;
							 | 
						|
									    while (node != NULL) {
							 | 
						|
										next = node->next;
							 | 
						|
										if (node->ref == 0) {
							 | 
						|
										    deleted++;
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
										    cuddOrderedInsert(&tree,node);
							 | 
						|
								#endif
							 | 
						|
								#else
							 | 
						|
										    cuddDeallocNode(unique,node);
							 | 
						|
								#endif
							 | 
						|
										} else {
							 | 
						|
										    *lastP = node;
							 | 
						|
										    lastP = &(node->next);
							 | 
						|
										}
							 | 
						|
										node = next;
							 | 
						|
									    }
							 | 
						|
									    *lastP = NULL;
							 | 
						|
									}
							 | 
						|
									if ((unsigned) deleted != unique->constants.dead) {
							 | 
						|
									    ddReportRefMess(unique, CUDD_CONST_INDEX, "cuddGarbageCollect");
							 | 
						|
									}
							 | 
						|
									totalDeleted += deleted;
							 | 
						|
									unique->constants.keys -= deleted;
							 | 
						|
									unique->constants.dead = 0;
							 | 
						|
								    }
							 | 
						|
								    if ((unsigned) totalDeleted != unique->dead) {
							 | 
						|
									ddReportRefMess(unique, -1, "cuddGarbageCollect");
							 | 
						|
								    }
							 | 
						|
								    unique->keys -= totalDeleted;
							 | 
						|
								    unique->dead = 0;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    unique->nodesFreed += (double) totalDeleted;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    totalDeletedZ = 0;
							 | 
						|
								
							 | 
						|
								    for (i = 0; i < unique->sizeZ; i++) {
							 | 
						|
									if (unique->subtableZ[i].dead == 0) continue;
							 | 
						|
									nodelist = unique->subtableZ[i].nodelist;
							 | 
						|
								
							 | 
						|
									deleted = 0;
							 | 
						|
									slots = unique->subtableZ[i].slots;
							 | 
						|
									for (j = 0; j < slots; j++) {
							 | 
						|
									    lastP = &(nodelist[j]);
							 | 
						|
									    node = *lastP;
							 | 
						|
									    while (node != NULL) {
							 | 
						|
										next = node->next;
							 | 
						|
										if (node->ref == 0) {
							 | 
						|
										    deleted++;
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
										    cuddOrderedInsert(&tree,node);
							 | 
						|
								#endif
							 | 
						|
								#else
							 | 
						|
										    cuddDeallocNode(unique,node);
							 | 
						|
								#endif
							 | 
						|
										} else {
							 | 
						|
										    *lastP = node;
							 | 
						|
										    lastP = &(node->next);
							 | 
						|
										}
							 | 
						|
										node = next;
							 | 
						|
									    }
							 | 
						|
									    *lastP = NULL;
							 | 
						|
									}
							 | 
						|
									if ((unsigned) deleted != unique->subtableZ[i].dead) {
							 | 
						|
									    ddReportRefMess(unique, i, "cuddGarbageCollect");
							 | 
						|
									}
							 | 
						|
									totalDeletedZ += deleted;
							 | 
						|
									unique->subtableZ[i].keys -= deleted;
							 | 
						|
									unique->subtableZ[i].dead = 0;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* No need to examine the constant table for ZDDs.
							 | 
						|
								    ** If we did we should be careful not to count whatever dead
							 | 
						|
								    ** nodes we found there among the dead ZDD nodes. */
							 | 
						|
								    if ((unsigned) totalDeletedZ != unique->deadZ) {
							 | 
						|
									ddReportRefMess(unique, -1, "cuddGarbageCollect");
							 | 
						|
								    }
							 | 
						|
								    unique->keysZ -= totalDeletedZ;
							 | 
						|
								    unique->deadZ = 0;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    unique->nodesFreed += (double) totalDeletedZ;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								    unique->nextFree = cuddOrderedThread(tree,unique->nextFree);
							 | 
						|
								#else
							 | 
						|
								    memListTrav = unique->memoryList;
							 | 
						|
								    sentry = NULL;
							 | 
						|
								    while (memListTrav != NULL) {
							 | 
						|
									ptruint offset;
							 | 
						|
									nxtNode = (DdNodePtr *)memListTrav[0];
							 | 
						|
									offset = (ptruint) memListTrav & (sizeof(DdNode) - 1);
							 | 
						|
									memListTrav += (sizeof(DdNode) - offset) / sizeof(DdNodePtr);
							 | 
						|
									downTrav = (DdNode *)memListTrav;
							 | 
						|
									k = 0;
							 | 
						|
									do {
							 | 
						|
									    if (downTrav[k].ref == 0) {
							 | 
						|
										if (sentry == NULL) {
							 | 
						|
										    unique->nextFree = sentry = &downTrav[k];
							 | 
						|
										} else {
							 | 
						|
										    /* First hook sentry->next to the dead node and then
							 | 
						|
										    ** reassign sentry to the dead node. */
							 | 
						|
										    sentry = (sentry->next = &downTrav[k]);
							 | 
						|
										}
							 | 
						|
									    }
							 | 
						|
									} while (++k < DD_MEM_CHUNK);
							 | 
						|
									memListTrav = nxtNode;
							 | 
						|
								    }
							 | 
						|
								    sentry->next = NULL;
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    unique->GCTime += util_cpu_time() - localTime;
							 | 
						|
								
							 | 
						|
								    hook = unique->postGCHook;
							 | 
						|
								    while (hook != NULL) {
							 | 
						|
									int res = (hook->f)(unique,"DD",NULL);
							 | 
						|
									if (res == 0) return(0);
							 | 
						|
									hook = hook->next;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
								    (void) fprintf(unique->err," done\n");
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return(totalDeleted+totalDeletedZ);
							 | 
						|
								
							 | 
						|
								} /* end of cuddGarbageCollect */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Wrapper for cuddUniqueInterZdd.]
							 | 
						|
								
							 | 
						|
								  Description [Wrapper for cuddUniqueInterZdd, which applies the ZDD
							 | 
						|
								  reduction rule. Returns a pointer to the result node under normal
							 | 
						|
								  conditions; NULL if reordering occurred or memory was exhausted.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddUniqueInterZdd]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddZddGetNode(
							 | 
						|
								  DdManager * zdd,
							 | 
						|
								  int  id,
							 | 
						|
								  DdNode * T,
							 | 
						|
								  DdNode * E)
							 | 
						|
								{
							 | 
						|
								    DdNode	*node;
							 | 
						|
								
							 | 
						|
								    if (T == DD_ZERO(zdd))
							 | 
						|
									return(E);
							 | 
						|
								    node = cuddUniqueInterZdd(zdd, id, T, E);
							 | 
						|
								    return(node);
							 | 
						|
								
							 | 
						|
								} /* end of cuddZddGetNode */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Wrapper for cuddUniqueInterZdd that is independent of variable
							 | 
						|
								  ordering.]
							 | 
						|
								
							 | 
						|
								  Description [Wrapper for cuddUniqueInterZdd that is independent of
							 | 
						|
								  variable ordering (IVO). This function does not require parameter
							 | 
						|
								  index to precede the indices of the top nodes of g and h in the
							 | 
						|
								  variable order.  Returns a pointer to the result node under normal
							 | 
						|
								  conditions; NULL if reordering occurred or memory was exhausted.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddZddGetNode cuddZddIsop]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddZddGetNodeIVO(
							 | 
						|
								  DdManager * dd,
							 | 
						|
								  int  index,
							 | 
						|
								  DdNode * g,
							 | 
						|
								  DdNode * h)
							 | 
						|
								{
							 | 
						|
								    DdNode	*f, *r, *t;
							 | 
						|
								    DdNode	*zdd_one = DD_ONE(dd);
							 | 
						|
								    DdNode	*zdd_zero = DD_ZERO(dd);
							 | 
						|
								
							 | 
						|
								    f = cuddUniqueInterZdd(dd, index, zdd_one, zdd_zero);
							 | 
						|
								    if (f == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(f);
							 | 
						|
								    t = cuddZddProduct(dd, f, g);
							 | 
						|
								    if (t == NULL) {
							 | 
						|
									Cudd_RecursiveDerefZdd(dd, f);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(t);
							 | 
						|
								    Cudd_RecursiveDerefZdd(dd, f);
							 | 
						|
								    r = cuddZddUnion(dd, t, h);
							 | 
						|
								    if (r == NULL) {
							 | 
						|
									Cudd_RecursiveDerefZdd(dd, t);
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    cuddRef(r);
							 | 
						|
								    Cudd_RecursiveDerefZdd(dd, t);
							 | 
						|
								
							 | 
						|
								    cuddDeref(r);
							 | 
						|
								    return(r);
							 | 
						|
								
							 | 
						|
								} /* end of cuddZddGetNodeIVO */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Checks the unique table for the existence of an internal node.]
							 | 
						|
								
							 | 
						|
								  Description [Checks the unique table for the existence of an internal
							 | 
						|
								  node. If it does not exist, it creates a new one.  Does not
							 | 
						|
								  modify the reference count of whatever is returned.  A newly created
							 | 
						|
								  internal node comes back with a reference count 0.  For a newly
							 | 
						|
								  created node, increments the reference counts of what T and E point
							 | 
						|
								  to.  Returns a pointer to the new node if successful; NULL if memory
							 | 
						|
								  is exhausted or if reordering took place.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddUniqueInterZdd]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddUniqueInter(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  index,
							 | 
						|
								  DdNode * T,
							 | 
						|
								  DdNode * E)
							 | 
						|
								{
							 | 
						|
								    int pos;
							 | 
						|
								    unsigned int level;
							 | 
						|
								    int retval;
							 | 
						|
								    DdNodePtr *nodelist;
							 | 
						|
								    DdNode *looking;
							 | 
						|
								    DdNodePtr *previousP;
							 | 
						|
								    DdSubtable *subtable;
							 | 
						|
								    int gcNumber;
							 | 
						|
								
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
								    unique->uniqueLookUps++;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if ((0x1ffffUL & (unsigned long) unique->cacheMisses) == 0) {
							 | 
						|
								        if (util_cpu_time() - unique->startTime > unique->timeLimit) {
							 | 
						|
								            unique->errorCode = CUDD_TIMEOUT_EXPIRED;
							 | 
						|
								            return(NULL);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    if (index >= unique->size) {
							 | 
						|
								        int amount = ddMax(DD_DEFAULT_RESIZE,unique->size/20);
							 | 
						|
								        if (!ddResizeTable(unique,index,amount)) return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    level = unique->perm[index];
							 | 
						|
								    subtable = &(unique->subtables[level]);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    assert(level < (unsigned) cuddI(unique,T->index));
							 | 
						|
								    assert(level < (unsigned) cuddI(unique,Cudd_Regular(E)->index));
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    pos = ddHash(T, E, subtable->shift);
							 | 
						|
								    nodelist = subtable->nodelist;
							 | 
						|
								    previousP = &(nodelist[pos]);
							 | 
						|
								    looking = *previousP;
							 | 
						|
								
							 | 
						|
								    while (T < cuddT(looking)) {
							 | 
						|
									previousP = &(looking->next);
							 | 
						|
									looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								    while (T == cuddT(looking) && E < cuddE(looking)) {
							 | 
						|
									previousP = &(looking->next);
							 | 
						|
									looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								    if (T == cuddT(looking) && E == cuddE(looking)) {
							 | 
						|
									if (looking->ref == 0) {
							 | 
						|
									    cuddReclaim(unique,looking);
							 | 
						|
									}
							 | 
						|
									return(looking);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* countDead is 0 if deads should be counted and ~0 if they should not. */
							 | 
						|
								    if (unique->autoDyn &&
							 | 
						|
								        unique->keys - (unique->dead & unique->countDead) >= unique->nextDyn &&
							 | 
						|
								        unique->maxReorderings > 0) {
							 | 
						|
								        unsigned long cpuTime;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									retval = Cudd_DebugCheck(unique);
							 | 
						|
									if (retval != 0) return(NULL);
							 | 
						|
									retval = Cudd_CheckKeys(unique);
							 | 
						|
									if (retval != 0) return(NULL);
							 | 
						|
								#endif
							 | 
						|
									retval = Cudd_ReduceHeap(unique,unique->autoMethod,10); /* 10 = whatever */
							 | 
						|
								        unique->maxReorderings--;
							 | 
						|
									if (retval == 0) {
							 | 
						|
								            unique->reordered = 2;
							 | 
						|
								        } else if ((cpuTime = util_cpu_time()) - unique->startTime > unique->timeLimit) {
							 | 
						|
								            unique->errorCode = CUDD_TIMEOUT_EXPIRED;
							 | 
						|
								            unique->reordered = 0;
							 | 
						|
								        } else if (unique->timeLimit - (cpuTime - unique->startTime)
							 | 
						|
								                   < unique->reordTime) {
							 | 
						|
								            unique->autoDyn = 0;
							 | 
						|
								        }
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									retval = Cudd_DebugCheck(unique);
							 | 
						|
									if (retval != 0) unique->reordered = 2;
							 | 
						|
									retval = Cudd_CheckKeys(unique);
							 | 
						|
									if (retval != 0) unique->reordered = 2;
							 | 
						|
								#endif
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (subtable->keys > subtable->maxKeys) {
							 | 
						|
									if (unique->gcEnabled &&
							 | 
						|
									    ((unique->dead > unique->minDead) ||
							 | 
						|
									    ((unique->dead > unique->minDead / 2) &&
							 | 
						|
									    (subtable->dead > subtable->keys * 0.95)))) { /* too many dead */
							 | 
						|
								            if (util_cpu_time() - unique->startTime > unique->timeLimit) {
							 | 
						|
								                unique->errorCode = CUDD_TIMEOUT_EXPIRED;
							 | 
						|
								                return(NULL);
							 | 
						|
								            }
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									} else {
							 | 
						|
									    cuddRehash(unique,(int)level);
							 | 
						|
									}
							 | 
						|
									/* Update pointer to insertion point. In the case of rehashing,
							 | 
						|
									** the slot may have changed. In the case of garbage collection,
							 | 
						|
									** the predecessor may have been dead. */
							 | 
						|
									pos = ddHash(T, E, subtable->shift);
							 | 
						|
									nodelist = subtable->nodelist;
							 | 
						|
									previousP = &(nodelist[pos]);
							 | 
						|
									looking = *previousP;
							 | 
						|
								
							 | 
						|
									while (T < cuddT(looking)) {
							 | 
						|
									    previousP = &(looking->next);
							 | 
						|
									    looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									    unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									}
							 | 
						|
									while (T == cuddT(looking) && E < cuddE(looking)) {
							 | 
						|
									    previousP = &(looking->next);
							 | 
						|
									    looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									    unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    gcNumber = unique->garbageCollections;
							 | 
						|
								    looking = cuddAllocNode(unique);
							 | 
						|
								    if (looking == NULL) {
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								    unique->keys++;
							 | 
						|
								    subtable->keys++;
							 | 
						|
								
							 | 
						|
								    if (gcNumber != unique->garbageCollections) {
							 | 
						|
									DdNode *looking2;
							 | 
						|
									pos = ddHash(T, E, subtable->shift);
							 | 
						|
									nodelist = subtable->nodelist;
							 | 
						|
									previousP = &(nodelist[pos]);
							 | 
						|
									looking2 = *previousP;
							 | 
						|
								
							 | 
						|
									while (T < cuddT(looking2)) {
							 | 
						|
									    previousP = &(looking2->next);
							 | 
						|
									    looking2 = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									    unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									}
							 | 
						|
									while (T == cuddT(looking2) && E < cuddE(looking2)) {
							 | 
						|
									    previousP = &(looking2->next);
							 | 
						|
									    looking2 = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									    unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    looking->index = index;
							 | 
						|
								    cuddT(looking) = T;
							 | 
						|
								    cuddE(looking) = E;
							 | 
						|
								    looking->next = *previousP;
							 | 
						|
								    *previousP = looking;
							 | 
						|
								    cuddSatInc(T->ref);		/* we know T is a regular pointer */
							 | 
						|
								    cuddRef(E);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    cuddCheckCollisionOrdering(unique,level,pos);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return(looking);
							 | 
						|
								
							 | 
						|
								} /* end of cuddUniqueInter */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Wrapper for cuddUniqueInter that is independent of variable
							 | 
						|
								  ordering.]
							 | 
						|
								
							 | 
						|
								  Description [Wrapper for cuddUniqueInter that is independent of
							 | 
						|
								  variable ordering (IVO). This function does not require parameter
							 | 
						|
								  index to precede the indices of the top nodes of T and E in the
							 | 
						|
								  variable order.  Returns a pointer to the result node under normal
							 | 
						|
								  conditions; NULL if reordering occurred or memory was exhausted.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddUniqueInter Cudd_MakeBddFromZddCover]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddUniqueInterIVO(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  index,
							 | 
						|
								  DdNode * T,
							 | 
						|
								  DdNode * E)
							 | 
						|
								{
							 | 
						|
								    DdNode *result;
							 | 
						|
								    DdNode *v;
							 | 
						|
								
							 | 
						|
								    v = cuddUniqueInter(unique, index, DD_ONE(unique),
							 | 
						|
											Cudd_Not(DD_ONE(unique)));
							 | 
						|
								    if (v == NULL)
							 | 
						|
									return(NULL);
							 | 
						|
								    /* Since v is a projection function, we can skip the call to cuddRef. */
							 | 
						|
								    result = cuddBddIteRecur(unique, v, T, E);
							 | 
						|
								    return(result);
							 | 
						|
								
							 | 
						|
								} /* end of cuddUniqueInterIVO */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Checks the unique table for the existence of an internal
							 | 
						|
								  ZDD node.]
							 | 
						|
								
							 | 
						|
								  Description [Checks the unique table for the existence of an internal
							 | 
						|
								  ZDD node. If it does not exist, it creates a new one.  Does not
							 | 
						|
								  modify the reference count of whatever is returned.  A newly created
							 | 
						|
								  internal node comes back with a reference count 0.  For a newly
							 | 
						|
								  created node, increments the reference counts of what T and E point
							 | 
						|
								  to.  Returns a pointer to the new node if successful; NULL if memory
							 | 
						|
								  is exhausted or if reordering took place.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddUniqueInter]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddUniqueInterZdd(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  index,
							 | 
						|
								  DdNode * T,
							 | 
						|
								  DdNode * E)
							 | 
						|
								{
							 | 
						|
								    int pos;
							 | 
						|
								    unsigned int level;
							 | 
						|
								    int retval;
							 | 
						|
								    DdNodePtr *nodelist;
							 | 
						|
								    DdNode *looking;
							 | 
						|
								    DdSubtable *subtable;
							 | 
						|
								
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
								    unique->uniqueLookUps++;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (index >= unique->sizeZ) {
							 | 
						|
									if (!cuddResizeTableZdd(unique,index)) return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    level = unique->permZ[index];
							 | 
						|
								    subtable = &(unique->subtableZ[level]);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    assert(level < (unsigned) cuddIZ(unique,T->index));
							 | 
						|
								    assert(level < (unsigned) cuddIZ(unique,Cudd_Regular(E)->index));
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (subtable->keys > subtable->maxKeys) {
							 | 
						|
									if (unique->gcEnabled && ((unique->deadZ > unique->minDead) ||
							 | 
						|
									(10 * subtable->dead > 9 * subtable->keys))) {	/* too many dead */
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									} else {
							 | 
						|
									    ddRehashZdd(unique,(int)level);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    pos = ddHash(T, E, subtable->shift);
							 | 
						|
								    nodelist = subtable->nodelist;
							 | 
						|
								    looking = nodelist[pos];
							 | 
						|
								
							 | 
						|
								    while (looking != NULL) {
							 | 
						|
									if (cuddT(looking) == T && cuddE(looking) == E) {
							 | 
						|
									    if (looking->ref == 0) {
							 | 
						|
										cuddReclaimZdd(unique,looking);
							 | 
						|
									    }
							 | 
						|
									    return(looking);
							 | 
						|
									}
							 | 
						|
									looking = looking->next;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* countDead is 0 if deads should be counted and ~0 if they should not. */
							 | 
						|
								    if (unique->autoDynZ &&
							 | 
						|
								    unique->keysZ - (unique->deadZ & unique->countDead) >= unique->nextDyn) {
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									retval = Cudd_DebugCheck(unique);
							 | 
						|
									if (retval != 0) return(NULL);
							 | 
						|
									retval = Cudd_CheckKeys(unique);
							 | 
						|
									if (retval != 0) return(NULL);
							 | 
						|
								#endif
							 | 
						|
									retval = Cudd_zddReduceHeap(unique,unique->autoMethodZ,10); /* 10 = whatever */
							 | 
						|
									if (retval == 0) unique->reordered = 2;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									retval = Cudd_DebugCheck(unique);
							 | 
						|
									if (retval != 0) unique->reordered = 2;
							 | 
						|
									retval = Cudd_CheckKeys(unique);
							 | 
						|
									if (retval != 0) unique->reordered = 2;
							 | 
						|
								#endif
							 | 
						|
									return(NULL);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    unique->keysZ++;
							 | 
						|
								    subtable->keys++;
							 | 
						|
								
							 | 
						|
								    looking = cuddAllocNode(unique);
							 | 
						|
								    if (looking == NULL) return(NULL);
							 | 
						|
								    looking->index = index;
							 | 
						|
								    cuddT(looking) = T;
							 | 
						|
								    cuddE(looking) = E;
							 | 
						|
								    looking->next = nodelist[pos];
							 | 
						|
								    nodelist[pos] = looking;
							 | 
						|
								    cuddRef(T);
							 | 
						|
								    cuddRef(E);
							 | 
						|
								
							 | 
						|
								    return(looking);
							 | 
						|
								
							 | 
						|
								} /* end of cuddUniqueInterZdd */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Checks the unique table for the existence of a constant node.]
							 | 
						|
								
							 | 
						|
								  Description [Checks the unique table for the existence of a constant node.
							 | 
						|
								  If it does not exist, it creates a new one.  Does not
							 | 
						|
								  modify the reference count of whatever is returned.  A newly created
							 | 
						|
								  internal node comes back with a reference count 0.  Returns a
							 | 
						|
								  pointer to the new node.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DdNode *
							 | 
						|
								cuddUniqueConst(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  CUDD_VALUE_TYPE  value)
							 | 
						|
								{
							 | 
						|
								    int pos;
							 | 
						|
								    DdNodePtr *nodelist;
							 | 
						|
								    DdNode *looking;
							 | 
						|
								    hack split;
							 | 
						|
								
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
								    unique->uniqueLookUps++;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (unique->constants.keys > unique->constants.maxKeys) {
							 | 
						|
									if (unique->gcEnabled && ((unique->dead > unique->minDead) ||
							 | 
						|
									(10 * unique->constants.dead > 9 * unique->constants.keys))) {	/* too many dead */
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									} else {
							 | 
						|
									    cuddRehash(unique,CUDD_CONST_INDEX);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    cuddAdjust(value); /* for the case of crippled infinities */
							 | 
						|
								
							 | 
						|
								    if (ddAbs(value) < unique->epsilon) {
							 | 
						|
									value = 0.0;
							 | 
						|
								    }
							 | 
						|
								    split.value = value;
							 | 
						|
								
							 | 
						|
								    pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift);
							 | 
						|
								    nodelist = unique->constants.nodelist;
							 | 
						|
								    looking = nodelist[pos];
							 | 
						|
								
							 | 
						|
								    /* Here we compare values both for equality and for difference less
							 | 
						|
								     * than epsilon. The first comparison is required when values are
							 | 
						|
								     * infinite, since Infinity - Infinity is NaN and NaN < X is 0 for
							 | 
						|
								     * every X.
							 | 
						|
								     */
							 | 
						|
								    while (looking != NULL) {
							 | 
						|
									if (looking->type.value == value ||
							 | 
						|
									ddEqualVal(looking->type.value,value,unique->epsilon)) {
							 | 
						|
									    if (looking->ref == 0) {
							 | 
						|
										cuddReclaim(unique,looking);
							 | 
						|
									    }
							 | 
						|
									    return(looking);
							 | 
						|
									}
							 | 
						|
									looking = looking->next;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
									unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    unique->keys++;
							 | 
						|
								    unique->constants.keys++;
							 | 
						|
								
							 | 
						|
								    looking = cuddAllocNode(unique);
							 | 
						|
								    if (looking == NULL) return(NULL);
							 | 
						|
								    looking->index = CUDD_CONST_INDEX;
							 | 
						|
								    looking->type.value = value;
							 | 
						|
								    looking->next = nodelist[pos];
							 | 
						|
								    nodelist[pos] = looking;
							 | 
						|
								
							 | 
						|
								    return(looking);
							 | 
						|
								
							 | 
						|
								} /* end of cuddUniqueConst */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Rehashes a unique subtable.]
							 | 
						|
								
							 | 
						|
								  Description [Doubles the size of a unique subtable and rehashes its
							 | 
						|
								  contents.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								void
							 | 
						|
								cuddRehash(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int i)
							 | 
						|
								{
							 | 
						|
								    unsigned int slots, oldslots;
							 | 
						|
								    int shift, oldshift;
							 | 
						|
								    int j, pos;
							 | 
						|
								    DdNodePtr *nodelist, *oldnodelist;
							 | 
						|
								    DdNode *node, *next;
							 | 
						|
								    DdNode *sentinel = &(unique->sentinel);
							 | 
						|
								    hack split;
							 | 
						|
								    extern DD_OOMFP MMoutOfMemory;
							 | 
						|
								    DD_OOMFP saveHandler;
							 | 
						|
								
							 | 
						|
								    if (unique->gcFrac == DD_GC_FRAC_HI && unique->slots > unique->looseUpTo) {
							 | 
						|
									unique->gcFrac = DD_GC_FRAC_LO;
							 | 
						|
									unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_LO);
							 | 
						|
									(void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (unique->gcFrac != DD_GC_FRAC_MIN && unique->memused > unique->maxmem) {
							 | 
						|
									unique->gcFrac = DD_GC_FRAC_MIN;
							 | 
						|
									unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,"GC fraction = %.2f\t", DD_GC_FRAC_MIN);
							 | 
						|
									(void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
							 | 
						|
								#endif
							 | 
						|
									cuddShrinkDeathRow(unique);
							 | 
						|
									if (cuddGarbageCollect(unique,1) > 0) return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (i != CUDD_CONST_INDEX) {
							 | 
						|
									oldslots = unique->subtables[i].slots;
							 | 
						|
									oldshift = unique->subtables[i].shift;
							 | 
						|
									oldnodelist = unique->subtables[i].nodelist;
							 | 
						|
								
							 | 
						|
									/* Compute the new size of the subtable. */
							 | 
						|
									slots = oldslots << 1;
							 | 
						|
									shift = oldshift - 1;
							 | 
						|
								
							 | 
						|
									saveHandler = MMoutOfMemory;
							 | 
						|
									MMoutOfMemory = Cudd_OutOfMem;
							 | 
						|
									nodelist = ALLOC(DdNodePtr, slots);
							 | 
						|
									MMoutOfMemory = saveHandler;
							 | 
						|
									if (nodelist == NULL) {
							 | 
						|
									    (void) fprintf(unique->err,
							 | 
						|
											   "Unable to resize subtable %d for lack of memory\n",
							 | 
						|
											   i);
							 | 
						|
									    /* Prevent frequent resizing attempts. */
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									    if (unique->stash != NULL) {
							 | 
						|
										FREE(unique->stash);
							 | 
						|
										unique->stash = NULL;
							 | 
						|
										/* Inhibit resizing of tables. */
							 | 
						|
										cuddSlowTableGrowth(unique);
							 | 
						|
									    }
							 | 
						|
									    return;
							 | 
						|
									}
							 | 
						|
									unique->subtables[i].nodelist = nodelist;
							 | 
						|
									unique->subtables[i].slots = slots;
							 | 
						|
									unique->subtables[i].shift = shift;
							 | 
						|
									unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
								
							 | 
						|
									/* Move the nodes from the old table to the new table.
							 | 
						|
									** This code depends on the type of hash function.
							 | 
						|
									** It assumes that the effect of doubling the size of the table
							 | 
						|
									** is to retain one more bit of the 32-bit hash value.
							 | 
						|
									** The additional bit is the LSB. */
							 | 
						|
									for (j = 0; (unsigned) j < oldslots; j++) {
							 | 
						|
									    DdNodePtr *evenP, *oddP;
							 | 
						|
									    node = oldnodelist[j];
							 | 
						|
									    evenP = &(nodelist[j<<1]);
							 | 
						|
									    oddP = &(nodelist[(j<<1)+1]);
							 | 
						|
									    while (node != sentinel) {
							 | 
						|
										next = node->next;
							 | 
						|
										pos = ddHash(cuddT(node), cuddE(node), shift);
							 | 
						|
										if (pos & 1) {
							 | 
						|
										    *oddP = node;
							 | 
						|
										    oddP = &(node->next);
							 | 
						|
										} else {
							 | 
						|
										    *evenP = node;
							 | 
						|
										    evenP = &(node->next);
							 | 
						|
										}
							 | 
						|
										node = next;
							 | 
						|
									    }
							 | 
						|
									    *evenP = *oddP = sentinel;
							 | 
						|
									}
							 | 
						|
									FREE(oldnodelist);
							 | 
						|
								
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "rehashing layer %d: keys %d dead %d new size %d\n",
							 | 
						|
										       i, unique->subtables[i].keys,
							 | 
						|
										       unique->subtables[i].dead, slots);
							 | 
						|
								#endif
							 | 
						|
								    } else {
							 | 
						|
									oldslots = unique->constants.slots;
							 | 
						|
									oldshift = unique->constants.shift;
							 | 
						|
									oldnodelist = unique->constants.nodelist;
							 | 
						|
								
							 | 
						|
									/* The constant subtable is never subjected to reordering.
							 | 
						|
									** Therefore, when it is resized, it is because it has just
							 | 
						|
									** reached the maximum load. We can safely just double the size,
							 | 
						|
									** with no need for the loop we use for the other tables.
							 | 
						|
									*/
							 | 
						|
									slots = oldslots << 1;
							 | 
						|
									shift = oldshift - 1;
							 | 
						|
									saveHandler = MMoutOfMemory;
							 | 
						|
									MMoutOfMemory = Cudd_OutOfMem;
							 | 
						|
									nodelist = ALLOC(DdNodePtr, slots);
							 | 
						|
									MMoutOfMemory = saveHandler;
							 | 
						|
									if (nodelist == NULL) {
							 | 
						|
									    (void) fprintf(unique->err,
							 | 
						|
											   "Unable to resize constant subtable for lack of memory\n");
							 | 
						|
									    (void) cuddGarbageCollect(unique,1);
							 | 
						|
									    for (j = 0; j < unique->size; j++) {
							 | 
						|
										unique->subtables[j].maxKeys <<= 1;
							 | 
						|
									    }
							 | 
						|
									    unique->constants.maxKeys <<= 1;
							 | 
						|
									    return;
							 | 
						|
									}
							 | 
						|
									unique->constants.slots = slots;
							 | 
						|
									unique->constants.shift = shift;
							 | 
						|
									unique->constants.maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									unique->constants.nodelist = nodelist;
							 | 
						|
									for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									    nodelist[j] = NULL;
							 | 
						|
									}
							 | 
						|
									for (j = 0; (unsigned) j < oldslots; j++) {
							 | 
						|
									    node = oldnodelist[j];
							 | 
						|
									    while (node != NULL) {
							 | 
						|
										next = node->next;
							 | 
						|
										split.value = cuddV(node);
							 | 
						|
										pos = ddHash(split.bits[0], split.bits[1], shift);
							 | 
						|
										node->next = nodelist[pos];
							 | 
						|
										nodelist[pos] = node;
							 | 
						|
										node = next;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									FREE(oldnodelist);
							 | 
						|
								
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "rehashing constants: keys %d dead %d new size %d\n",
							 | 
						|
										       unique->constants.keys,unique->constants.dead,slots);
							 | 
						|
								#endif
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Update global data */
							 | 
						|
								
							 | 
						|
								    unique->memused += (slots - oldslots) * sizeof(DdNodePtr);
							 | 
						|
								    unique->slots += (slots - oldslots);
							 | 
						|
								    ddFixLimits(unique);
							 | 
						|
								
							 | 
						|
								} /* end of cuddRehash */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Shrinks a subtable.]
							 | 
						|
								
							 | 
						|
								  Description [Shrinks a subtable.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddRehash]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								void
							 | 
						|
								cuddShrinkSubtable(
							 | 
						|
								  DdManager *unique,
							 | 
						|
								  int i)
							 | 
						|
								{
							 | 
						|
								    int j;
							 | 
						|
								    int shift, posn;
							 | 
						|
								    DdNodePtr *nodelist, *oldnodelist;
							 | 
						|
								    DdNode *node, *next;
							 | 
						|
								    DdNode *sentinel = &(unique->sentinel);
							 | 
						|
								    unsigned int slots, oldslots;
							 | 
						|
								    extern DD_OOMFP MMoutOfMemory;
							 | 
						|
								    DD_OOMFP saveHandler;
							 | 
						|
								
							 | 
						|
								    oldnodelist = unique->subtables[i].nodelist;
							 | 
						|
								    oldslots = unique->subtables[i].slots;
							 | 
						|
								    slots = oldslots >> 1;
							 | 
						|
								    saveHandler = MMoutOfMemory;
							 | 
						|
								    MMoutOfMemory = Cudd_OutOfMem;
							 | 
						|
								    nodelist = ALLOC(DdNodePtr, slots);
							 | 
						|
								    MMoutOfMemory = saveHandler;
							 | 
						|
								    if (nodelist == NULL) {
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    unique->subtables[i].nodelist = nodelist;
							 | 
						|
								    unique->subtables[i].slots = slots;
							 | 
						|
								    unique->subtables[i].shift++;
							 | 
						|
								    unique->subtables[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
								    (void) fprintf(unique->err,
							 | 
						|
										   "shrunk layer %d (%d keys) from %d to %d slots\n",
							 | 
						|
										   i, unique->subtables[i].keys, oldslots, slots);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									nodelist[j] = sentinel;
							 | 
						|
								    }
							 | 
						|
								    shift = unique->subtables[i].shift;
							 | 
						|
								    for (j = 0; (unsigned) j < oldslots; j++) {
							 | 
						|
									node = oldnodelist[j];
							 | 
						|
									while (node != sentinel) {
							 | 
						|
									    DdNode *looking, *T, *E;
							 | 
						|
									    DdNodePtr *previousP;
							 | 
						|
									    next = node->next;
							 | 
						|
									    posn = ddHash(cuddT(node), cuddE(node), shift);
							 | 
						|
									    previousP = &(nodelist[posn]);
							 | 
						|
									    looking = *previousP;
							 | 
						|
									    T = cuddT(node);
							 | 
						|
									    E = cuddE(node);
							 | 
						|
									    while (T < cuddT(looking)) {
							 | 
						|
										previousP = &(looking->next);
							 | 
						|
										looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
										unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									    }
							 | 
						|
									    while (T == cuddT(looking) && E < cuddE(looking)) {
							 | 
						|
										previousP = &(looking->next);
							 | 
						|
										looking = *previousP;
							 | 
						|
								#ifdef DD_UNIQUE_PROFILE
							 | 
						|
										unique->uniqueLinks++;
							 | 
						|
								#endif
							 | 
						|
									    }
							 | 
						|
									    node->next = *previousP;
							 | 
						|
									    *previousP = node;
							 | 
						|
									    node = next;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    FREE(oldnodelist);
							 | 
						|
								
							 | 
						|
								    unique->memused += ((long) slots - (long) oldslots) * sizeof(DdNode *);
							 | 
						|
								    unique->slots += slots - oldslots;
							 | 
						|
								    unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
							 | 
						|
								    unique->cacheSlack = (int)
							 | 
						|
									ddMin(unique->maxCacheHard,DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots)
							 | 
						|
									- 2 * (int) unique->cacheSlots;
							 | 
						|
								
							 | 
						|
								} /* end of cuddShrinkSubtable */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Inserts n new subtables in a unique table at level.]
							 | 
						|
								
							 | 
						|
								  Description [Inserts n new subtables in a unique table at level.
							 | 
						|
								  The number n should be positive, and level should be an existing level.
							 | 
						|
								  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddDestroySubtables]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								cuddInsertSubtables(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  n,
							 | 
						|
								  int  level)
							 | 
						|
								{
							 | 
						|
								    DdSubtable *newsubtables;
							 | 
						|
								    DdNodePtr *newnodelist;
							 | 
						|
								    DdNodePtr *newvars;
							 | 
						|
								    DdNode *sentinel = &(unique->sentinel);
							 | 
						|
								    int oldsize,newsize;
							 | 
						|
								    int i,j,index,reorderSave;
							 | 
						|
								    unsigned int numSlots = unique->initSlots;
							 | 
						|
								    int *newperm, *newinvperm, *newmap;
							 | 
						|
								    DdNode *one, *zero;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    assert(n > 0 && level < unique->size);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    oldsize = unique->size;
							 | 
						|
								    /* Easy case: there is still room in the current table. */
							 | 
						|
								    if (oldsize + n <= unique->maxSize) {
							 | 
						|
									/* Shift the tables at and below level. */
							 | 
						|
									for (i = oldsize - 1; i >= level; i--) {
							 | 
						|
									    unique->subtables[i+n].slots    = unique->subtables[i].slots;
							 | 
						|
									    unique->subtables[i+n].shift    = unique->subtables[i].shift;
							 | 
						|
									    unique->subtables[i+n].keys     = unique->subtables[i].keys;
							 | 
						|
									    unique->subtables[i+n].maxKeys  = unique->subtables[i].maxKeys;
							 | 
						|
									    unique->subtables[i+n].dead     = unique->subtables[i].dead;
							 | 
						|
									    unique->subtables[i+n].nodelist = unique->subtables[i].nodelist;
							 | 
						|
									    unique->subtables[i+n].bindVar  = unique->subtables[i].bindVar;
							 | 
						|
									    unique->subtables[i+n].varType  = unique->subtables[i].varType;
							 | 
						|
									    unique->subtables[i+n].pairIndex  = unique->subtables[i].pairIndex;
							 | 
						|
									    unique->subtables[i+n].varHandled = unique->subtables[i].varHandled;
							 | 
						|
									    unique->subtables[i+n].varToBeGrouped =
							 | 
						|
										unique->subtables[i].varToBeGrouped;
							 | 
						|
								
							 | 
						|
									    index                           = unique->invperm[i];
							 | 
						|
									    unique->invperm[i+n]            = index;
							 | 
						|
									    unique->perm[index]            += n;
							 | 
						|
									}
							 | 
						|
									/* Create new subtables. */
							 | 
						|
									for (i = 0; i < n; i++) {
							 | 
						|
									    unique->subtables[level+i].slots = numSlots;
							 | 
						|
									    unique->subtables[level+i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    unique->subtables[level+i].keys = 0;
							 | 
						|
									    unique->subtables[level+i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    unique->subtables[level+i].dead = 0;
							 | 
						|
									    unique->subtables[level+i].bindVar = 0;
							 | 
						|
									    unique->subtables[level+i].varType = CUDD_VAR_PRIMARY_INPUT;
							 | 
						|
									    unique->subtables[level+i].pairIndex = 0;
							 | 
						|
									    unique->subtables[level+i].varHandled = 0;
							 | 
						|
									    unique->subtables[level+i].varToBeGrouped = CUDD_LAZY_NONE;
							 | 
						|
								
							 | 
						|
									    unique->perm[oldsize+i] = level + i;
							 | 
						|
									    unique->invperm[level+i] = oldsize + i;
							 | 
						|
									    newnodelist = unique->subtables[level+i].nodelist =
							 | 
						|
										ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; (unsigned) j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = sentinel;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    for (i = 0; i < n; i++) {
							 | 
						|
										unique->map[oldsize+i] = oldsize + i;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									/* The current table is too small: we need to allocate a new,
							 | 
						|
									** larger one; move all old subtables, and initialize the new
							 | 
						|
									** subtables.
							 | 
						|
									*/
							 | 
						|
									newsize = oldsize + n + DD_DEFAULT_RESIZE;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "Increasing the table size from %d to %d\n",
							 | 
						|
									    unique->maxSize, newsize);
							 | 
						|
								#endif
							 | 
						|
									/* Allocate memory for new arrays (except nodelists). */
							 | 
						|
									newsubtables = ALLOC(DdSubtable,newsize);
							 | 
						|
									if (newsubtables == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newvars = ALLOC(DdNodePtr,newsize);
							 | 
						|
									if (newvars == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newperm = ALLOC(int,newsize);
							 | 
						|
									if (newperm == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    FREE(newvars);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newinvperm = ALLOC(int,newsize);
							 | 
						|
									if (newinvperm == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    FREE(newvars);
							 | 
						|
									    FREE(newperm);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    newmap = ALLOC(int,newsize);
							 | 
						|
									    if (newmap == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										FREE(newsubtables);
							 | 
						|
										FREE(newvars);
							 | 
						|
										FREE(newperm);
							 | 
						|
										FREE(newinvperm);
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    unique->memused += (newsize - unique->maxSize) * sizeof(int);
							 | 
						|
									}
							 | 
						|
									unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
							 | 
						|
									    sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
							 | 
						|
									/* Copy levels before insertion points from old tables. */
							 | 
						|
									for (i = 0; i < level; i++) {
							 | 
						|
									    newsubtables[i].slots = unique->subtables[i].slots;
							 | 
						|
									    newsubtables[i].shift = unique->subtables[i].shift;
							 | 
						|
									    newsubtables[i].keys = unique->subtables[i].keys;
							 | 
						|
									    newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
							 | 
						|
									    newsubtables[i].dead = unique->subtables[i].dead;
							 | 
						|
									    newsubtables[i].nodelist = unique->subtables[i].nodelist;
							 | 
						|
									    newsubtables[i].bindVar = unique->subtables[i].bindVar;
							 | 
						|
									    newsubtables[i].varType = unique->subtables[i].varType;
							 | 
						|
									    newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
							 | 
						|
									    newsubtables[i].varHandled = unique->subtables[i].varHandled;
							 | 
						|
									    newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
							 | 
						|
								
							 | 
						|
									    newvars[i] = unique->vars[i];
							 | 
						|
									    newperm[i] = unique->perm[i];
							 | 
						|
									    newinvperm[i] = unique->invperm[i];
							 | 
						|
									}
							 | 
						|
									/* Finish initializing permutation for new table to old one. */
							 | 
						|
									for (i = level; i < oldsize; i++) {
							 | 
						|
									    newperm[i] = unique->perm[i];
							 | 
						|
									}
							 | 
						|
									/* Initialize new levels. */
							 | 
						|
									for (i = level; i < level + n; i++) {
							 | 
						|
									    newsubtables[i].slots = numSlots;
							 | 
						|
									    newsubtables[i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    newsubtables[i].keys = 0;
							 | 
						|
									    newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    newsubtables[i].dead = 0;
							 | 
						|
									    newsubtables[i].bindVar = 0;
							 | 
						|
									    newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
							 | 
						|
									    newsubtables[i].pairIndex = 0;
							 | 
						|
									    newsubtables[i].varHandled = 0;
							 | 
						|
									    newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
							 | 
						|
								
							 | 
						|
									    newperm[oldsize + i - level] = i;
							 | 
						|
									    newinvperm[i] = oldsize + i - level;
							 | 
						|
									    newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										/* We are going to leak some memory.  We should clean up. */
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; (unsigned) j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = sentinel;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									/* Copy the old tables for levels past the insertion point. */
							 | 
						|
									for (i = level; i < oldsize; i++) {
							 | 
						|
									    newsubtables[i+n].slots    = unique->subtables[i].slots;
							 | 
						|
									    newsubtables[i+n].shift    = unique->subtables[i].shift;
							 | 
						|
									    newsubtables[i+n].keys     = unique->subtables[i].keys;
							 | 
						|
									    newsubtables[i+n].maxKeys  = unique->subtables[i].maxKeys;
							 | 
						|
									    newsubtables[i+n].dead     = unique->subtables[i].dead;
							 | 
						|
									    newsubtables[i+n].nodelist = unique->subtables[i].nodelist;
							 | 
						|
									    newsubtables[i+n].bindVar  = unique->subtables[i].bindVar;
							 | 
						|
									    newsubtables[i+n].varType  = unique->subtables[i].varType;
							 | 
						|
									    newsubtables[i+n].pairIndex  = unique->subtables[i].pairIndex;
							 | 
						|
									    newsubtables[i+n].varHandled  = unique->subtables[i].varHandled;
							 | 
						|
									    newsubtables[i+n].varToBeGrouped  =
							 | 
						|
										unique->subtables[i].varToBeGrouped;
							 | 
						|
								
							 | 
						|
									    newvars[i]                 = unique->vars[i];
							 | 
						|
									    index                      = unique->invperm[i];
							 | 
						|
									    newinvperm[i+n]            = index;
							 | 
						|
									    newperm[index]            += n;
							 | 
						|
									}
							 | 
						|
									/* Update the map. */
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    for (i = 0; i < oldsize; i++) {
							 | 
						|
										newmap[i] = unique->map[i];
							 | 
						|
									    }
							 | 
						|
									    for (i = oldsize; i < oldsize + n; i++) {
							 | 
						|
										newmap[i] = i;
							 | 
						|
									    }
							 | 
						|
									    FREE(unique->map);
							 | 
						|
									    unique->map = newmap;
							 | 
						|
									}
							 | 
						|
									/* Install the new tables and free the old ones. */
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									unique->subtables = newsubtables;
							 | 
						|
									unique->maxSize = newsize;
							 | 
						|
									FREE(unique->vars);
							 | 
						|
									unique->vars = newvars;
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									unique->perm = newperm;
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									unique->invperm = newinvperm;
							 | 
						|
									/* Update the stack for iterative procedures. */
							 | 
						|
									if (newsize > unique->maxSizeZ) {
							 | 
						|
									    FREE(unique->stack);
							 | 
						|
									    unique->stack = ALLOC(DdNodePtr,newsize + 1);
							 | 
						|
									    if (unique->stack == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    unique->stack[0] = NULL; /* to suppress harmless UMR */
							 | 
						|
									    unique->memused +=
							 | 
						|
										(newsize - ddMax(unique->maxSize,unique->maxSizeZ))
							 | 
						|
										* sizeof(DdNode *);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    /* Update manager parameters to account for the new subtables. */
							 | 
						|
								    unique->slots += n * numSlots;
							 | 
						|
								    ddFixLimits(unique);
							 | 
						|
								    unique->size += n;
							 | 
						|
								
							 | 
						|
								    /* Now that the table is in a coherent state, create the new
							 | 
						|
								    ** projection functions. We need to temporarily disable reordering,
							 | 
						|
								    ** because we cannot reorder without projection functions in place.
							 | 
						|
								    **/
							 | 
						|
								    one = unique->one;
							 | 
						|
								    zero = Cudd_Not(one);
							 | 
						|
								
							 | 
						|
								    reorderSave = unique->autoDyn;
							 | 
						|
								    unique->autoDyn = 0;
							 | 
						|
								    for (i = oldsize; i < oldsize + n; i++) {
							 | 
						|
									unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
							 | 
						|
									if (unique->vars[i] == NULL) {
							 | 
						|
									    unique->autoDyn = reorderSave;
							 | 
						|
									    /* Shift everything back so table remains coherent. */
							 | 
						|
									    for (j = oldsize; j < i; j++) {
							 | 
						|
										Cudd_IterDerefBdd(unique,unique->vars[j]);
							 | 
						|
										cuddDeallocNode(unique,unique->vars[j]);
							 | 
						|
										unique->vars[j] = NULL;
							 | 
						|
									    }
							 | 
						|
									    for (j = level; j < oldsize; j++) {
							 | 
						|
										unique->subtables[j].slots    = unique->subtables[j+n].slots;
							 | 
						|
										unique->subtables[j].slots    = unique->subtables[j+n].slots;
							 | 
						|
										unique->subtables[j].shift    = unique->subtables[j+n].shift;
							 | 
						|
										unique->subtables[j].keys     = unique->subtables[j+n].keys;
							 | 
						|
										unique->subtables[j].maxKeys  =
							 | 
						|
										    unique->subtables[j+n].maxKeys;
							 | 
						|
										unique->subtables[j].dead     = unique->subtables[j+n].dead;
							 | 
						|
										FREE(unique->subtables[j].nodelist);
							 | 
						|
										unique->subtables[j].nodelist =
							 | 
						|
										    unique->subtables[j+n].nodelist;
							 | 
						|
										unique->subtables[j+n].nodelist = NULL;
							 | 
						|
										unique->subtables[j].bindVar  =
							 | 
						|
										    unique->subtables[j+n].bindVar;
							 | 
						|
										unique->subtables[j].varType  =
							 | 
						|
										    unique->subtables[j+n].varType;
							 | 
						|
										unique->subtables[j].pairIndex =
							 | 
						|
										    unique->subtables[j+n].pairIndex;
							 | 
						|
										unique->subtables[j].varHandled =
							 | 
						|
										    unique->subtables[j+n].varHandled;
							 | 
						|
										unique->subtables[j].varToBeGrouped =
							 | 
						|
										    unique->subtables[j+n].varToBeGrouped;
							 | 
						|
										index                         = unique->invperm[j+n];
							 | 
						|
										unique->invperm[j]            = index;
							 | 
						|
										unique->perm[index]          -= n;
							 | 
						|
									    }
							 | 
						|
									    unique->size = oldsize;
							 | 
						|
									    unique->slots -= n * numSlots;
							 | 
						|
									    ddFixLimits(unique);
							 | 
						|
									    (void) Cudd_DebugCheck(unique);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									cuddRef(unique->vars[i]);
							 | 
						|
								    }
							 | 
						|
								    if (unique->tree != NULL) {
							 | 
						|
									unique->tree->size += n;
							 | 
						|
									unique->tree->index = unique->invperm[0];
							 | 
						|
									ddPatchTree(unique,unique->tree);
							 | 
						|
								    }
							 | 
						|
								    unique->autoDyn = reorderSave;
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of cuddInsertSubtables */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Destroys the n most recently created subtables in a unique table.]
							 | 
						|
								
							 | 
						|
								  Description [Destroys the n most recently created subtables in a unique
							 | 
						|
								  table.  n should be positive. The subtables should not contain any live
							 | 
						|
								  nodes, except the (isolated) projection function. The projection
							 | 
						|
								  functions are freed.  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [The variable map used for fast variable substitution is
							 | 
						|
								  destroyed if it exists. In this case the cache is also cleared.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddInsertSubtables Cudd_SetVarMap]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								cuddDestroySubtables(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  n)
							 | 
						|
								{
							 | 
						|
								    DdSubtable *subtables;
							 | 
						|
								    DdNodePtr *nodelist;
							 | 
						|
								    DdNodePtr *vars;
							 | 
						|
								    int firstIndex, lastIndex;
							 | 
						|
								    int index, level, newlevel;
							 | 
						|
								    int lowestLevel;
							 | 
						|
								    int shift;
							 | 
						|
								    int found;
							 | 
						|
								
							 | 
						|
								    /* Sanity check and set up. */
							 | 
						|
								    if (n <= 0) return(0);
							 | 
						|
								    if (n > unique->size) n = unique->size;
							 | 
						|
								
							 | 
						|
								    subtables = unique->subtables;
							 | 
						|
								    vars = unique->vars;
							 | 
						|
								    firstIndex = unique->size - n;
							 | 
						|
								    lastIndex  = unique->size;
							 | 
						|
								
							 | 
						|
								    /* Check for nodes labeled by the variables being destroyed
							 | 
						|
								    ** that may still be in use.  It is allowed to destroy a variable
							 | 
						|
								    ** only if there are no such nodes. Also, find the lowest level
							 | 
						|
								    ** among the variables being destroyed. This will make further
							 | 
						|
								    ** processing more efficient.
							 | 
						|
								    */
							 | 
						|
								    lowestLevel = unique->size;
							 | 
						|
								    for (index = firstIndex; index < lastIndex; index++) {
							 | 
						|
									level = unique->perm[index];
							 | 
						|
									if (level < lowestLevel) lowestLevel = level;
							 | 
						|
									nodelist = subtables[level].nodelist;
							 | 
						|
									if (subtables[level].keys - subtables[level].dead != 1) return(0);
							 | 
						|
									/* The projection function should be isolated. If the ref count
							 | 
						|
									** is 1, everything is OK. If the ref count is saturated, then
							 | 
						|
									** we need to make sure that there are no nodes pointing to it.
							 | 
						|
									** As for the external references, we assume the application is
							 | 
						|
									** responsible for them.
							 | 
						|
									*/
							 | 
						|
									if (vars[index]->ref != 1) {
							 | 
						|
									    if (vars[index]->ref != DD_MAXREF) return(0);
							 | 
						|
									    found = cuddFindParent(unique,vars[index]);
							 | 
						|
									    if (found) {
							 | 
						|
										return(0);
							 | 
						|
									    } else {
							 | 
						|
										vars[index]->ref = 1;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									Cudd_RecursiveDeref(unique,vars[index]);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Collect garbage, because we cannot afford having dead nodes pointing
							 | 
						|
								    ** to the dead nodes in the subtables being destroyed.
							 | 
						|
								    */
							 | 
						|
								    (void) cuddGarbageCollect(unique,1);
							 | 
						|
								
							 | 
						|
								    /* Here we know we can destroy our subtables. */
							 | 
						|
								    for (index = firstIndex; index < lastIndex; index++) {
							 | 
						|
									level = unique->perm[index];
							 | 
						|
									nodelist = subtables[level].nodelist;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(subtables[level].keys == 0);
							 | 
						|
								#endif
							 | 
						|
									FREE(nodelist);
							 | 
						|
									unique->memused -= sizeof(DdNodePtr) * subtables[level].slots;
							 | 
						|
									unique->slots -= subtables[level].slots;
							 | 
						|
									unique->dead -= subtables[level].dead;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Here all subtables to be destroyed have their keys field == 0 and
							 | 
						|
								    ** their hash tables have been freed.
							 | 
						|
								    ** We now scan the subtables from level lowestLevel + 1 to level size - 1,
							 | 
						|
								    ** shifting the subtables as required. We keep a running count of
							 | 
						|
								    ** how many subtables have been moved, so that we know by how many
							 | 
						|
								    ** positions each subtable should be shifted.
							 | 
						|
								    */
							 | 
						|
								    shift = 1;
							 | 
						|
								    for (level = lowestLevel + 1; level < unique->size; level++) {
							 | 
						|
									if (subtables[level].keys == 0) {
							 | 
						|
									    shift++;
							 | 
						|
									    continue;
							 | 
						|
									}
							 | 
						|
									newlevel = level - shift;
							 | 
						|
									subtables[newlevel].slots = subtables[level].slots;
							 | 
						|
									subtables[newlevel].shift = subtables[level].shift;
							 | 
						|
									subtables[newlevel].keys = subtables[level].keys;
							 | 
						|
									subtables[newlevel].maxKeys = subtables[level].maxKeys;
							 | 
						|
									subtables[newlevel].dead = subtables[level].dead;
							 | 
						|
									subtables[newlevel].nodelist = subtables[level].nodelist;
							 | 
						|
									index = unique->invperm[level];
							 | 
						|
									unique->perm[index] = newlevel;
							 | 
						|
									unique->invperm[newlevel]  = index;
							 | 
						|
									subtables[newlevel].bindVar = subtables[level].bindVar;
							 | 
						|
									subtables[newlevel].varType = subtables[level].varType;
							 | 
						|
									subtables[newlevel].pairIndex = subtables[level].pairIndex;
							 | 
						|
									subtables[newlevel].varHandled = subtables[level].varHandled;
							 | 
						|
									subtables[newlevel].varToBeGrouped = subtables[level].varToBeGrouped;
							 | 
						|
								    }
							 | 
						|
								    /* Destroy the map. If a surviving variable is
							 | 
						|
								    ** mapped to a dying variable, and the map were used again,
							 | 
						|
								    ** an out-of-bounds access to unique->vars would result. */
							 | 
						|
								    if (unique->map != NULL) {
							 | 
						|
									cuddCacheFlush(unique);
							 | 
						|
									FREE(unique->map);
							 | 
						|
									unique->map = NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
							 | 
						|
								    unique->size -= n;
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of cuddDestroySubtables */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Increases the number of ZDD subtables in a unique table so
							 | 
						|
								  that it meets or exceeds index.]
							 | 
						|
								
							 | 
						|
								  Description [Increases the number of ZDD subtables in a unique table so
							 | 
						|
								  that it meets or exceeds index.  When new ZDD variables are created, it
							 | 
						|
								  is possible to preserve the functions unchanged, or it is possible to
							 | 
						|
								  preserve the covers unchanged, but not both. cuddResizeTableZdd preserves
							 | 
						|
								  the covers.  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [ddResizeTable]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								cuddResizeTableZdd(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  index)
							 | 
						|
								{
							 | 
						|
								    DdSubtable *newsubtables;
							 | 
						|
								    DdNodePtr *newnodelist;
							 | 
						|
								    int oldsize,newsize;
							 | 
						|
								    int i,j,reorderSave;
							 | 
						|
								    unsigned int numSlots = unique->initSlots;
							 | 
						|
								    int *newperm, *newinvperm;
							 | 
						|
								
							 | 
						|
								    oldsize = unique->sizeZ;
							 | 
						|
								    /* Easy case: there is still room in the current table. */
							 | 
						|
								    if (index < unique->maxSizeZ) {
							 | 
						|
									for (i = oldsize; i <= index; i++) {
							 | 
						|
									    unique->subtableZ[i].slots = numSlots;
							 | 
						|
									    unique->subtableZ[i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    unique->subtableZ[i].keys = 0;
							 | 
						|
									    unique->subtableZ[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    unique->subtableZ[i].dead = 0;
							 | 
						|
									    unique->permZ[i] = i;
							 | 
						|
									    unique->invpermZ[i] = i;
							 | 
						|
									    newnodelist = unique->subtableZ[i].nodelist =
							 | 
						|
										ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; (unsigned) j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = NULL;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									/* The current table is too small: we need to allocate a new,
							 | 
						|
									** larger one; move all old subtables, and initialize the new
							 | 
						|
									** subtables up to index included.
							 | 
						|
									*/
							 | 
						|
									newsize = index + DD_DEFAULT_RESIZE;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "Increasing the ZDD table size from %d to %d\n",
							 | 
						|
									    unique->maxSizeZ, newsize);
							 | 
						|
								#endif
							 | 
						|
									newsubtables = ALLOC(DdSubtable,newsize);
							 | 
						|
									if (newsubtables == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newperm = ALLOC(int,newsize);
							 | 
						|
									if (newperm == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newinvperm = ALLOC(int,newsize);
							 | 
						|
									if (newinvperm == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									unique->memused += (newsize - unique->maxSizeZ) * ((numSlots+1) *
							 | 
						|
									    sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
							 | 
						|
									if (newsize > unique->maxSize) {
							 | 
						|
									    FREE(unique->stack);
							 | 
						|
									    unique->stack = ALLOC(DdNodePtr,newsize + 1);
							 | 
						|
									    if (unique->stack == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    unique->stack[0] = NULL; /* to suppress harmless UMR */
							 | 
						|
									    unique->memused +=
							 | 
						|
										(newsize - ddMax(unique->maxSize,unique->maxSizeZ))
							 | 
						|
										* sizeof(DdNode *);
							 | 
						|
									}
							 | 
						|
									for (i = 0; i < oldsize; i++) {
							 | 
						|
									    newsubtables[i].slots = unique->subtableZ[i].slots;
							 | 
						|
									    newsubtables[i].shift = unique->subtableZ[i].shift;
							 | 
						|
									    newsubtables[i].keys = unique->subtableZ[i].keys;
							 | 
						|
									    newsubtables[i].maxKeys = unique->subtableZ[i].maxKeys;
							 | 
						|
									    newsubtables[i].dead = unique->subtableZ[i].dead;
							 | 
						|
									    newsubtables[i].nodelist = unique->subtableZ[i].nodelist;
							 | 
						|
									    newperm[i] = unique->permZ[i];
							 | 
						|
									    newinvperm[i] = unique->invpermZ[i];
							 | 
						|
									}
							 | 
						|
									for (i = oldsize; i <= index; i++) {
							 | 
						|
									    newsubtables[i].slots = numSlots;
							 | 
						|
									    newsubtables[i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    newsubtables[i].keys = 0;
							 | 
						|
									    newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    newsubtables[i].dead = 0;
							 | 
						|
									    newperm[i] = i;
							 | 
						|
									    newinvperm[i] = i;
							 | 
						|
									    newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; (unsigned) j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = NULL;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									FREE(unique->subtableZ);
							 | 
						|
									unique->subtableZ = newsubtables;
							 | 
						|
									unique->maxSizeZ = newsize;
							 | 
						|
									FREE(unique->permZ);
							 | 
						|
									unique->permZ = newperm;
							 | 
						|
									FREE(unique->invpermZ);
							 | 
						|
									unique->invpermZ = newinvperm;
							 | 
						|
								    }
							 | 
						|
								    unique->slots += (index + 1 - unique->sizeZ) * numSlots;
							 | 
						|
								    ddFixLimits(unique);
							 | 
						|
								    unique->sizeZ = index + 1;
							 | 
						|
								
							 | 
						|
								    /* Now that the table is in a coherent state, update the ZDD
							 | 
						|
								    ** universe. We need to temporarily disable reordering,
							 | 
						|
								    ** because we cannot reorder without universe in place.
							 | 
						|
								    */
							 | 
						|
								
							 | 
						|
								    reorderSave = unique->autoDynZ;
							 | 
						|
								    unique->autoDynZ = 0;
							 | 
						|
								    cuddZddFreeUniv(unique);
							 | 
						|
								    if (!cuddZddInitUniv(unique)) {
							 | 
						|
									unique->autoDynZ = reorderSave;
							 | 
						|
									return(0);
							 | 
						|
								    }
							 | 
						|
								    unique->autoDynZ = reorderSave;
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of cuddResizeTableZdd */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Adjusts parameters of a table to slow down its growth.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								void
							 | 
						|
								cuddSlowTableGrowth(
							 | 
						|
								  DdManager *unique)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								
							 | 
						|
								    unique->maxCacheHard = unique->cacheSlots - 1;
							 | 
						|
								    unique->cacheSlack = - (int) (unique->cacheSlots + 1);
							 | 
						|
								    for (i = 0; i < unique->size; i++) {
							 | 
						|
									unique->subtables[i].maxKeys <<= 2;
							 | 
						|
								    }
							 | 
						|
								    unique->gcFrac = DD_GC_FRAC_MIN;
							 | 
						|
								    unique->minDead = (unsigned) (DD_GC_FRAC_MIN * (double) unique->slots);
							 | 
						|
								    cuddShrinkDeathRow(unique);
							 | 
						|
								    (void) fprintf(unique->err,"Slowing down table growth: ");
							 | 
						|
								    (void) fprintf(unique->err,"GC fraction = %.2f\t", unique->gcFrac);
							 | 
						|
								    (void) fprintf(unique->err,"minDead = %u\n", unique->minDead);
							 | 
						|
								
							 | 
						|
								} /* end of cuddSlowTableGrowth */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Rehashes a ZDD unique subtable.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddRehash]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ddRehashZdd(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int  i)
							 | 
						|
								{
							 | 
						|
								    unsigned int slots, oldslots;
							 | 
						|
								    int shift, oldshift;
							 | 
						|
								    int j, pos;
							 | 
						|
								    DdNodePtr *nodelist, *oldnodelist;
							 | 
						|
								    DdNode *node, *next;
							 | 
						|
								    extern DD_OOMFP MMoutOfMemory;
							 | 
						|
								    DD_OOMFP saveHandler;
							 | 
						|
								
							 | 
						|
								    if (unique->slots > unique->looseUpTo) {
							 | 
						|
									unique->minDead = (unsigned) (DD_GC_FRAC_LO * (double) unique->slots);
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									if (unique->gcFrac == DD_GC_FRAC_HI) {
							 | 
						|
									    (void) fprintf(unique->err,"GC fraction = %.2f\t",
							 | 
						|
											   DD_GC_FRAC_LO);
							 | 
						|
									    (void) fprintf(unique->err,"minDead = %d\n", unique->minDead);
							 | 
						|
									}
							 | 
						|
								#endif
							 | 
						|
									unique->gcFrac = DD_GC_FRAC_LO;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    assert(i != CUDD_MAXINDEX);
							 | 
						|
								    oldslots = unique->subtableZ[i].slots;
							 | 
						|
								    oldshift = unique->subtableZ[i].shift;
							 | 
						|
								    oldnodelist = unique->subtableZ[i].nodelist;
							 | 
						|
								
							 | 
						|
								    /* Compute the new size of the subtable. Normally, we just
							 | 
						|
								    ** double.  However, after reordering, a table may be severely
							 | 
						|
								    ** overloaded. Therefore, we iterate. */
							 | 
						|
								    slots = oldslots;
							 | 
						|
								    shift = oldshift;
							 | 
						|
								    do {
							 | 
						|
									slots <<= 1;
							 | 
						|
									shift--;
							 | 
						|
								    } while (slots * DD_MAX_SUBTABLE_DENSITY < unique->subtableZ[i].keys);
							 | 
						|
								
							 | 
						|
								    saveHandler = MMoutOfMemory;
							 | 
						|
								    MMoutOfMemory = Cudd_OutOfMem;
							 | 
						|
								    nodelist = ALLOC(DdNodePtr, slots);
							 | 
						|
								    MMoutOfMemory = saveHandler;
							 | 
						|
								    if (nodelist == NULL) {
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "Unable to resize ZDD subtable %d for lack of memory.\n",
							 | 
						|
										       i);
							 | 
						|
									(void) cuddGarbageCollect(unique,1);
							 | 
						|
									for (j = 0; j < unique->sizeZ; j++) {
							 | 
						|
									    unique->subtableZ[j].maxKeys <<= 1;
							 | 
						|
									}
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								    unique->subtableZ[i].nodelist = nodelist;
							 | 
						|
								    unique->subtableZ[i].slots = slots;
							 | 
						|
								    unique->subtableZ[i].shift = shift;
							 | 
						|
								    unique->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
								    for (j = 0; (unsigned) j < slots; j++) {
							 | 
						|
									nodelist[j] = NULL;
							 | 
						|
								    }
							 | 
						|
								    for (j = 0; (unsigned) j < oldslots; j++) {
							 | 
						|
									node = oldnodelist[j];
							 | 
						|
									while (node != NULL) {
							 | 
						|
									    next = node->next;
							 | 
						|
									    pos = ddHash(cuddT(node), cuddE(node), shift);
							 | 
						|
									    node->next = nodelist[pos];
							 | 
						|
									    nodelist[pos] = node;
							 | 
						|
									    node = next;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    FREE(oldnodelist);
							 | 
						|
								
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
								    (void) fprintf(unique->err,
							 | 
						|
										   "rehashing layer %d: keys %d dead %d new size %d\n",
							 | 
						|
										   i, unique->subtableZ[i].keys,
							 | 
						|
										   unique->subtableZ[i].dead, slots);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Update global data. */
							 | 
						|
								    unique->memused += (slots - oldslots) * sizeof(DdNode *);
							 | 
						|
								    unique->slots += (slots - oldslots);
							 | 
						|
								    ddFixLimits(unique);
							 | 
						|
								
							 | 
						|
								} /* end of ddRehashZdd */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis [Increases the number of subtables in a unique table so
							 | 
						|
								  that it meets or exceeds index.]
							 | 
						|
								
							 | 
						|
								  Description [Increases the number of subtables in a unique table so
							 | 
						|
								  that it meets or exceeds index.  The parameter amount determines how
							 | 
						|
								  much spare space is allocated to prevent too frequent resizing.  If
							 | 
						|
								  index is negative, the table is resized, but no new variables are
							 | 
						|
								  created.  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_Reserve cuddResizeTableZdd]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								ddResizeTable(
							 | 
						|
								  DdManager * unique,
							 | 
						|
								  int index,
							 | 
						|
								  int amount)
							 | 
						|
								{
							 | 
						|
								    DdSubtable *newsubtables;
							 | 
						|
								    DdNodePtr *newnodelist;
							 | 
						|
								    DdNodePtr *newvars;
							 | 
						|
								    DdNode *sentinel = &(unique->sentinel);
							 | 
						|
								    int oldsize,newsize;
							 | 
						|
								    int i,j,reorderSave;
							 | 
						|
								    int numSlots = unique->initSlots;
							 | 
						|
								    int *newperm, *newinvperm, *newmap;
							 | 
						|
								    DdNode *one, *zero;
							 | 
						|
								
							 | 
						|
								    oldsize = unique->size;
							 | 
						|
								    /* Easy case: there is still room in the current table. */
							 | 
						|
								    if (index >= 0 && index < unique->maxSize) {
							 | 
						|
									for (i = oldsize; i <= index; i++) {
							 | 
						|
									    unique->subtables[i].slots = numSlots;
							 | 
						|
									    unique->subtables[i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    unique->subtables[i].keys = 0;
							 | 
						|
									    unique->subtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    unique->subtables[i].dead = 0;
							 | 
						|
									    unique->subtables[i].bindVar = 0;
							 | 
						|
									    unique->subtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
							 | 
						|
									    unique->subtables[i].pairIndex = 0;
							 | 
						|
									    unique->subtables[i].varHandled = 0;
							 | 
						|
									    unique->subtables[i].varToBeGrouped = CUDD_LAZY_NONE;
							 | 
						|
								
							 | 
						|
									    unique->perm[i] = i;
							 | 
						|
									    unique->invperm[i] = i;
							 | 
						|
									    newnodelist = unique->subtables[i].nodelist =
							 | 
						|
										ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										for (j = oldsize; j < i; j++) {
							 | 
						|
										    FREE(unique->subtables[j].nodelist);
							 | 
						|
										}
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = sentinel;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    for (i = oldsize; i <= index; i++) {
							 | 
						|
										unique->map[i] = i;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									/* The current table is too small: we need to allocate a new,
							 | 
						|
									** larger one; move all old subtables, and initialize the new
							 | 
						|
									** subtables up to index included.
							 | 
						|
									*/
							 | 
						|
									newsize = (index < 0) ? amount : index + amount;
							 | 
						|
								#ifdef DD_VERBOSE
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
										       "Increasing the table size from %d to %d\n",
							 | 
						|
										       unique->maxSize, newsize);
							 | 
						|
								#endif
							 | 
						|
									newsubtables = ALLOC(DdSubtable,newsize);
							 | 
						|
									if (newsubtables == NULL) {
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newvars = ALLOC(DdNodePtr,newsize);
							 | 
						|
									if (newvars == NULL) {
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newperm = ALLOC(int,newsize);
							 | 
						|
									if (newperm == NULL) {
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    FREE(newvars);
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									newinvperm = ALLOC(int,newsize);
							 | 
						|
									if (newinvperm == NULL) {
							 | 
						|
									    FREE(newsubtables);
							 | 
						|
									    FREE(newvars);
							 | 
						|
									    FREE(newperm);
							 | 
						|
									    unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    newmap = ALLOC(int,newsize);
							 | 
						|
									    if (newmap == NULL) {
							 | 
						|
										FREE(newsubtables);
							 | 
						|
										FREE(newvars);
							 | 
						|
										FREE(newperm);
							 | 
						|
										FREE(newinvperm);
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    unique->memused += (newsize - unique->maxSize) * sizeof(int);
							 | 
						|
									}
							 | 
						|
									unique->memused += (newsize - unique->maxSize) * ((numSlots+1) *
							 | 
						|
									    sizeof(DdNode *) + 2 * sizeof(int) + sizeof(DdSubtable));
							 | 
						|
									if (newsize > unique->maxSizeZ) {
							 | 
						|
									    FREE(unique->stack);
							 | 
						|
									    unique->stack = ALLOC(DdNodePtr,newsize + 1);
							 | 
						|
									    if (unique->stack == NULL) {
							 | 
						|
										FREE(newsubtables);
							 | 
						|
										FREE(newvars);
							 | 
						|
										FREE(newperm);
							 | 
						|
										FREE(newinvperm);
							 | 
						|
										if (unique->map != NULL) {
							 | 
						|
										    FREE(newmap);
							 | 
						|
										}
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    unique->stack[0] = NULL; /* to suppress harmless UMR */
							 | 
						|
									    unique->memused +=
							 | 
						|
										(newsize - ddMax(unique->maxSize,unique->maxSizeZ))
							 | 
						|
										* sizeof(DdNode *);
							 | 
						|
									}
							 | 
						|
									for (i = 0; i < oldsize; i++) {
							 | 
						|
									    newsubtables[i].slots = unique->subtables[i].slots;
							 | 
						|
									    newsubtables[i].shift = unique->subtables[i].shift;
							 | 
						|
									    newsubtables[i].keys = unique->subtables[i].keys;
							 | 
						|
									    newsubtables[i].maxKeys = unique->subtables[i].maxKeys;
							 | 
						|
									    newsubtables[i].dead = unique->subtables[i].dead;
							 | 
						|
									    newsubtables[i].nodelist = unique->subtables[i].nodelist;
							 | 
						|
									    newsubtables[i].bindVar = unique->subtables[i].bindVar;
							 | 
						|
									    newsubtables[i].varType = unique->subtables[i].varType;
							 | 
						|
									    newsubtables[i].pairIndex = unique->subtables[i].pairIndex;
							 | 
						|
									    newsubtables[i].varHandled = unique->subtables[i].varHandled;
							 | 
						|
									    newsubtables[i].varToBeGrouped = unique->subtables[i].varToBeGrouped;
							 | 
						|
								
							 | 
						|
									    newvars[i] = unique->vars[i];
							 | 
						|
									    newperm[i] = unique->perm[i];
							 | 
						|
									    newinvperm[i] = unique->invperm[i];
							 | 
						|
									}
							 | 
						|
									for (i = oldsize; i <= index; i++) {
							 | 
						|
									    newsubtables[i].slots = numSlots;
							 | 
						|
									    newsubtables[i].shift = sizeof(int) * 8 -
							 | 
						|
										cuddComputeFloorLog2(numSlots);
							 | 
						|
									    newsubtables[i].keys = 0;
							 | 
						|
									    newsubtables[i].maxKeys = numSlots * DD_MAX_SUBTABLE_DENSITY;
							 | 
						|
									    newsubtables[i].dead = 0;
							 | 
						|
									    newsubtables[i].bindVar = 0;
							 | 
						|
									    newsubtables[i].varType = CUDD_VAR_PRIMARY_INPUT;
							 | 
						|
									    newsubtables[i].pairIndex = 0;
							 | 
						|
									    newsubtables[i].varHandled = 0;
							 | 
						|
									    newsubtables[i].varToBeGrouped = CUDD_LAZY_NONE;
							 | 
						|
								
							 | 
						|
									    newperm[i] = i;
							 | 
						|
									    newinvperm[i] = i;
							 | 
						|
									    newnodelist = newsubtables[i].nodelist = ALLOC(DdNodePtr, numSlots);
							 | 
						|
									    if (newnodelist == NULL) {
							 | 
						|
										unique->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
										return(0);
							 | 
						|
									    }
							 | 
						|
									    for (j = 0; j < numSlots; j++) {
							 | 
						|
										newnodelist[j] = sentinel;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
									if (unique->map != NULL) {
							 | 
						|
									    for (i = 0; i < oldsize; i++) {
							 | 
						|
										newmap[i] = unique->map[i];
							 | 
						|
									    }
							 | 
						|
									    for (i = oldsize; i <= index; i++) {
							 | 
						|
										newmap[i] = i;
							 | 
						|
									    }
							 | 
						|
									    FREE(unique->map);
							 | 
						|
									    unique->map = newmap;
							 | 
						|
									}
							 | 
						|
									FREE(unique->subtables);
							 | 
						|
									unique->subtables = newsubtables;
							 | 
						|
									unique->maxSize = newsize;
							 | 
						|
									FREE(unique->vars);
							 | 
						|
									unique->vars = newvars;
							 | 
						|
									FREE(unique->perm);
							 | 
						|
									unique->perm = newperm;
							 | 
						|
									FREE(unique->invperm);
							 | 
						|
									unique->invperm = newinvperm;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Now that the table is in a coherent state, create the new
							 | 
						|
								    ** projection functions. We need to temporarily disable reordering,
							 | 
						|
								    ** because we cannot reorder without projection functions in place.
							 | 
						|
								    **/
							 | 
						|
								    if (index >= 0) {
							 | 
						|
								        one = unique->one;
							 | 
						|
								        zero = Cudd_Not(one);
							 | 
						|
								
							 | 
						|
								        unique->size = index + 1;
							 | 
						|
								        if (unique->tree != NULL) {
							 | 
						|
								            unique->tree->size = ddMax(unique->tree->size, unique->size);
							 | 
						|
								        }
							 | 
						|
								        unique->slots += (index + 1 - oldsize) * numSlots;
							 | 
						|
								        ddFixLimits(unique);
							 | 
						|
								
							 | 
						|
								        reorderSave = unique->autoDyn;
							 | 
						|
								        unique->autoDyn = 0;
							 | 
						|
								        for (i = oldsize; i <= index; i++) {
							 | 
						|
								            unique->vars[i] = cuddUniqueInter(unique,i,one,zero);
							 | 
						|
								            if (unique->vars[i] == NULL) {
							 | 
						|
								                unique->autoDyn = reorderSave;
							 | 
						|
								                for (j = oldsize; j < i; j++) {
							 | 
						|
								                    Cudd_IterDerefBdd(unique,unique->vars[j]);
							 | 
						|
								                    cuddDeallocNode(unique,unique->vars[j]);
							 | 
						|
								                    unique->vars[j] = NULL;
							 | 
						|
								                }
							 | 
						|
								                for (j = oldsize; j <= index; j++) {
							 | 
						|
								                    FREE(unique->subtables[j].nodelist);
							 | 
						|
								                    unique->subtables[j].nodelist = NULL;
							 | 
						|
								                }
							 | 
						|
								                unique->size = oldsize;
							 | 
						|
								                unique->slots -= (index + 1 - oldsize) * numSlots;
							 | 
						|
								                ddFixLimits(unique);
							 | 
						|
								                return(0);
							 | 
						|
								            }
							 | 
						|
								            cuddRef(unique->vars[i]);
							 | 
						|
								        }
							 | 
						|
								        unique->autoDyn = reorderSave;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of ddResizeTable */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Searches the subtables above node for a parent.]
							 | 
						|
								
							 | 
						|
								  Description [Searches the subtables above node for a parent. Returns 1
							 | 
						|
								  as soon as one parent is found. Returns 0 is the search is fruitless.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								cuddFindParent(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  DdNode * node)
							 | 
						|
								{
							 | 
						|
								    int         i,j;
							 | 
						|
								    int		slots;
							 | 
						|
								    DdNodePtr	*nodelist;
							 | 
						|
								    DdNode	*f;
							 | 
						|
								
							 | 
						|
								    for (i = cuddI(table,node->index) - 1; i >= 0; i--) {
							 | 
						|
									nodelist = table->subtables[i].nodelist;
							 | 
						|
									slots = table->subtables[i].slots;
							 | 
						|
								
							 | 
						|
									for (j = 0; j < slots; j++) {
							 | 
						|
									    f = nodelist[j];
							 | 
						|
									    while (cuddT(f) > node) {
							 | 
						|
										f = f->next;
							 | 
						|
									    }
							 | 
						|
									    while (cuddT(f) == node && Cudd_Regular(cuddE(f)) > node) {
							 | 
						|
										f = f->next;
							 | 
						|
									    }
							 | 
						|
									    if (cuddT(f) == node && Cudd_Regular(cuddE(f)) == node) {
							 | 
						|
										return(1);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of cuddFindParent */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Adjusts the values of table limits.]
							 | 
						|
								
							 | 
						|
								  Description [Adjusts the values of table fields controlling the.
							 | 
						|
								  sizes of subtables and computed table. If the computed table is too small
							 | 
						|
								  according to the new values, it is resized.]
							 | 
						|
								
							 | 
						|
								  SideEffects [Modifies manager fields. May resize computed table.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DD_INLINE
							 | 
						|
								static void
							 | 
						|
								ddFixLimits(
							 | 
						|
								  DdManager *unique)
							 | 
						|
								{
							 | 
						|
								    unique->minDead = (unsigned) (unique->gcFrac * (double) unique->slots);
							 | 
						|
								    unique->cacheSlack = (int) ddMin(unique->maxCacheHard,
							 | 
						|
									DD_MAX_CACHE_TO_SLOTS_RATIO * unique->slots) -
							 | 
						|
									2 * (int) unique->cacheSlots;
							 | 
						|
								    if (unique->cacheSlots < unique->slots/2 && unique->cacheSlack >= 0)
							 | 
						|
									cuddCacheResize(unique);
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ddFixLimits */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifndef DD_UNSORTED_FREE_LIST
							 | 
						|
								#ifdef DD_RED_BLACK_FREE_LIST
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Inserts a DdNode in a red/black search tree.]
							 | 
						|
								
							 | 
						|
								  Description [Inserts a DdNode in a red/black search tree. Nodes from
							 | 
						|
								  the same "page" (defined by DD_PAGE_MASK) are linked in a LIFO list.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddOrderedThread]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								cuddOrderedInsert(
							 | 
						|
								  DdNodePtr * root,
							 | 
						|
								  DdNodePtr node)
							 | 
						|
								{
							 | 
						|
								    DdNode *scan;
							 | 
						|
								    DdNodePtr *scanP;
							 | 
						|
								    DdNodePtr *stack[DD_STACK_SIZE];
							 | 
						|
								    int stackN = 0;
							 | 
						|
								
							 | 
						|
								    scanP = root;
							 | 
						|
								    while ((scan = *scanP) != NULL) {
							 | 
						|
									stack[stackN++] = scanP;
							 | 
						|
									if (DD_INSERT_COMPARE(node, scan) == 0) { /* add to page list */
							 | 
						|
									    DD_NEXT(node) = DD_NEXT(scan);
							 | 
						|
									    DD_NEXT(scan) = node;
							 | 
						|
									    return;
							 | 
						|
									}
							 | 
						|
									scanP = (node < scan) ? &DD_LEFT(scan) : &DD_RIGHT(scan);
							 | 
						|
								    }
							 | 
						|
								    DD_RIGHT(node) = DD_LEFT(node) = DD_NEXT(node) = NULL;
							 | 
						|
								    DD_COLOR(node) = DD_RED;
							 | 
						|
								    *scanP = node;
							 | 
						|
								    stack[stackN] = &node;
							 | 
						|
								    cuddDoRebalance(stack,stackN);
							 | 
						|
								
							 | 
						|
								} /* end of cuddOrderedInsert */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Threads all the nodes of a search tree into a linear list.]
							 | 
						|
								
							 | 
						|
								  Description [Threads all the nodes of a search tree into a linear
							 | 
						|
								  list. For each node of the search tree, the "left" child, if non-null, has
							 | 
						|
								  a lower address than its parent, and the "right" child, if non-null, has a
							 | 
						|
								  higher address than its parent.
							 | 
						|
								  The list is sorted in order of increasing addresses. The search
							 | 
						|
								  tree is destroyed as a result of this operation. The last element of
							 | 
						|
								  the linear list is made to point to the address passed in list. Each
							 | 
						|
								  node if the search tree is a linearly-linked list of nodes from the
							 | 
						|
								  same memory page (as defined in DD_PAGE_MASK). When a node is added to
							 | 
						|
								  the linear list, all the elements of the linked list are added.]
							 | 
						|
								
							 | 
						|
								  SideEffects [The search tree is destroyed as a result of this operation.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddOrderedInsert]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static DdNode *
							 | 
						|
								cuddOrderedThread(
							 | 
						|
								  DdNode * root,
							 | 
						|
								  DdNode * list)
							 | 
						|
								{
							 | 
						|
								    DdNode *current, *next, *prev, *end;
							 | 
						|
								
							 | 
						|
								    current = root;
							 | 
						|
								    /* The first word in the node is used to implement a stack that holds
							 | 
						|
								    ** the nodes from the root of the tree to the current node. Here we
							 | 
						|
								    ** put the root of the tree at the bottom of the stack.
							 | 
						|
								    */
							 | 
						|
								    *((DdNodePtr *) current) = NULL;
							 | 
						|
								
							 | 
						|
								    while (current != NULL) {
							 | 
						|
									if (DD_RIGHT(current) != NULL) {
							 | 
						|
									    /* If possible, we follow the "right" link. Eventually we'll
							 | 
						|
									    ** find the node with the largest address in the current tree.
							 | 
						|
									    ** In this phase we use the first word of a node to implemen
							 | 
						|
									    ** a stack of the nodes on the path from the root to "current".
							 | 
						|
									    ** Also, we disconnect the "right" pointers to indicate that
							 | 
						|
									    ** we have already followed them.
							 | 
						|
									    */
							 | 
						|
									    next = DD_RIGHT(current);
							 | 
						|
									    DD_RIGHT(current) = NULL;
							 | 
						|
									    *((DdNodePtr *)next) = current;
							 | 
						|
									    current = next;
							 | 
						|
									} else {
							 | 
						|
									    /* We can't proceed along the "right" links any further.
							 | 
						|
									    ** Hence "current" is the largest element in the current tree.
							 | 
						|
									    ** We make this node the new head of "list". (Repeating this
							 | 
						|
									    ** operation until the tree is empty yields the desired linear
							 | 
						|
									    ** threading of all nodes.)
							 | 
						|
									    */
							 | 
						|
									    prev = *((DdNodePtr *) current); /* save prev node on stack in prev */
							 | 
						|
									    /* Traverse the linked list of current until the end. */
							 | 
						|
									    for (end = current; DD_NEXT(end) != NULL; end = DD_NEXT(end));
							 | 
						|
									    DD_NEXT(end) = list; /* attach "list" at end and make */
							 | 
						|
									    list = current;   /* "current" the new head of "list" */
							 | 
						|
									    /* Now, if current has a "left" child, we push it on the stack.
							 | 
						|
									    ** Otherwise, we just continue with the parent of "current".
							 | 
						|
									    */
							 | 
						|
									    if (DD_LEFT(current) != NULL) {
							 | 
						|
										next = DD_LEFT(current);
							 | 
						|
										*((DdNodePtr *) next) = prev;
							 | 
						|
										current = next;
							 | 
						|
									    } else {
							 | 
						|
										current = prev;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(list);
							 | 
						|
								
							 | 
						|
								} /* end of cuddOrderedThread */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Performs the left rotation for red/black trees.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddRotateRight]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DD_INLINE
							 | 
						|
								static void
							 | 
						|
								cuddRotateLeft(
							 | 
						|
								  DdNodePtr * nodeP)
							 | 
						|
								{
							 | 
						|
								    DdNode *newRoot;
							 | 
						|
								    DdNode *oldRoot = *nodeP;
							 | 
						|
								
							 | 
						|
								    *nodeP = newRoot = DD_RIGHT(oldRoot);
							 | 
						|
								    DD_RIGHT(oldRoot) = DD_LEFT(newRoot);
							 | 
						|
								    DD_LEFT(newRoot) = oldRoot;
							 | 
						|
								
							 | 
						|
								} /* end of cuddRotateLeft */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Performs the right rotation for red/black trees.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddRotateLeft]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								DD_INLINE
							 | 
						|
								static void
							 | 
						|
								cuddRotateRight(
							 | 
						|
								  DdNodePtr * nodeP)
							 | 
						|
								{
							 | 
						|
								    DdNode *newRoot;
							 | 
						|
								    DdNode *oldRoot = *nodeP;
							 | 
						|
								
							 | 
						|
								    *nodeP = newRoot = DD_LEFT(oldRoot);
							 | 
						|
								    DD_LEFT(oldRoot) = DD_RIGHT(newRoot);
							 | 
						|
								    DD_RIGHT(newRoot) = oldRoot;
							 | 
						|
								
							 | 
						|
								} /* end of cuddRotateRight */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Rebalances a red/black tree.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								cuddDoRebalance(
							 | 
						|
								  DdNodePtr ** stack,
							 | 
						|
								  int  stackN)
							 | 
						|
								{
							 | 
						|
								    DdNodePtr *xP, *parentP, *grandpaP;
							 | 
						|
								    DdNode *x, *y, *parent, *grandpa;
							 | 
						|
								
							 | 
						|
								    xP = stack[stackN];
							 | 
						|
								    x = *xP;
							 | 
						|
								    /* Work our way back up, re-balancing the tree. */
							 | 
						|
								    while (--stackN >= 0) {
							 | 
						|
									parentP = stack[stackN];
							 | 
						|
									parent = *parentP;
							 | 
						|
									if (DD_IS_BLACK(parent)) break;
							 | 
						|
									/* Since the root is black, here a non-null grandparent exists. */
							 | 
						|
									grandpaP = stack[stackN-1];
							 | 
						|
									grandpa = *grandpaP;
							 | 
						|
									if (parent == DD_LEFT(grandpa)) {
							 | 
						|
									    y = DD_RIGHT(grandpa);
							 | 
						|
									    if (y != NULL && DD_IS_RED(y)) {
							 | 
						|
										DD_COLOR(parent) = DD_BLACK;
							 | 
						|
										DD_COLOR(y) = DD_BLACK;
							 | 
						|
										DD_COLOR(grandpa) = DD_RED;
							 | 
						|
										x = grandpa;
							 | 
						|
										stackN--;
							 | 
						|
									    } else {
							 | 
						|
										if (x == DD_RIGHT(parent)) {
							 | 
						|
										    cuddRotateLeft(parentP);
							 | 
						|
										    DD_COLOR(x) = DD_BLACK;
							 | 
						|
										} else {
							 | 
						|
										    DD_COLOR(parent) = DD_BLACK;
							 | 
						|
										}
							 | 
						|
										DD_COLOR(grandpa) = DD_RED;
							 | 
						|
										cuddRotateRight(grandpaP);
							 | 
						|
										break;
							 | 
						|
									    }
							 | 
						|
									} else {
							 | 
						|
									    y = DD_LEFT(grandpa);
							 | 
						|
									    if (y != NULL && DD_IS_RED(y)) {
							 | 
						|
										DD_COLOR(parent) = DD_BLACK;
							 | 
						|
										DD_COLOR(y) = DD_BLACK;
							 | 
						|
										DD_COLOR(grandpa) = DD_RED;
							 | 
						|
										x = grandpa;
							 | 
						|
										stackN--;
							 | 
						|
									    } else {
							 | 
						|
										if (x == DD_LEFT(parent)) {
							 | 
						|
										    cuddRotateRight(parentP);
							 | 
						|
										    DD_COLOR(x) = DD_BLACK;
							 | 
						|
										} else {
							 | 
						|
										    DD_COLOR(parent) = DD_BLACK;
							 | 
						|
										}
							 | 
						|
										DD_COLOR(grandpa) = DD_RED;
							 | 
						|
										cuddRotateLeft(grandpaP);
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								    DD_COLOR(*(stack[0])) = DD_BLACK;
							 | 
						|
								
							 | 
						|
								} /* end of cuddDoRebalance */
							 | 
						|
								#endif
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Fixes a variable tree after the insertion of new subtables.]
							 | 
						|
								
							 | 
						|
								  Description [Fixes a variable tree after the insertion of new subtables.
							 | 
						|
								  After such an insertion, the low fields of the tree below the insertion
							 | 
						|
								  point are inconsistent.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ddPatchTree(
							 | 
						|
								  DdManager *dd,
							 | 
						|
								  MtrNode *treenode)
							 | 
						|
								{
							 | 
						|
								    MtrNode *auxnode = treenode;
							 | 
						|
								
							 | 
						|
								    while (auxnode != NULL) {
							 | 
						|
									auxnode->low = dd->perm[auxnode->index];
							 | 
						|
									if (auxnode->child != NULL) {
							 | 
						|
									    ddPatchTree(dd, auxnode->child);
							 | 
						|
									}
							 | 
						|
									auxnode = auxnode->younger;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of ddPatchTree */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Checks whether a collision list is ordered.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								cuddCheckCollisionOrdering(
							 | 
						|
								  DdManager *unique,
							 | 
						|
								  int i,
							 | 
						|
								  int j)
							 | 
						|
								{
							 | 
						|
								    int slots;
							 | 
						|
								    DdNode *node, *next;
							 | 
						|
								    DdNodePtr *nodelist;
							 | 
						|
								    DdNode *sentinel = &(unique->sentinel);
							 | 
						|
								
							 | 
						|
								    nodelist = unique->subtables[i].nodelist;
							 | 
						|
								    slots = unique->subtables[i].slots;
							 | 
						|
								    node = nodelist[j];
							 | 
						|
								    if (node == sentinel) return(1);
							 | 
						|
								    next = node->next;
							 | 
						|
								    while (next != sentinel) {
							 | 
						|
									if (cuddT(node) < cuddT(next) ||
							 | 
						|
									    (cuddT(node) == cuddT(next) && cuddE(node) < cuddE(next))) {
							 | 
						|
									    (void) fprintf(unique->err,
							 | 
						|
											   "Unordered list: index %u, position %d\n", i, j);
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
									node = next;
							 | 
						|
									next = node->next;
							 | 
						|
								    }
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of cuddCheckCollisionOrdering */
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Reports problem in garbage collection.]
							 | 
						|
								
							 | 
						|
								  Description []
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [cuddGarbageCollect cuddGarbageCollectZdd]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								ddReportRefMess(
							 | 
						|
								  DdManager *unique /* manager */,
							 | 
						|
								  int i /* table in which the problem occurred */,
							 | 
						|
								  const char *caller /* procedure that detected the problem */)
							 | 
						|
								{
							 | 
						|
								    if (i == CUDD_CONST_INDEX) {
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
											   "%s: problem in constants\n", caller);
							 | 
						|
								    } else if (i != -1) {
							 | 
						|
									(void) fprintf(unique->err,
							 | 
						|
											   "%s: problem in table %d\n", caller, i);
							 | 
						|
								    }
							 | 
						|
								    (void) fprintf(unique->err, "  dead count != deleted\n");
							 | 
						|
								    (void) fprintf(unique->err, "  This problem is often due to a missing \
							 | 
						|
								call to Cudd_Ref\n  or to an extra call to Cudd_RecursiveDeref.\n  \
							 | 
						|
								See the CUDD Programmer's Guide for additional details.");
							 | 
						|
								    abort();
							 | 
						|
								
							 | 
						|
								} /* end of ddReportRefMess */
							 |