/**Function******************************************************************** Synopsis [Decreases the reference count of node.] Description [Decreases the reference count of node. It is primarily used in recursive procedures to decrease the ref count of a result node before returning it. This accomplishes the goal of removing the protection applied by a previous Cudd_Ref.] SideEffects [None] SeeAlso [Cudd_RecursiveDeref Cudd_RecursiveDerefZdd Cudd_Ref] ******************************************************************************/ void Cudd_Deref( DdNode * node) { node = Cudd_Regular(node); cuddSatDec(node->ref); } /* end of Cudd_Deref */
/**Function******************************************************************** Synopsis [Decreases the reference count of node n.] Description [Decreases the reference count of node n. If n dies, recursively decreases the reference counts of its children. It is used to dispose of a DD that is no longer needed.] SideEffects [None] SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDerefZdd] ******************************************************************************/ void Cudd_RecursiveDeref( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack = table->stack; int SP = 1; unsigned int live = table->keys - table->dead; if (live > table->peakLiveNodes) { table->peakLiveNodes = live; } N = Cudd_Regular(n); do { #ifdef DD_DEBUG assert(N->ref != 0); #endif if (N->ref == 1) { N->ref = 0; table->dead++; #ifdef DD_STATS table->nodesDropped++; #endif if (cuddIsConstant(N)) { table->constants.dead++; N = stack[--SP]; } else { ord = table->perm[N->index]; stack[SP++] = Cudd_Regular(cuddE(N)); table->subtables[ord].dead++; N = cuddT(N); } } else { cuddSatDec(N->ref); N = stack[--SP]; } } while (SP != 0); } /* end of Cudd_RecursiveDeref */
/**Function******************************************************************** Synopsis [Brings children of a dead node back.] Description [] SideEffects [None] SeeAlso [cuddReclaimZdd] ******************************************************************************/ void cuddReclaim( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack = table->stack; int SP = 1; double initialDead = table->dead; N = Cudd_Regular(n); #ifdef DD_DEBUG assert(N->ref == 0); #endif do { if (N->ref == 0) { N->ref = 1; table->dead--; if (cuddIsConstant(N)) { table->constants.dead--; N = stack[--SP]; } else { ord = table->perm[N->index]; stack[SP++] = Cudd_Regular(cuddE(N)); table->subtables[ord].dead--; N = cuddT(N); } } else { cuddSatInc(N->ref); N = stack[--SP]; } } while (SP != 0); N = Cudd_Regular(n); cuddSatDec(N->ref); table->reclaimed += initialDead - table->dead; } /* end of cuddReclaim */
/**Function******************************************************************** Synopsis [Brings children of a dead ZDD node back.] Description [] SideEffects [None] SeeAlso [cuddReclaim] ******************************************************************************/ void cuddReclaimZdd( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack = table->stack; int SP = 1; N = n; #ifdef DD_DEBUG assert(N->ref == 0); #endif do { cuddSatInc(N->ref); if (N->ref == 1) { table->deadZ--; table->reclaimed++; #ifdef DD_DEBUG assert(!cuddIsConstant(N)); #endif ord = table->permZ[N->index]; stack[SP++] = cuddE(N); table->subtableZ[ord].dead--; N = cuddT(N); } else { N = stack[--SP]; } } while (SP != 0); cuddSatDec(n->ref); } /* end of cuddReclaimZdd */
/**Function******************************************************************** Synopsis [Decreases the reference count of ZDD node n.] Description [Decreases the reference count of ZDD node n. If n dies, recursively decreases the reference counts of its children. It is used to dispose of a ZDD that is no longer needed.] SideEffects [None] SeeAlso [Cudd_Deref Cudd_Ref Cudd_RecursiveDeref] ******************************************************************************/ void Cudd_RecursiveDerefZdd( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack = table->stack; int SP = 1; N = n; do { #ifdef DD_DEBUG assert(N->ref != 0); #endif cuddSatDec(N->ref); if (N->ref == 0) { table->deadZ++; #ifdef DD_STATS table->nodesDropped++; #endif #ifdef DD_DEBUG assert(!cuddIsConstant(N)); #endif ord = table->permZ[N->index]; stack[SP++] = cuddE(N); table->subtableZ[ord].dead++; N = cuddT(N); } else { N = stack[--SP]; } } while (SP != 0); } /* end of Cudd_RecursiveDerefZdd */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_MinHammingDist.] Description [Performs the recursive step of Cudd_MinHammingDist. It is based on the following identity. Let H(f) be the minimum Hamming distance of the minterms of f from the reference minterm. Then: <xmp> H(f) = min(H(f0)+h0,H(f1)+h1) </xmp> where f0 and f1 are the two cofactors of f with respect to its top variable; h0 is 1 if the minterm assigns 1 to the top variable of f; h1 is 1 if the minterm assigns 0 to the top variable of f. The upper bound on the distance is used to bound the depth of the recursion. Returns the minimum distance unless it exceeds the upper bound or computation fails.] SideEffects [None] SeeAlso [Cudd_MinHammingDist] ******************************************************************************/ static int cuddMinHammingDistRecur( DdNode * f, int *minterm, DdHashTable * table, int upperBound) { DdNode *F, *Ft, *Fe; double h, hT, hE; DdNode *zero, *res; DdManager *dd = table->manager; statLine(dd); if (upperBound == 0) return(0); F = Cudd_Regular(f); if (cuddIsConstant(F)) { zero = Cudd_Not(DD_ONE(dd)); if (f == dd->background || f == zero) { return(upperBound); } else { return(0); } } if ((res = cuddHashTableLookup1(table,f)) != NULL) { //Rob Apr 6 2001: might need to change this, not sure what it does..... h = (*cuddV(res)).get_val(); if (res->ref == 0) { dd->dead++; dd->constants.dead++; } return((int) h); } Ft = cuddT(F); Fe = cuddE(F); if (Cudd_IsComplement(f)) { Ft = Cudd_Not(Ft); Fe = Cudd_Not(Fe); } if (minterm[F->index] == 0) { DdNode *temp = Ft; Ft = Fe; Fe = temp; } hT = cuddMinHammingDistRecur(Ft,minterm,table,upperBound); if (hT == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); if (hT == 0) { hE = upperBound; } else { hE = cuddMinHammingDistRecur(Fe,minterm,table,upperBound - 1); if (hE == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); } h = ddMin(hT, hE + 1); if (F->ref != 1) { ptrint fanout = (ptrint) F->ref; cuddSatDec(fanout); Terminal hTerminal; hTerminal.set((double) h); res = cuddUniqueConst(dd,&hTerminal); //res = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) h); if (!cuddHashTableInsert1(table,f,res,fanout)) { cuddRef(res); Cudd_RecursiveDeref(dd, res); return(CUDD_OUT_OF_MEM); } } return((int) h); } /* end of cuddMinHammingDistRecur */
/**Function******************************************************************** Synopsis [Decreases the reference count of BDD node n.] Description [Enqueues node n for later dereferencing. If the queue is full decreases the reference count of the oldest node N to make room for n. If N dies, recursively decreases the reference counts of its children. It is used to dispose of a BDD that is currently not needed, but may be useful again in the near future. The dereferencing proper is done as in Cudd_IterDerefBdd.] SideEffects [None] SeeAlso [Cudd_RecursiveDeref Cudd_IterDerefBdd] ******************************************************************************/ void Cudd_DelayedDerefBdd( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack; int SP; unsigned int live = table->keys - table->dead; if (live > table->peakLiveNodes) { table->peakLiveNodes = live; } n = Cudd_Regular(n); #ifdef DD_DEBUG assert(n->ref != 0); #endif #ifdef DD_NO_DEATH_ROW N = n; #else if (cuddIsConstant(n) || n->ref > 1) { #ifdef DD_DEBUG assert(n->ref != 1 && (!cuddIsConstant(n) || n == DD_ONE(table))); #endif cuddSatDec(n->ref); return; } N = table->deathRow[table->nextDead]; if (N != NULL) { #endif #ifdef DD_DEBUG assert(!Cudd_IsComplement(N)); #endif stack = table->stack; SP = 1; do { #ifdef DD_DEBUG assert(N->ref != 0); #endif if (N->ref == 1) { N->ref = 0; table->dead++; #ifdef DD_STATS table->nodesDropped++; #endif ord = table->perm[N->index]; stack[SP++] = Cudd_Regular(cuddE(N)); table->subtables[ord].dead++; N = cuddT(N); } else { cuddSatDec(N->ref); N = stack[--SP]; } } while (SP != 0); #ifndef DD_NO_DEATH_ROW } table->deathRow[table->nextDead] = n; /* Udate insertion point. */ table->nextDead++; table->nextDead &= table->deadMask; #if 0 if (table->nextDead == table->deathRowDepth) { if (table->deathRowDepth < table->looseUpTo / 2) { extern void (*MMoutOfMemory)(long); void (*saveHandler)(long) = MMoutOfMemory; DdNodePtr *newRow; MMoutOfMemory = Cudd_OutOfMem; newRow = ABC_REALLOC(DdNodePtr,table->deathRow,2*table->deathRowDepth); MMoutOfMemory = saveHandler; if (newRow == NULL) { table->nextDead = 0; } else { int i; table->memused += table->deathRowDepth; i = table->deathRowDepth; table->deathRowDepth <<= 1; for (; i < table->deathRowDepth; i++) { newRow[i] = NULL; } table->deadMask = table->deathRowDepth - 1; table->deathRow = newRow; } } else { table->nextDead = 0; } } #endif #endif } /* end of Cudd_DelayedDerefBdd */
/**Function******************************************************************** Synopsis [Swaps two adjacent variables.] Description [Swaps two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddSwapInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddSwapInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *next; DdNodePtr g, *lastP, *previousP; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberSwapping++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer that don't depend on y directly ** will stay there; the others are put in a chain. ** The chain is handled as a FIFO; g points to the beginning and ** last points to the end. */ g = NULL; lastP = &g; for (i = 0; i < xslots; i++) { previousP = &(xlist[i]); f = *previousP; while (f != NULL) { next = f->next; f1 = cuddT(f); f0 = cuddE(f); if ((f1->index != (DdHalfWord) yindex) && (f0->index != (DdHalfWord) yindex)) { /* stays */ newxkeys++; *previousP = f; previousP = &(f->next); } else { f->index = yindex; *lastP = f; lastP = &(f->next); } f = next; } /* while there are elements in the collision chain */ *previousP = NULL; } /* for each slot of the x subtable */ *lastP = NULL; #ifdef DD_COUNT table->swapSteps += oldxkeys - newxkeys; #endif /* Take care of the x nodes that must be re-expressed. ** They form a linked list pointed by g. Their index has been ** changed to yindex already. */ f = g; while (f != NULL) { next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Decrease ref count of f1. */ cuddSatDec(f1->ref); /* Create the new T child. */ if (f11 == empty) { if (f01 != empty) { newf1 = f01; cuddSatInc(newf1->ref); } /* else case was already handled when finding nodes ** with both children below level y */ } else { /* Check xlist for triple (xindex, f11, f01). */ posn = ddHash(f11, f01, xshift); /* For each element newf1 in collision list xlist[posn]. */ newf1 = xlist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f11 && cuddE(newf1) == f01) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = xindex; newf1->ref = 1; cuddT(newf1) = f11; cuddE(newf1) = f01; /* Insert newf1 in the collision list xlist[pos]; ** increase the ref counts of f11 and f01 */ newxkeys++; newf1->next = xlist[posn]; xlist[posn] = newf1; cuddSatInc(f11->ref); cuddSatInc(f01->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Decrease ref count of f0. */ cuddSatDec(f0->ref); /* Create the new E child. */ if (f10 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check xlist for triple (xindex, f10, f00). */ posn = ddHash(f10, f00, xshift); /* For each element newf0 in collision list xlist[posn]. */ newf0 = xlist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f10 && cuddE(newf0) == f00) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = xindex; newf0->ref = 1; cuddT(newf0) = f10; cuddE(newf0) = f00; /* Insert newf0 in the collision list xlist[posn]; ** increase the ref counts of f10 and f00. */ newxkeys++; newf0->next = xlist[posn]; xlist[posn] = newf0; cuddSatInc(f10->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Insert the modified f in ylist. ** The modified f does not already exists in ylist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, yshift); newykeys++; f->next = ylist[posn]; ylist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previousP = &(ylist[i]); f = *previousP; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; } else { *previousP = f; previousP = &(f->next); } f = next; } /* while f */ *previousP = NULL; } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].nodelist = ylist; table->subtableZ[x].slots = yslots; table->subtableZ[x].shift = yshift; table->subtableZ[x].keys = newykeys; table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY; table->subtableZ[y].nodelist = xlist; table->subtableZ[y].slots = xslots; table->subtableZ[y].shift = xshift; table->subtableZ[y].keys = newxkeys; table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY; table->permZ[xindex] = y; table->permZ[yindex] = x; table->invpermZ[x] = yindex; table->invpermZ[y] = xindex; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddSwapInPlace */
/**Function******************************************************************** Synopsis [Linearly combines two adjacent variables.] Description [Linearly combines two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddLinearInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddSwapInPlace cuddLinearInPlace] ******************************************************************************/ static int cuddZddLinearInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *g, *next, *previous; DdNode *special; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberLinearTr++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; /* Get parameters of y subtable. */ yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer are put in two chains. The chain ** pointed by g holds the normal nodes. When re-expressed they stay ** in the x list. The chain pointed by special holds the elements ** that will move to the y list. */ g = special = NULL; for (i = 0; i < xslots; i++) { f = xlist[i]; if (f == NULL) continue; xlist[i] = NULL; while (f != NULL) { next = f->next; f1 = cuddT(f); /* if (f1->index == yindex) */ cuddSatDec(f1->ref); f0 = cuddE(f); /* if (f0->index == yindex) */ cuddSatDec(f0->ref); if ((int) f1->index == yindex && cuddE(f1) == empty && (int) f0->index != yindex) { f->next = special; special = f; } else { f->next = g; g = f; } f = next; } /* while there are elements in the collision chain */ } /* for each slot of the x subtable */ /* Mark y nodes with pointers from above x. We mark them by ** changing their index to x. */ for (i = 0; i < yslots; i++) { f = ylist[i]; while (f != NULL) { if (f->ref != 0) { f->index = xindex; } f = f->next; } /* while there are elements in the collision chain */ } /* for each slot of the y subtable */ /* Move special nodes to the y list. */ f = special; while (f != NULL) { next = f->next; f1 = cuddT(f); f11 = cuddT(f1); cuddT(f) = f11; cuddSatInc(f11->ref); f0 = cuddE(f); cuddSatInc(f0->ref); f->index = yindex; /* Insert at the beginning of the list so that it will be ** found first if there is a duplicate. The duplicate will ** eventually be moved or garbage collected. No node ** re-expression will add a pointer to it. */ posn = ddHash(f11, f0, yshift); f->next = ylist[posn]; ylist[posn] = f; newykeys++; f = next; } /* Take care of the remaining x nodes that must be re-expressed. ** They form a linked list pointed by g. */ f = g; while (f != NULL) { #ifdef DD_COUNT table->swapSteps++; #endif next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex || (int) f1->index == xindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex || (int) f0->index == xindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Create the new T child. */ if (f01 == empty) { newf1 = f10; cuddSatInc(newf1->ref); } else { /* Check ylist for triple (yindex, f01, f10). */ posn = ddHash(f01, f10, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; /* Search the collision chain skipping the marked nodes. */ while (newf1 != NULL) { if (cuddT(newf1) == f01 && cuddE(newf1) == f10 && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f01; cuddE(newf1) = f10; /* Insert newf1 in the collision list ylist[pos]; ** increase the ref counts of f01 and f10 */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; cuddSatInc(f01->ref); cuddSatInc(f10->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Create the new E child. */ if (f11 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check ylist for triple (yindex, f11, f00). */ posn = ddHash(f11, f00, yshift); /* For each element newf0 in collision list ylist[posn]. */ newf0 = ylist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f11 && cuddE(newf0) == f00 && (int) newf0->index == yindex) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = yindex; newf0->ref = 1; cuddT(newf0) = f11; cuddE(newf0) = f00; /* Insert newf0 in the collision list ylist[posn]; ** increase the ref counts of f11 and f00. */ newykeys++; newf0->next = ylist[posn]; ylist[posn] = newf0; cuddSatInc(f11->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Re-insert the modified f in xlist. ** The modified f does not already exists in xlist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, xshift); newxkeys++; f->next = xlist[posn]; xlist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer and move the marked nodes to the x list. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previous = NULL; f = ylist[i]; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; if (previous == NULL) ylist[i] = next; else previous->next = next; } else if ((int) f->index == xindex) { /* move marked node */ if (previous == NULL) ylist[i] = next; else previous->next = next; f1 = cuddT(f); cuddSatDec(f1->ref); /* Check ylist for triple (yindex, f1, empty). */ posn = ddHash(f1, empty, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f1 && cuddE(newf1) == empty && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f1; cuddE(newf1) = empty; /* Insert newf1 in the collision list ylist[posn]; ** increase the ref counts of f1 and empty. */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; if (posn == i && previous == NULL) previous = newf1; cuddSatInc(f1->ref); cuddSatInc(empty->ref); } cuddT(f) = newf1; f0 = cuddE(f); /* Insert f in x list. */ posn = ddHash(newf1, f0, xshift); newxkeys++; newykeys--; f->next = xlist[posn]; xlist[posn] = f; } else { previous = f; } f = next; } /* while f */ } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].keys = newxkeys; table->subtableZ[y].keys = newykeys; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); #if 0 (void) fprintf(table->out,"x = %d y = %d\n", x, y); (void) Cudd_DebugCheck(table); (void) Cudd_CheckKeys(table); #endif return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddLinearInPlace */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_bddVectorCompose.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * cuddBddVectorComposeRecur( DdManager * dd /* DD manager */, DdHashTable * table /* computed table */, DdNode * f /* BDD in which to compose */, DdNode ** vector /* functions to be composed */, int deepest /* depth of the deepest substitution */) { DdNode *F,*T,*E; DdNode *res; statLine(dd); F = Cudd_Regular(f); /* If we are past the deepest substitution, return f. */ if (cuddI(dd,F->index) > deepest) { return(f); } /* If problem already solved, look up answer and return. */ if ((res = cuddHashTableLookup1(table,F)) != NULL) { #ifdef DD_DEBUG bddVectorComposeHits++; #endif return(Cudd_NotCond(res,F != f)); } /* Split and recur on children of this node. */ T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest); if (T == NULL) return(NULL); cuddRef(T); E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest); if (E == NULL) { Cudd_IterDerefBdd(dd, T); return(NULL); } cuddRef(E); /* Call cuddBddIteRecur with the BDD that replaces the current top ** variable and the T and E we just created. */ res = cuddBddIteRecur(dd,vector[F->index],T,E); if (res == NULL) { Cudd_IterDerefBdd(dd, T); Cudd_IterDerefBdd(dd, E); return(NULL); } cuddRef(res); Cudd_IterDerefBdd(dd, T); Cudd_IterDerefBdd(dd, E); /* Do not keep the result if the reference count is only 1, since ** it will not be visited again. */ if (F->ref != 1) { ptrint fanout = (ptrint) F->ref; cuddSatDec(fanout); if (!cuddHashTableInsert1(table,F,res,fanout)) { Cudd_IterDerefBdd(dd, res); return(NULL); } } cuddDeref(res); return(Cudd_NotCond(res,F != f)); } /* end of cuddBddVectorComposeRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addGeneralVectorCompose.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * cuddAddGeneralVectorComposeRecur( DdManager * dd /* DD manager */, DdHashTable * table /* computed table */, DdNode * f /* ADD in which to compose */, DdNode ** vectorOn /* functions to substitute for x_i */, DdNode ** vectorOff /* functions to substitute for x_i' */, int deepest /* depth of deepest substitution */) { DdNode *T,*E,*t,*e; DdNode *res; /* If we are past the deepest substitution, return f. */ if (cuddI(dd,f->index) > deepest) { return(f); } if ((res = cuddHashTableLookup1(table,f)) != NULL) { #ifdef DD_DEBUG addGeneralVectorComposeHits++; #endif return(res); } /* Split and recur on children of this node. */ T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f), vectorOn,vectorOff,deepest); if (T == NULL) return(NULL); cuddRef(T); E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f), vectorOn,vectorOff,deepest); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); /* Retrieve the compose ADDs for the current top variable and call ** cuddAddApplyRecur with the T and E we just created. */ t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T); if (t == NULL) { Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); return(NULL); } cuddRef(t); e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E); if (e == NULL) { Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); Cudd_RecursiveDeref(dd,t); return(NULL); } cuddRef(e); res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); Cudd_RecursiveDeref(dd,t); Cudd_RecursiveDeref(dd,e); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); Cudd_RecursiveDeref(dd,t); Cudd_RecursiveDeref(dd,e); /* Do not keep the result if the reference count is only 1, since ** it will not be visited again */ if (f->ref != 1) { ptrint fanout = (ptrint) f->ref; cuddSatDec(fanout); if (!cuddHashTableInsert1(table,f,res,fanout)) { Cudd_RecursiveDeref(dd, res); return(NULL); } } cuddDeref(res); return(res); } /* end of cuddAddGeneralVectorComposeRecur */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_bddPermute.] Description [ Recursively puts the BDD in the order given in the array permut. Checks for trivial cases to terminate recursion, then splits on the children of this node. Once the solutions for the children are obtained, it puts into the current position the node from the rest of the BDD that should be here. Then returns this BDD. The key here is that the node being visited is NOT put in its proper place by this instance, but rather is switched when its proper position is reached in the recursion tree.<p> The DdNode * that is returned is the same BDD as passed in as node, but in the new order.] SideEffects [None] SeeAlso [Cudd_bddPermute cuddAddPermuteRecur] ******************************************************************************/ static DdNode * cuddBddPermuteRecur( DdManager * manager /* DD manager */, DdHashTable * table /* computed table */, DdNode * node /* BDD to be reordered */, int * permut /* permutation array */) { DdNode *N,*T,*E; DdNode *res; int index; statLine(manager); N = Cudd_Regular(node); /* Check for terminal case of constant node. */ if (cuddIsConstant(N)) { return(node); } /* If problem already solved, look up answer and return. */ if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) { #ifdef DD_DEBUG bddPermuteRecurHits++; #endif return(Cudd_NotCond(res,N != node)); } /* Split and recur on children of this node. */ T = cuddBddPermuteRecur(manager,table,cuddT(N),permut); if (T == NULL) return(NULL); cuddRef(T); E = cuddBddPermuteRecur(manager,table,cuddE(N),permut); if (E == NULL) { Cudd_IterDerefBdd(manager, T); return(NULL); } cuddRef(E); /* Move variable that should be in this position to this position ** by retrieving the single var BDD for that variable, and calling ** cuddBddIteRecur with the T and E we just created. */ index = permut[N->index]; res = cuddBddIteRecur(manager,manager->vars[index],T,E); if (res == NULL) { Cudd_IterDerefBdd(manager, T); Cudd_IterDerefBdd(manager, E); return(NULL); } cuddRef(res); Cudd_IterDerefBdd(manager, T); Cudd_IterDerefBdd(manager, E); /* Do not keep the result if the reference count is only 1, since ** it will not be visited again. */ if (N->ref != 1) { ptrint fanout = (ptrint) N->ref; cuddSatDec(fanout); if (!cuddHashTableInsert1(table,N,res,fanout)) { Cudd_IterDerefBdd(manager, res); return(NULL); } } cuddDeref(res); return(Cudd_NotCond(res,N != node)); } /* end of cuddBddPermuteRecur */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_addPermute.] Description [ Recursively puts the ADD in the order given in the array permut. Checks for trivial cases to terminate recursion, then splits on the children of this node. Once the solutions for the children are obtained, it puts into the current position the node from the rest of the ADD that should be here. Then returns this ADD. The key here is that the node being visited is NOT put in its proper place by this instance, but rather is switched when its proper position is reached in the recursion tree.<p> The DdNode * that is returned is the same ADD as passed in as node, but in the new order.] SideEffects [None] SeeAlso [Cudd_addPermute cuddBddPermuteRecur] ******************************************************************************/ static DdNode * cuddAddPermuteRecur( DdManager * manager /* DD manager */, DdHashTable * table /* computed table */, DdNode * node /* ADD to be reordered */, int * permut /* permutation array */) { DdNode *T,*E; DdNode *res,*var; int index; statLine(manager); /* Check for terminal case of constant node. */ if (cuddIsConstant(node)) { return(node); } /* If problem already solved, look up answer and return. */ if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) { #ifdef DD_DEBUG addPermuteRecurHits++; #endif return(res); } /* Split and recur on children of this node. */ T = cuddAddPermuteRecur(manager,table,cuddT(node),permut); if (T == NULL) return(NULL); cuddRef(T); E = cuddAddPermuteRecur(manager,table,cuddE(node),permut); if (E == NULL) { Cudd_RecursiveDeref(manager, T); return(NULL); } cuddRef(E); /* Move variable that should be in this position to this position ** by creating a single var ADD for that variable, and calling ** cuddAddIteRecur with the T and E we just created. */ index = permut[node->index]; var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager)); if (var == NULL) return(NULL); cuddRef(var); res = cuddAddIteRecur(manager,var,T,E); if (res == NULL) { Cudd_RecursiveDeref(manager,var); Cudd_RecursiveDeref(manager, T); Cudd_RecursiveDeref(manager, E); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(manager,var); Cudd_RecursiveDeref(manager, T); Cudd_RecursiveDeref(manager, E); /* Do not keep the result if the reference count is only 1, since ** it will not be visited again. */ if (node->ref != 1) { ptrint fanout = (ptrint) node->ref; cuddSatDec(fanout); if (!cuddHashTableInsert1(table,node,res,fanout)) { Cudd_RecursiveDeref(manager, res); return(NULL); } } cuddDeref(res); return(res); } /* end of cuddAddPermuteRecur */