/**Function******************************************************************** Synopsis [Increases the reference count of a node, if it is not saturated.] Description [] SideEffects [None] SeeAlso [Cudd_RecursiveDeref Cudd_Deref] ******************************************************************************/ void Cudd_Ref( DdNode * n) { n = Cudd_Regular(n); cuddSatInc(n->ref); } /* end of Cudd_Ref */
/**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 [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 */