Пример #1
0
/**Function*************************************************************

  Synopsis    [Prints one row of the latch dependency matrix.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Extra_bddImagePrintLatchDependencyOne(
    DdManager * dd, DdNode * bFunc,      // the function
    DdNode * bVarsCs, DdNode * bVarsNs,  // the current/next state vars
    int iPart )
{
    DdNode * bSupport;
    int v;
    bSupport = Cudd_Support( dd, bFunc );  Cudd_Ref( bSupport );
    printf( " %3d : ", iPart );
    for ( v = 0; v < dd->size; v++ )
    {
        if ( Cudd_bddLeq( dd, bSupport, dd->vars[v] ) )
        {
            if ( Cudd_bddLeq( dd, bVarsCs, dd->vars[v] ) )
                printf( "c" );
            else if ( Cudd_bddLeq( dd, bVarsNs, dd->vars[v] ) ) 
                printf( "n" );
            else
                printf( "i" );
        }
        else
            printf( "." );
    }
    printf( "\n" );
    Cudd_RecursiveDeref( dd, bSupport );
}
Пример #2
0
    Vec_IntForEachEntry( vNodes, Entry, i )
    { 
        if ( Entry != 0 && Entry != 1 )
            continue;
        pObj = Aig_ManObj( p, i );
        bFunc = Llb_ManComputeIndCase_rec( p, pObj, dd, vBdds );
        if ( Entry == 0 )
        {
//            Extra_bddPrint( dd, Cudd_Not(pObj->pData) );  printf( "\n" );
//            Extra_bddPrint( dd, Cudd_Not(bFunc) );        printf( "\n" );
            if ( !Cudd_bddLeq( dd, Cudd_Not(pObj->pData), Cudd_Not(bFunc) ) )
                Vec_IntWriteEntry( vNodes, i, -1 );
        }
        else if ( Entry == 1 )
        {
//            Extra_bddPrint( dd, pObj->pData );  printf( "\n" );
//            Extra_bddPrint( dd, bFunc );        printf( "\n" );
            if ( !Cudd_bddLeq( dd, (DdNode *)pObj->pData, bFunc ) )
                Vec_IntWriteEntry( vNodes, i, -1 );
        }
    }
Пример #3
0
/**Function********************************************************************

  Synopsis    [Checks whether a variable is dependent on others in a
  function.]

  Description [Checks whether a variable is dependent on others in a
  function.  Returns 1 if the variable is dependent; 0 otherwise. No
  new nodes are created.]

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
int
Cudd_bddVarIsDependent(
  DdManager *dd,		/* manager */
  DdNode *f,			/* function */
  DdNode *var			/* variable */)
{
    DdNode *F, *res, *zero, *ft, *fe;
    unsigned topf, level;
    DD_CTFP cacheOp;
    int retval;

    /* NuSMV: begin add */
    abort(); /* NOT USED BY NUSMV */
    /* NuSMV: begin end */

    zero = Cudd_Not(DD_TRUE(dd));
    if (Cudd_IsConstant(f)) return(f == zero);

    /* From now on f is not constant. */
    F = Cudd_Regular(f);
    topf = (unsigned) dd->perm[F->index];
    level = (unsigned) dd->perm[var->index];

    /* Check terminal case. If topf > index of var, f does not depend on var.
    ** Therefore, var is not dependent in f. */
    if (topf > level) {
	return(0);
    }

    cacheOp = (DD_CTFP) Cudd_bddVarIsDependent;
    res = cuddCacheLookup2(dd,cacheOp,f,var);
    if (res != NULL) {
	return(res != zero);
    }

    /* Compute cofactors. */
    ft = Cudd_NotCond(cuddT(F), f != F);
    fe = Cudd_NotCond(cuddE(F), f != F);

    if (topf == level) {
	retval = Cudd_bddLeq(dd,ft,Cudd_Not(fe));
    } else {
	retval = Cudd_bddVarIsDependent(dd,ft,var) &&
	    Cudd_bddVarIsDependent(dd,fe,var);
    }

    cuddCacheInsert2(dd,cacheOp,f,var,Cudd_NotCond(zero,retval));

    return(retval);

} /* Cudd_bddVarIsDependent */
Пример #4
0
/**Function********************************************************************

  Synopsis    [Main function for testcudd.]

  Description []

  SideEffects [None]

  SeeAlso     []

******************************************************************************/
int
main(int argc, char **argv)
{
    FILE *fp;           /* pointer to input file */
    char *file = (char *) "";	/* input file name */
    FILE *dfp = NULL;	/* pointer to dump file */
    char *dfile;	/* file for DD dump */
    DdNode *dfunc[2];	/* addresses of the functions to be dumped */
    DdManager *dd;	/* pointer to DD manager */
    DdNode *_true;	/* fast access to constant function */
    DdNode *M;
    DdNode **x;		/* pointers to variables */
    DdNode **y;		/* pointers to variables */
    DdNode **xn;       	/* complements of row variables */
    DdNode **yn_;      	/* complements of column variables */
    DdNode **xvars;
    DdNode **yvars;
    DdNode *C;		/* result of converting from ADD to BDD */
    DdNode *ess;	/* cube of essential variables */
    DdNode *shortP;	/* BDD cube of shortest path */
    DdNode *largest;	/* BDD of largest cube */
    DdNode *shortA;	/* ADD cube of shortest path */
    DdNode *constN;	/* value returned by evaluation of ADD */
    DdNode *ycube;	/* cube of the negated y vars for c-proj */
    DdNode *CP;		/* C-Projection of C */
    DdNode *CPr;	/* C-Selection of C */
    int    length;	/* length of the shortest path */
    int    nx;			/* number of variables */
    int    ny;
    int    maxnx;
    int    maxny;
    int    m;
    int    n;
    int    N;
    int    cmu;			/* use CMU multiplication */
    int    pr;			/* verbose printout level */
    int    harwell;
    int    multiple;		/* read multiple matrices */
    int    ok;
    int    c;			/* variable to read in options */
    int    approach;		/* reordering approach */
    int    autodyn;		/* automatic reordering */
    int    groupcheck;		/* option for group sifting */
    int    profile;		/* print heap profile if != 0 */
    int    keepperm;		/* keep track of permutation */
    int    clearcache;		/* clear the cache after each matrix */
    int    blifOrDot;		/* dump format: 0 -> dot, 1 -> blif, ... */
    int    retval;		/* return value */
    int    i;			/* loop index */
    long   startTime;		/* initial time */
    long   lapTime;
    int    size;
    unsigned int cacheSize, maxMemory;
    unsigned int nvars,nslots;

    startTime = util_cpu_time();

    approach = CUDD_REORDER_NONE;
    autodyn = 0;
    pr = 0;
    harwell = 0;
    multiple = 0;
    profile = 0;
    keepperm = 0;
    cmu = 0;
    N = 4;
    nvars = 4;
    cacheSize = 127;
    maxMemory = 0;
    nslots = CUDD_UNIQUE_SLOTS;
    clearcache = 0;
    groupcheck = CUDD_GROUP_CHECK7;
    dfile = NULL;
    blifOrDot = 0; /* dot format */

    /* Parse command line. */
    while ((c = util_getopt(argc, argv, (char *) "CDHMPS:a:bcd:g:hkmn:p:v:x:X:"))
	   != EOF) {
	switch(c) {
	case 'C':
	    cmu = 1;
	    break;
	case 'D':
	    autodyn = 1;
	    break;
	case 'H':
	    harwell = 1;
	    break;
	case 'M':
#ifdef MNEMOSYNE
	    (void) mnem_setrecording(0);
#endif
	    break;
	case 'P':
	    profile = 1;
	    break;
	case 'S':
	    nslots = atoi(util_optarg);
	    break;
	case 'X':
	    maxMemory = atoi(util_optarg);
	    break;
	case 'a':
	    approach = atoi(util_optarg);
	    break;
	case 'b':
	    blifOrDot = 1; /* blif format */
	    break;
	case 'c':
	    clearcache = 1;
	    break;
	case 'd':
	    dfile = util_optarg;
	    break;
	case 'g':
	    groupcheck = atoi(util_optarg);
	    break;
	case 'k':
	    keepperm = 1;
	    break;
	case 'm':
	    multiple = 1;
	    break;
	case 'n':
	    N = atoi(util_optarg);
	    break;
	case 'p':
	    pr = atoi(util_optarg);
	    break;
	case 'v':
	    nvars = atoi(util_optarg);
	    break;
	case 'x':
	    cacheSize = atoi(util_optarg);
	    break;
	case 'h':
	default:
	    usage(argv[0]);
	    break;
	}
    }

    if (argc - util_optind == 0) {
	file = (char *) "-";
    } else if (argc - util_optind == 1) {
	file = argv[util_optind];
    } else {
	usage(argv[0]);
    }
    if ((approach<0) || (approach>17)) {
	(void) fprintf(stderr,"Invalid approach: %d \n",approach);
	usage(argv[0]);
    }

    if (pr >= 0) {
	(void) printf("# %s\n", TESTCUDD_VERSION);
	/* Echo command line and arguments. */
	(void) printf("#");
	for (i = 0; i < argc; i++) {
	    (void) printf(" %s", argv[i]);
	}
	(void) printf("\n");
	(void) fflush(stdout);
    }

    /* Initialize manager and provide easy reference to terminals. */
    dd = Cudd_Init(nvars,0,nslots,cacheSize,maxMemory);
    _true = DD_TRUE(dd);
    dd->groupcheck = (Cudd_AggregationType) groupcheck;
    if (autodyn) Cudd_AutodynEnable(dd,CUDD_REORDER_SAME);

    /* Open input file. */
    fp = open_file(file, "r");

    /* Open dump file if requested */
    if (dfile != NULL) {
	dfp = open_file(dfile, "w");
    }

    x = y = xn = yn_ = NULL;
    do {
	/* We want to start anew for every matrix. */
	maxnx = maxny = 0;
	nx = maxnx; ny = maxny;
	if (pr>0) lapTime = util_cpu_time();
	if (harwell) {
	    if (pr >= 0) (void) printf(":name: ");
	    ok = Cudd_addHarwell(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
	    &m, &n, 0, 2, 1, 2, pr);
	} else {
	    ok = Cudd_addRead(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny,
	    &m, &n, 0, 2, 1, 2);
	    if (pr >= 0)
		(void) printf(":name: %s: %d rows %d columns\n", file, m, n);
	}
	if (!ok) {
	    (void) fprintf(stderr, "Error reading matrix\n");
	    exit(1);
	}

	if (nx > maxnx) maxnx = nx;
	if (ny > maxny) maxny = ny;

	/* Build cube of negated y's. */
	ycube = DD_TRUE(dd);
	Cudd_Ref(ycube);
	for (i = maxny - 1; i >= 0; i--) {
	    DdNode *tmpp;
	    tmpp = Cudd_bddAnd(dd,Cudd_Not(dd->vars[y[i]->index]),ycube);
	    if (tmpp == NULL) exit(2);
	    Cudd_Ref(tmpp);
	    Cudd_RecursiveDeref(dd,ycube);
	    ycube = tmpp;
	}
	/* Initialize vectors of BDD variables used by priority func. */
	xvars = ALLOC(DdNode *, nx);
	if (xvars == NULL) exit(2);
	for (i = 0; i < nx; i++) {
	    xvars[i] = dd->vars[x[i]->index];
	}
	yvars = ALLOC(DdNode *, ny);
	if (yvars == NULL) exit(2);
	for (i = 0; i < ny; i++) {
	    yvars[i] = dd->vars[y[i]->index];
	}

	/* Clean up */
	for (i=0; i < maxnx; i++) {
	    Cudd_RecursiveDeref(dd, x[i]);
	    Cudd_RecursiveDeref(dd, xn[i]);
	}
	FREE(x);
	FREE(xn);
	for (i=0; i < maxny; i++) {
	    Cudd_RecursiveDeref(dd, y[i]);
	    Cudd_RecursiveDeref(dd, yn_[i]);
	}
	FREE(y);
	FREE(yn_);

	if (pr>0) {(void) printf(":1: M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}

	if (pr>0) (void) printf(":2: time to read the matrix = %s\n",
		    util_print_time(util_cpu_time() - lapTime));

	C = Cudd_addBddPattern(dd, M);
	if (C == 0) exit(2);
	Cudd_Ref(C);
	if (pr>0) {(void) printf(":3: C"); Cudd_PrintDebug(dd,C,nx+ny,pr);}

	/* Test iterators. */
	retval = testIterators(dd,M,C,pr);
	if (retval == 0) exit(2);

	cuddCacheProfile(dd,stdout);

	/* Test XOR */
	retval = testXor(dd,C,pr,nx+ny);
	if (retval == 0) exit(2);

	/* Test Hamming distance functions. */
	retval = testHamming(dd,C,pr);
	if (retval == 0) exit(2);

	/* Test selection functions. */
	CP = Cudd_CProjection(dd,C,ycube);
	if (CP == NULL) exit(2);
	Cudd_Ref(CP);
	if (pr>0) {(void) printf("ycube"); Cudd_PrintDebug(dd,ycube,nx+ny,pr);}
	if (pr>0) {(void) printf("CP"); Cudd_PrintDebug(dd,CP,nx+ny,pr);}

	if (nx == ny) {
	    CPr = Cudd_PrioritySelect(dd,C,xvars,yvars,(DdNode **)NULL,
		(DdNode *)NULL,ny,Cudd_Xgty);
	    if (CPr == NULL) exit(2);
	    Cudd_Ref(CPr);
	    if (pr>0) {(void) printf(":4: CPr"); Cudd_PrintDebug(dd,CPr,nx+ny,pr);}
	    if (CP != CPr) {
		(void) printf("CP != CPr!\n");
	    }
	    Cudd_RecursiveDeref(dd, CPr);
	}
	FREE(xvars); FREE(yvars);

	Cudd_RecursiveDeref(dd, CP);
	Cudd_RecursiveDeref(dd, ycube);

	/* Test functions for essential variables. */
	ess = Cudd_FindEssential(dd,C);
	if (ess == NULL) exit(2);
	Cudd_Ref(ess);
	if (pr>0) {(void) printf(":4: ess"); Cudd_PrintDebug(dd,ess,nx+ny,pr);}
	Cudd_RecursiveDeref(dd, ess);

	/* Test functions for shortest paths. */
	shortP = Cudd_ShortestPath(dd, M, NULL, NULL, &length);
	if (shortP == NULL) exit(2);
	Cudd_Ref(shortP);
	if (pr>0) {
	    (void) printf(":5: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
	}
	/* Test functions for largest cubes. */
	largest = Cudd_LargestCube(dd, Cudd_Not(C), &length);
	if (largest == NULL) exit(2);
	Cudd_Ref(largest);
	if (pr>0) {
	    (void) printf(":5b: largest");
	    Cudd_PrintDebug(dd,largest,nx+ny,pr);
	}
	Cudd_RecursiveDeref(dd, largest);

	/* Test Cudd_addEvalConst and Cudd_addIteConstant. */
	shortA = Cudd_BddToAdd(dd,shortP);
	if (shortA == NULL) exit(2);
	Cudd_Ref(shortA);
	Cudd_RecursiveDeref(dd, shortP);
	constN = Cudd_addEvalConst(dd,shortA,M);
	if (constN == DD_NON_CONSTANT) exit(2);
	if (Cudd_addIteConstant(dd,shortA,M,constN) != constN) exit(2);
	if (pr>0) {(void) printf("The value of M along the chosen shortest path is %g\n", cuddV(constN));}
	Cudd_RecursiveDeref(dd, shortA);

	shortP = Cudd_ShortestPath(dd, C, NULL, NULL, &length);
	if (shortP == NULL) exit(2);
	Cudd_Ref(shortP);
	if (pr>0) {
	    (void) printf(":6: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr);
	}

	/* Test Cudd_bddIteConstant and Cudd_bddLeq. */
	if (!Cudd_bddLeq(dd,shortP,C)) exit(2);
	if (Cudd_bddIteConstant(dd,Cudd_Not(shortP),_true,C) != _true) exit(2);
	Cudd_RecursiveDeref(dd, shortP);

	if (profile) {
	    retval = cuddHeapProfile(dd);
	}

	size = dd->size;

	if (pr>0) {
	    (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
	}

	/* Reorder if so requested. */
        if (approach != CUDD_REORDER_NONE) {
#ifndef DD_STATS
	    retval = Cudd_EnableReorderingReporting(dd);
	    if (retval == 0) {
		(void) fprintf(stderr,"Error reported by Cudd_EnableReorderingReporting\n");
		exit(3);
	    }
#endif
#ifdef DD_DEBUG
	    retval = Cudd_DebugCheck(dd);
	    if (retval != 0) {
		(void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
		exit(3);
	    }
	    retval = Cudd_CheckKeys(dd);
	    if (retval != 0) {
		(void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
		exit(3);
	    }
#endif
	    retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5);
	    if (retval == 0) {
		(void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n");
		exit(3);
	    }
#ifndef DD_STATS
	    retval = Cudd_DisableReorderingReporting(dd);
	    if (retval == 0) {
		(void) fprintf(stderr,"Error reported by Cudd_DisableReorderingReporting\n");
		exit(3);
	    }
#endif
#ifdef DD_DEBUG
	    retval = Cudd_DebugCheck(dd);
	    if (retval != 0) {
		(void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
		exit(3);
	    }
	    retval = Cudd_CheckKeys(dd);
	    if (retval != 0) {
		(void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
		exit(3);
	    }
#endif
	    if (approach == CUDD_REORDER_SYMM_SIFT ||
	    approach == CUDD_REORDER_SYMM_SIFT_CONV) {
		Cudd_SymmProfile(dd,0,dd->size-1);
	    }

	    if (pr>0) {
		(void) printf("Average distance: %g\n", Cudd_AverageDistance(dd));
	    }

	    if (keepperm) {
		/* Print variable permutation. */
		(void) printf("Variable Permutation:");
		for (i=0; i<size; i++) {
		    if (i%20 == 0) (void) printf("\n");
		    (void) printf("%d ", dd->invperm[i]);
		}
		(void) printf("\n");
		(void) printf("Inverse Permutation:");
		for (i=0; i<size; i++) {
		    if (i%20 == 0) (void) printf("\n");
		    (void) printf("%d ", dd->perm[i]);
		}
		(void) printf("\n");
	    }

	    if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,nx+ny,pr);}

	    if (profile) {
		retval = cuddHeapProfile(dd);
	    }

	}

	/* Dump DDs of C and M if so requested. */
	if (dfile != NULL) {
	    dfunc[0] = C;
	    dfunc[1] = M;
	    if (blifOrDot == 1) {
		/* Only dump C because blif cannot handle ADDs */
		retval = Cudd_DumpBlif(dd,1,dfunc,NULL,(char **)onames,
				       NULL,dfp);
	    } else {
		retval = Cudd_DumpDot(dd,2,dfunc,NULL,(char **)onames,dfp);
	    }
	    if (retval != 1) {
		(void) fprintf(stderr,"abnormal termination\n");
		exit(2);
	    }
	}

	Cudd_RecursiveDeref(dd, C);
	Cudd_RecursiveDeref(dd, M);

	if (clearcache) {
	    if (pr>0) {(void) printf("Clearing the cache... ");}
	    for (i = dd->cacheSlots - 1; i>=0; i--) {
		dd->cache[i].data = NIL(DdNode);
	    }
	    if (pr>0) {(void) printf("done\n");}
	}
	if (pr>0) {
	    (void) printf("Number of variables = %6d\t",dd->size);
	    (void) printf("Number of slots     = %6d\n",dd->slots);
	    (void) printf("Number of keys      = %6d\t",dd->keys);
	    (void) printf("Number of min dead  = %6d\n",dd->minDead);
	}

    } while (multiple && !feof(fp));

    fclose(fp);
    if (dfile != NULL) {
	fclose(dfp);
    }

    /* Second phase: experiment with Walsh matrices. */
    if (!testWalsh(dd,N,cmu,approach,pr)) {
	exit(2);
    }

    /* Check variable destruction. */
    assert(cuddDestroySubtables(dd,3));
    assert(Cudd_DebugCheck(dd) == 0);
    assert(Cudd_CheckKeys(dd) == 0);

    retval = Cudd_CheckZeroRef(dd);
    ok = retval != 0;  /* ok == 0 means O.K. */
    if (retval != 0) {
	(void) fprintf(stderr,
	    "%d non-zero DD reference counts after dereferencing\n", retval);
    }

    if (pr >= 0) {
	(void) Cudd_PrintInfo(dd,stdout);
    }

    Cudd_Quit(dd);

#ifdef MNEMOSYNE
    mnem_writestats();
#endif

    if (pr>0) (void) printf("total time = %s\n",
		util_print_time(util_cpu_time() - startTime));

    if (pr >= 0) util_print_cpu_stats(stdout);
    exit(ok);
    /* NOTREACHED */

} /* end of main */
Пример #5
0
/**
  @brief Implements the recursive step of Cudd_bddClippingAnd.

  @details Takes the conjunction of two BDDs.

  @return a pointer to the result is successful; NULL otherwise.

  @sideeffect None

  @see cuddBddClippingAnd

*/
static DdNode *
cuddBddClippingAndRecur(
  DdManager * manager,
  DdNode * f,
  DdNode * g,
  int  distance,
  int  direction)
{
    DdNode *F, *ft, *fe, *G, *gt, *ge;
    DdNode *one, *zero, *r, *t, *e;
    int topf, topg;
    unsigned int index;
    DD_CTFP cacheOp;

    statLine(manager);
    one = DD_ONE(manager);
    zero = Cudd_Not(one);

    /* Terminal cases. */
    if (f == zero || g == zero || f == Cudd_Not(g)) return(zero);
    if (f == g || g == one) return(f);
    if (f == one) return(g);
    if (distance == 0) {
	/* One last attempt at returning the right result. We sort of
	** cheat by calling Cudd_bddLeq. */
	if (Cudd_bddLeq(manager,f,g)) return(f);
	if (Cudd_bddLeq(manager,g,f)) return(g);
	if (direction == 1) {
	    if (Cudd_bddLeq(manager,f,Cudd_Not(g)) ||
		Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero);
	}
	return(Cudd_NotCond(one,(direction == 0)));
    }

    /* At this point f and g are not constant. */
    distance--;

    /* Check cache. Try to increase cache efficiency by sorting the
    ** pointers. */
    if (f > g) {
	DdNode *tmp = f;
	f = g; g = tmp;
    }
    F = Cudd_Regular(f);
    G = Cudd_Regular(g);
    cacheOp = (DD_CTFP)
	(direction ? Cudd_bddClippingAnd : cuddBddClippingAnd);
    if (F->ref != 1 || G->ref != 1) {
	r = cuddCacheLookup2(manager, cacheOp, f, g);
	if (r != NULL) return(r);
    }

    checkWhetherToGiveUp(manager);

    /* Here we can skip the use of cuddI, because the operands are known
    ** to be non-constant.
    */
    topf = manager->perm[F->index];
    topg = manager->perm[G->index];

    /* Compute cofactors. */
    if (topf <= topg) {
	index = F->index;
	ft = cuddT(F);
	fe = cuddE(F);
	if (Cudd_IsComplement(f)) {
	    ft = Cudd_Not(ft);
	    fe = Cudd_Not(fe);
	}
    } else {
	index = G->index;
	ft = fe = f;
    }

    if (topg <= topf) {
	gt = cuddT(G);
	ge = cuddE(G);
	if (Cudd_IsComplement(g)) {
	    gt = Cudd_Not(gt);
	    ge = Cudd_Not(ge);
	}
    } else {
	gt = ge = g;
    }

    t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction);
    if (t == NULL) return(NULL);
    cuddRef(t);
    e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction);
    if (e == NULL) {
	Cudd_RecursiveDeref(manager, t);
	return(NULL);
    }
    cuddRef(e);

    if (t == e) {
	r = t;
    } else {
	if (Cudd_IsComplement(t)) {
	    r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e));
	    if (r == NULL) {
		Cudd_RecursiveDeref(manager, t);
		Cudd_RecursiveDeref(manager, e);
		return(NULL);
	    }
	    r = Cudd_Not(r);
	} else {
	    r = cuddUniqueInter(manager,(int)index,t,e);
	    if (r == NULL) {
		Cudd_RecursiveDeref(manager, t);
		Cudd_RecursiveDeref(manager, e);
		return(NULL);
	    }
	}
    }
    cuddDeref(e);
    cuddDeref(t);
    if (F->ref != 1 || G->ref != 1)
	cuddCacheInsert2(manager, cacheOp, f, g, r);
    return(r);

} /* end of cuddBddClippingAndRecur */
Пример #6
0
/**Function********************************************************************

  Synopsis    [Determines whether f is less than or equal to g.]

  Description [Returns 1 if f is less than or equal to g; 0 otherwise.
  No new nodes are created.]

  SideEffects [None]

  SeeAlso     [Cudd_bddIteConstant Cudd_addEvalConst]

******************************************************************************/
int
Cudd_bddLeq(
  DdManager * dd,
  DdNode * f,
  DdNode * g)
{
    DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn;
    unsigned int topf, topg, res;

    statLine(dd);
    /* Terminal cases and normalization. */
    if (f == g) return(1);

    if (Cudd_IsComplement(g)) {
        /* Special case: if f is regular and g is complemented,
        ** f(1,...,1) = 1 > 0 = g(1,...,1).
        */
        if (!Cudd_IsComplement(f)) return(0);
        /* Both are complemented: Swap and complement because
        ** f <= g <=> g' <= f' and we want the second argument to be regular.
        */
        tmp = g;
        g = Cudd_Not(f);
        f = Cudd_Not(tmp);
    } else if (Cudd_IsComplement(f) && cuddF2L(g) < cuddF2L(f)) {
        tmp = g;
        g = Cudd_Not(f);
        f = Cudd_Not(tmp);
    }

    /* Now g is regular and, if f is not regular, f < g. */
    one = DD_ONE(dd);
    if (g == one) return(1);    /* no need to test against zero */
    if (f == one) return(0);    /* since at this point g != one */
    if (Cudd_Not(f) == g) return(0); /* because neither is constant */
    zero = Cudd_Not(one);
    if (f == zero) return(1);

    /* Here neither f nor g is constant. */

    /* Check cache. */
    tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_bddLeq,f,g);
    if (tmp != NULL) {
        return(tmp == one);
    }

    /* Compute cofactors. */
    F = Cudd_Regular(f);
    topf = dd->perm[F->index];
    topg = dd->perm[g->index];
    if (topf <= topg) {
        fv = cuddT(F); fvn = cuddE(F);
        if (f != F) {
            fv = Cudd_Not(fv);
            fvn = Cudd_Not(fvn);
        }
    } else {
        fv = fvn = f;
    }
    if (topg <= topf) {
        gv = cuddT(g); gvn = cuddE(g);
    } else {
        gv = gvn = g;
    }

    /* Recursive calls. Since we want to maximize the probability of
    ** the special case f(1,...,1) > g(1,...,1), we consider the negative
    ** cofactors first. Indeed, the complementation parity of the positive
    ** cofactors is the same as the one of the parent functions.
    */
    res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv);

    /* Store result in cache and return. */
    cuddCacheInsert2(dd,(DD_CTFP)Cudd_bddLeq,f,g,(res ? one : zero));
    return(res);

} /* end of Cudd_bddLeq */
Пример #7
0
/**
 * @brief Basic test of timeout handler.
 *
 * @details Sets a short timeout and then tries to build a function
 * with a large BDD.  Strives to avoid leaking nodes.
 *
 * @return 0 if successful; -1 otherwise.
 */
static int
testTimeout(int verbosity)
{
    DdManager *dd;
    /* Declare these "volatile" to prevent clobbering by longjmp. */
    DdNode * volatile f;
    DdNode * volatile clause = NULL;
    DdNode * var1, * var2;
    int i, ret, count;
    int const N = 20; /* half the number of variables in f */
    unsigned long timeout = 100UL; /* in milliseconds */
    jmp_buf timeoutEnv;

    dd = Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0);
    if (!dd) {
        if (verbosity) {
            printf("initialization failed\n");
        }
        return -1;
    }

    /* Set up timeout handling. */
    if (setjmp(timeoutEnv) > 0) {
        if (verbosity) {
            printf("caught timeout\n");
        }
        /* The nodes of clause may be leaked if the timeout was
         * detected while conjoining the clause to f.  We set
         * clause to NULL when it's not in use to be able to
         * detect this case.
         */
        if (clause)
            Cudd_RecursiveDeref(dd, clause);
        goto finally;
    }
    (void) Cudd_RegisterTimeoutHandler(dd, timeoutHandler, (void *) &timeoutEnv);
    (void) Cudd_SetTimeLimit(dd, timeout);

    /* Try to build function.  This is expected to run out of time. */
    f = Cudd_ReadOne(dd);
    Cudd_Ref(f);
    for (i = 0; i < N; i++) {
        DdNode * tmp;
        var1 = Cudd_bddIthVar(dd, i);
        if (!var1) {
            if (verbosity) {
                printf("computation failed\n");
                return -1;
            }
        }
        var2 = Cudd_bddIthVar(dd, i+N);
        if (!var2) {
            if (verbosity) {
                printf("computation failed\n");
                return -1;
            }
        }
        clause = Cudd_bddOr(dd, var1, var2);
        if (!clause) {
            if (verbosity) {
                printf("computation failed\n");
            }
            return -1;
        }
        Cudd_Ref(clause);
        tmp = Cudd_bddAnd(dd, f, clause);
        if (!tmp) {
            if (verbosity) {
                printf("computation failed\n");
            }
            return -1;
        }
        Cudd_Ref(tmp);
        Cudd_RecursiveDeref(dd, clause);
        clause = NULL;
        Cudd_RecursiveDeref(dd, f);
        f = tmp;
    }
    if (verbosity > 1) {
        Cudd_bddPrintCover(dd, f, f);
    }

finally:
    if (verbosity) {
        printf("so far");
        Cudd_PrintSummary(dd, f, 2*N, 0);
    }
    count = 0;
    for (i = 0; i < N-1; i += 2) {
        var1 = Cudd_bddIthVar(dd, i);
        if (!var1) {
            printf("computation failed\n");
            return -1;
        }
        var2 = Cudd_bddIthVar(dd, i+1);
        if (!var2) {
            printf("computation failed\n");
            return -1;
        }
        clause = Cudd_bddOr(dd, var1, var2);
        if (!clause) {
            printf("computation failed\n");
            return -1;
        }
        Cudd_Ref(clause);
        if (Cudd_bddLeq(dd, f, clause)) {
            count++;
        }
        Cudd_RecursiveDeref(dd, clause);
    }
    if (verbosity) {
        printf("f implies %d clauses\n", count);
    }
    Cudd_RecursiveDeref(dd, f);
    ret = Cudd_CheckZeroRef(dd);
    if (verbosity) {
        Cudd_PrintInfo(dd, stdout);
        if (ret != 0) {
            printf("%d non-zero references\n", ret);
        }
    }
    Cudd_Quit(dd);
    return 0;
}
Пример #8
0
DdNode *compute_winning_set_BDD( DdManager *manager,
                                 DdNode *etrans, DdNode *strans,
                                 DdNode **egoals, DdNode **sgoals,
                                 unsigned char verbose )
{
    DdNode *X = NULL, *X_prev = NULL;
    DdNode *Y = NULL, *Y_exmod = NULL, *Y_prev = NULL;
    DdNode **Z = NULL, **Z_prev = NULL;
    bool Z_changed;  /* Use to detect occurrence of fixpoint for all Z_i */

    /* Fixpoint iteration counters */
    int num_it_Z, num_it_Y, num_it_X;

    DdNode *tmp, *tmp2;
    int i, j;  /* Generic counters */

    DdNode **vars, **pvars;
    int num_env, num_sys;
    int *cube;  /* length will be twice total number of variables (to
                   account for both variables and their primes). */

    num_env = tree_size( spc.evar_list );
    num_sys = tree_size( spc.svar_list );

    /* Allocate cube array, used later for quantifying over variables. */
    cube = (int *)malloc( sizeof(int)*2*(num_env+num_sys) );
    if (cube == NULL) {
        perror( __FILE__ ",  malloc" );
        exit(-1);
    }

    /* Define a map in the manager to easily swap variables with their
       primed selves. */
    vars = malloc( (num_env+num_sys)*sizeof(DdNode *) );
    pvars = malloc( (num_env+num_sys)*sizeof(DdNode *) );
    for (i = 0; i < num_env+num_sys; i++) {
        *(vars+i) = Cudd_bddIthVar( manager, i );
        *(pvars+i) = Cudd_bddIthVar( manager, i+num_env+num_sys );
    }
    if (!Cudd_SetVarMap( manager, vars, pvars, num_env+num_sys )) {
        fprintf( stderr,
                 "Error: failed to define variable map in CUDD manager.\n" );
        free( cube );
        return NULL;
    }
    free( vars );
    free( pvars );

    if (spc.num_sgoals > 0) {
        Z = malloc( spc.num_sgoals*sizeof(DdNode *) );
        Z_prev = malloc( spc.num_sgoals*sizeof(DdNode *) );
        for (i = 0; i < spc.num_sgoals; i++) {
            *(Z+i) = NULL;
            *(Z_prev+i) = NULL;
        }
    }

    /* Initialize */
    for (i = 0; i < spc.num_sgoals; i++) {
        *(Z+i) = Cudd_ReadOne( manager );
        Cudd_Ref( *(Z+i) );
    }

    num_it_Z = 0;
    do {
        num_it_Z++;
        if (verbose > 1) {
            logprint( "Z iteration %d", num_it_Z );
            logprint( "Cudd_ReadMemoryInUse (bytes): %d",
                      Cudd_ReadMemoryInUse( manager ) );
        }

        for (i = 0; i < spc.num_sgoals; i++) {
            if (*(Z_prev+i) != NULL)
                Cudd_RecursiveDeref( manager, *(Z_prev+i) );
            *(Z_prev+i) = *(Z+i);
        }

        for (i = 0; i < spc.num_sgoals; i++) {
            if (i == spc.num_sgoals-1) {
                *(Z+i) = compute_existsmodal( manager, *Z_prev, etrans, strans,
                                              num_env, num_sys, cube );
            } else {
                *(Z+i) = compute_existsmodal( manager, *(Z_prev+i+1),
                                              etrans, strans, num_env, num_sys,
                                              cube );
            }
            if (*(Z+i) == NULL) {
                /* fatal error */
                return NULL;
            }

            /* (Re)initialize Y */
            if (Y != NULL)
                Cudd_RecursiveDeref( manager, Y );
            Y = Cudd_Not( Cudd_ReadOne( manager ) );
            Cudd_Ref( Y );

            num_it_Y = 0;
            do {
                num_it_Y++;
                if (verbose > 1) {
                    logprint( "\tY iteration %d", num_it_Y );
                    logprint( "\tCudd_ReadMemoryInUse (bytes): %d",
                              Cudd_ReadMemoryInUse( manager ) );
                }

                if (Y_prev != NULL)
                    Cudd_RecursiveDeref( manager, Y_prev );
                Y_prev = Y;
                if (Y_exmod != NULL)
                    Cudd_RecursiveDeref( manager, Y_exmod );
                Y_exmod = compute_existsmodal( manager, Y_prev, etrans, strans,
                                               num_env, num_sys, cube );
                if (Y_exmod == NULL) {
                    /* fatal error */
                    return NULL;
                }

                Y = Cudd_Not( Cudd_ReadOne( manager ) );
                Cudd_Ref( Y );
                for (j = 0; j < spc.num_egoals; j++) {

                    /* (Re)initialize X */
                    if (X != NULL)
                        Cudd_RecursiveDeref( manager, X );
                    X = Cudd_ReadOne( manager );
                    Cudd_Ref( X );

                    /* Greatest fixpoint for X, for this env goal */
                    num_it_X = 0;
                    do {
                        num_it_X++;
                        if (verbose > 1) {
                            logprint( "\t\tX iteration %d", num_it_X );
                            logprint( "\t\tCudd_ReadMemoryInUse (bytes): %d",
                                      Cudd_ReadMemoryInUse( manager ) );
                        }

                        if (X_prev != NULL)
                            Cudd_RecursiveDeref( manager, X_prev );
                        X_prev = X;
                        X = compute_existsmodal( manager, X_prev,
                                                 etrans, strans,
                                                 num_env, num_sys, cube );
                        if (X == NULL) {
                            /* fatal error */
                            return NULL;
                        }

                        tmp = Cudd_bddAnd( manager, *(sgoals+i), *(Z+i) );
                        Cudd_Ref( tmp );
                        tmp2 = Cudd_bddOr( manager, tmp, Y_exmod );
                        Cudd_Ref( tmp2 );
                        Cudd_RecursiveDeref( manager, tmp );

                        tmp = Cudd_bddAnd( manager,
                                           X, Cudd_Not( *(egoals+j) ) );
                        Cudd_Ref( tmp );
                        Cudd_RecursiveDeref( manager, X );

                        X = Cudd_bddOr( manager, tmp2, tmp );
                        Cudd_Ref( X );
                        Cudd_RecursiveDeref( manager, tmp );
                        Cudd_RecursiveDeref( manager, tmp2 );

                        tmp = X;
                        X = Cudd_bddAnd( manager, X, X_prev );
                        Cudd_Ref( X );
                        Cudd_RecursiveDeref( manager, tmp );

                    } while (!Cudd_bddLeq( manager, X, X_prev )
                             || !Cudd_bddLeq( manager, X_prev, X ));

                    tmp = Y;
                    Y = Cudd_bddOr( manager, Y, X );
                    Cudd_Ref( Y );
                    Cudd_RecursiveDeref( manager, tmp );

                    Cudd_RecursiveDeref( manager, X );
                    X = NULL;
                    Cudd_RecursiveDeref( manager, X_prev );
                    X_prev = NULL;
                }

                tmp2 = Y;
                Y = Cudd_bddOr( manager, Y, Y_prev );
                Cudd_Ref( Y );
                Cudd_RecursiveDeref( manager, tmp2 );

            } while (!Cudd_bddLeq( manager, Y, Y_prev )
                     || !Cudd_bddLeq( manager, Y_prev, Y ));

            Cudd_RecursiveDeref( manager, *(Z+i) );
            *(Z+i) = Cudd_bddAnd( manager, Y, *(Z_prev+i) );
            Cudd_Ref( *(Z+i) );

            Cudd_RecursiveDeref( manager, Y );
            Y = NULL;
            Cudd_RecursiveDeref( manager, Y_prev );
            Y_prev = NULL;
            Cudd_RecursiveDeref( manager, Y_exmod );
            Y_exmod = NULL;

        }

        Z_changed = False;
        for (i = 0; i < spc.num_sgoals; i++) {
            if (!Cudd_bddLeq( manager, *(Z+i), *(Z_prev+i) )
                || !Cudd_bddLeq( manager, *(Z_prev+i), *(Z+i) )) {
                Z_changed = True;
                break;
            }
        }
    } while (Z_changed);

    /* Pre-exit clean-up */
    tmp = *Z;
    Cudd_RecursiveDeref( manager, *Z_prev );
    for (i = 1; i < spc.num_sgoals; i++) {
        Cudd_RecursiveDeref( manager, *(Z+i) );
        Cudd_RecursiveDeref( manager, *(Z_prev+i) );
    }
    free( Z );
    free( Z_prev );
    free( cube );

    return tmp;
}
Пример #9
0
/**Function********************************************************************

  Synopsis    [Performs the recursive step of Dsd_CheckRootFunctionIdentity().]

  Description []

  SideEffects []

  SeeAlso     []

******************************************************************************/
int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 )
{
    unsigned HKey;

    // if either bC1 or bC2 is zero, the test is true
//  if ( bC1 == b0 || bC2 == b0 )  return 1;
    assert( bC1 != b0 );
    assert( bC2 != b0 );

    // if both bC1 and bC2 are one - perform comparison
    if ( bC1 == b1 && bC2 == b1 )  return (int)( bF1 == bF2 );

    if ( bF1 == b0 )
        return Cudd_bddLeq( dd, bC2, Cudd_Not(bF2) );

    if ( bF1 == b1 )
        return Cudd_bddLeq( dd, bC2, bF2 );

    if ( bF2 == b0 )
        return Cudd_bddLeq( dd, bC1, Cudd_Not(bF1) );

    if ( bF2 == b1 )
        return Cudd_bddLeq( dd, bC1, bF1 );

    // otherwise, keep expanding

    // check cache
//  HKey = _Hash( ((unsigned)bF1), ((unsigned)bF2), ((unsigned)bC1), ((unsigned)bC2) );
    HKey = hashKey4( bF1, bF2, bC1, bC2, pCache->nTableSize );
    if ( pCache->pTable[HKey].bX[0] == bF1 &&
            pCache->pTable[HKey].bX[1] == bF2 &&
            pCache->pTable[HKey].bX[2] == bC1 &&
            pCache->pTable[HKey].bX[3] == bC2 )
    {
        pCache->nSuccess++;
        return (int)(ABC_PTRUINT_T)pCache->pTable[HKey].bX[4]; // the last bit records the result (yes/no)
    }
    else
    {

        // determine the top variables
        int RetValue;
        DdNode * bA[4]  = { bF1, bF2, bC1, bC2 }; // arguments
        DdNode * bAR[4] = { Cudd_Regular(bF1), Cudd_Regular(bF2), Cudd_Regular(bC1), Cudd_Regular(bC2) }; // regular arguments
        int CurLevel[4] = { cuddI(dd,bAR[0]->index), cuddI(dd,bAR[1]->index), cuddI(dd,bAR[2]->index), cuddI(dd,bAR[3]->index) };
        int TopLevel = CUDD_CONST_INDEX;
        int i;
        DdNode * bE[4], * bT[4];
        DdNode * bF1next, * bF2next, * bC1next, * bC2next;

        pCache->nFailure++;

        // determine the top level
        for ( i = 0; i < 4; i++ )
            if ( TopLevel > CurLevel[i] )
                TopLevel = CurLevel[i];

        // compute the cofactors
        for ( i = 0; i < 4; i++ )
            if ( TopLevel == CurLevel[i] )
            {
                if ( bA[i] != bAR[i] ) // complemented
                {
                    bE[i] = Cudd_Not(cuddE(bAR[i]));
                    bT[i] = Cudd_Not(cuddT(bAR[i]));
                }
                else
                {
                    bE[i] = cuddE(bAR[i]);
                    bT[i] = cuddT(bAR[i]);
                }
            }
            else
                bE[i] = bT[i] = bA[i];

        // solve subproblems
        // three cases are possible

        // (1) the top var belongs to both C1 and C2
        //     in this case, any cofactor of F1 and F2 will do,
        //     as long as the corresponding cofactor of C1 and C2 is not equal to 0
        if ( TopLevel == CurLevel[2] && TopLevel == CurLevel[3] )
        {
            if ( bE[2] != b0 ) // C1
            {
                bF1next = bE[0];
                bC1next = bE[2];
            }
            else
            {
                bF1next = bT[0];
                bC1next = bT[2];
            }
            if ( bE[3] != b0 ) // C2
            {
                bF2next = bE[1];
                bC2next = bE[3];
            }
            else
            {
                bF2next = bT[1];
                bC2next = bT[3];
            }
            RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bF2next, bC1next, bC2next );
        }
        // (2) the top var belongs to either C1 or C2
        //     in this case normal splitting of cofactors
        else if ( TopLevel == CurLevel[2] && TopLevel != CurLevel[3] )
        {
            if ( bE[2] != b0 ) // C1
            {
                bF1next = bE[0];
                bC1next = bE[2];
            }
            else
            {
                bF1next = bT[0];
                bC1next = bT[2];
            }
            // split around this variable
            RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bE[1], bC1next, bE[3] );
            if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
                RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bT[1], bC1next, bT[3] );
        }
        else if ( TopLevel != CurLevel[2] && TopLevel == CurLevel[3] )
        {
            if ( bE[3] != b0 ) // C2
            {
                bF2next = bE[1];
                bC2next = bE[3];
            }
            else
            {
                bF2next = bT[1];
                bC2next = bT[3];
            }
            // split around this variable
            RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bF2next, bE[2], bC2next );
            if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
                RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bF2next, bT[2], bC2next );
        }
        // (3) the top var does not belong to C1 and C2
        //     in this case normal splitting of cofactors
        else // if ( TopLevel != CurLevel[2] && TopLevel != CurLevel[3] )
        {
            // split around this variable
            RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bE[1], bE[2], bE[3] );
            if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test
                RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bT[1], bT[2], bT[3] );
        }

        // set cache
        for ( i = 0; i < 4; i++ )
            pCache->pTable[HKey].bX[i] = bA[i];
        pCache->pTable[HKey].bX[4] = (DdNode*)(ABC_PTRUINT_T)RetValue;

        return RetValue;
    }
}
Пример #10
0
/**Function*************************************************************

  Synopsis    [Builds the tree.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int Extra_BuildTreeNode( DdManager * dd, 
    int nNodes, Extra_ImageNode_t ** pNodes, 
    int nVars,  Extra_ImageVar_t ** pVars )
{
    Extra_ImageNode_t * pNode1, * pNode2;
    Extra_ImageVar_t * pVar;
    Extra_ImageNode_t * pNode;
    DdNode * bCube, * bTemp, * bSuppTemp, * bParts;
    int iNode1, iNode2;
    int iVarBest, nSupp, v;

    // find the best variable
    iVarBest = Extra_FindBestVariable( dd, nNodes, pNodes, nVars, pVars );
    if ( iVarBest == -1 )
        return 0;

    pVar = pVars[iVarBest];

    // this var cannot appear in one partition only
    nSupp = Extra_bddSuppSize( dd, pVar->bParts );
    assert( nSupp == pVar->nParts );
    assert( nSupp != 1 );

    // if it appears in only two partitions, quantify it
    if ( pVar->nParts == 2 )
    {
        // get the nodes
        iNode1 = pVar->bParts->index;
        iNode2 = cuddT(pVar->bParts)->index;
        pNode1 = pNodes[iNode1];
        pNode2 = pNodes[iNode2];

        // get the quantification cube
        bCube = dd->vars[pVar->iNum];    Cudd_Ref( bCube );
        // add the variables that appear only in these partitions
        for ( v = 0; v < nVars; v++ )
            if ( pVars[v] && v != iVarBest && pVars[v]->bParts == pVars[iVarBest]->bParts )
            {
                // add this var
                bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[pVars[v]->iNum] );   Cudd_Ref( bCube );
                Cudd_RecursiveDeref( dd, bTemp );
                // clean this var
                Cudd_RecursiveDeref( dd, pVars[v]->bParts );
                ABC_FREE( pVars[v] );
            }
        // clean the best var
        Cudd_RecursiveDeref( dd, pVars[iVarBest]->bParts );
        ABC_FREE( pVars[iVarBest] );

        // combines two nodes
        pNode = Extra_CombineTwoNodes( dd, bCube, pNode1, pNode2 );
        Cudd_RecursiveDeref( dd, bCube );
    }
    else // if ( pVar->nParts > 2 )
    {
        // find two smallest BDDs that have this var
        Extra_FindBestPartitions( dd, pVar->bParts, nNodes, pNodes, &iNode1, &iNode2 );
        pNode1 = pNodes[iNode1];
        pNode2 = pNodes[iNode2];

        // it is not possible that a var appears only in these two
        // otherwise, it would have a different cost
        bParts = Cudd_bddAnd( dd, dd->vars[iNode1], dd->vars[iNode2] ); Cudd_Ref( bParts );
        for ( v = 0; v < nVars; v++ )
            if ( pVars[v] && pVars[v]->bParts == bParts )
                assert( 0 );
        Cudd_RecursiveDeref( dd, bParts );

        // combines two nodes
        pNode = Extra_CombineTwoNodes( dd, b1, pNode1, pNode2 );
    }

    // clean the old nodes
    pNodes[iNode1] = pNode;
    pNodes[iNode2] = NULL;
    
    // update the variables that appear in pNode[iNode2]
    for ( bSuppTemp = pNode2->pPart->bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) )
    {
        pVar = pVars[bSuppTemp->index];
        if ( pVar == NULL ) // this variable is not be quantified
            continue;
        // quantify this var
        assert( Cudd_bddLeq( dd, pVar->bParts, dd->vars[iNode2] ) );
        pVar->bParts = Cudd_bddExistAbstract( dd, bTemp = pVar->bParts, dd->vars[iNode2] ); Cudd_Ref( pVar->bParts );
        Cudd_RecursiveDeref( dd, bTemp );
        // add the new var
        pVar->bParts = Cudd_bddAnd( dd, bTemp = pVar->bParts, dd->vars[iNode1] ); Cudd_Ref( pVar->bParts );
        Cudd_RecursiveDeref( dd, bTemp );
        // update the score
        pVar->nParts = Extra_bddSuppSize( dd, pVar->bParts );
    }
    return 1;
}