static YAP_Bool bdd_to_add(void) { YAP_Term arg1, arg2, out; DdNode *node1, *node2; arg1 = YAP_ARG1; arg2 = YAP_ARG2; node1 = (DdNode *)YAP_IntOfTerm(arg1); node2 = Cudd_BddToAdd(mgr_ex[ex], node1); out = YAP_MkIntTerm((YAP_Int)node2); return (YAP_Unify(out, arg2)); }
/**Function******************************************************************** Synopsis [Computes the Hamming distance ADD.] Description [Computes the Hamming distance ADD. Returns an ADD that gives the Hamming distance between its two arguments if successful; NULL otherwise. The two vectors xVars and yVars identify the variables that form the two arguments.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * Cudd_addHamming( DdManager * dd, DdNode ** xVars, DdNode ** yVars, int nVars) { DdNode *result,*tempBdd; DdNode *tempAdd,*temp; int i; result = DD_ZERO(dd); cuddRef(result); for (i = 0; i < nVars; i++) { tempBdd = Cudd_bddIte(dd,xVars[i],Cudd_Not(yVars[i]),yVars[i]); if (tempBdd == NULL) { Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(tempBdd); tempAdd = Cudd_BddToAdd(dd,tempBdd); if (tempAdd == NULL) { Cudd_RecursiveDeref(dd,tempBdd); Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(tempAdd); Cudd_RecursiveDeref(dd,tempBdd); temp = Cudd_addApply(dd,Cudd_addPlus,tempAdd,result); if (temp == NULL) { Cudd_RecursiveDeref(dd,tempAdd); Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(temp); Cudd_RecursiveDeref(dd,tempAdd); Cudd_RecursiveDeref(dd,result); result = temp; } cuddDeref(result); return(result); } /* end of Cudd_addHamming */
/**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 */
/**Function******************************************************************** Synopsis [Computes shortest paths in a state graph.] Description [Computes shortest paths in the state transition graph of a network. Three methods are availabe: <ul> <li> Bellman-Ford algorithm for single-source shortest paths; the algorithm computes the distance (number of transitions) from the initial states to all states. <li> Floyd-Warshall algorithm for all-pair shortest paths. <li> Repeated squaring algorithm for all-pair shortest paths. </ul> The function returns 1 in case of success; 0 otherwise. ] SideEffects [ADD variables are created in the manager.] SeeAlso [] ******************************************************************************/ int Ntr_ShortestPaths( DdManager * dd, BnetNetwork * net, NtrOptions * option) { NtrPartTR *TR; DdNode *edges, *source, *res, *r, *q, *bddSource; DdNode **xadd, **yadd, **zadd; int i; int pr = option->verb; int algorithm = option->shortPath; int selectiveTrace = option->selectiveTrace; int nvars = net->nlatches; /* Set background to infinity for shortest paths. */ Cudd_SetBackground(dd,Cudd_ReadPlusInfinity(dd)); /* Build the monolithic TR. */ TR = Ntr_buildTR(dd,net,option,NTR_IMAGE_MONO); /* Build the ADD variable vectors for x and y. */ xadd = ALLOC(DdNode *, nvars); yadd = ALLOC(DdNode *, nvars); for(i = 0; i < nvars; i++) { q = Cudd_addIthVar(dd,TR->x[i]->index); Cudd_Ref(q); xadd[i] = q; q = Cudd_addIthVar(dd,TR->y[i]->index); Cudd_Ref(q); yadd[i] = q; } /* Convert the transition relation BDD into an ADD... */ q = Cudd_BddToAdd(dd,TR->part[0]); Cudd_Ref(q); /* ...replacing zeroes with infinities... */ r = Cudd_addIte(dd,q,Cudd_ReadOne(dd),Cudd_ReadPlusInfinity(dd)); Cudd_Ref(r); Cudd_RecursiveDeref(dd,q); /* ...and zeroing the diagonal. */ q = Cudd_addXeqy(dd,nvars,xadd,yadd); Cudd_Ref(q); edges = Cudd_addIte(dd,q,Cudd_ReadZero(dd),r); Cudd_Ref(edges); Cudd_RecursiveDeref(dd,r); Cudd_RecursiveDeref(dd,q); switch(algorithm) { case NTR_SHORT_BELLMAN: bddSource = Ntr_initState(dd,net,option); source = Cudd_BddToAdd(dd,bddSource); Cudd_Ref(source); res = ntrBellman(dd,edges,source,xadd,yadd,nvars,pr); if (res == NULL) return(0); Cudd_Ref(res); Cudd_RecursiveDeref(dd,source); Cudd_RecursiveDeref(dd,bddSource); if (pr >= 0) { (void) fprintf(stdout,"Distance Matrix"); Cudd_PrintDebug(dd,res,nvars,pr); } break; case NTR_SHORT_FLOYD: res = ntrWarshall(dd,edges,xadd,yadd,nvars,pr); if (res == NULL) return(0); Cudd_Ref(res); if (pr >= 0) { (void) fprintf(stdout,"Distance Matrix"); Cudd_PrintDebug(dd,res,2*nvars,pr); } break; case NTR_SHORT_SQUARE: /* Create a third set of ADD variables. */ zadd = ALLOC(DdNode *, nvars); for(i = 0; i < nvars; i++) { int level; level = Cudd_ReadIndex(dd,TR->x[i]->index); q = Cudd_addNewVarAtLevel(dd,level); Cudd_Ref(q); zadd[i] = q; } /* Compute the shortest paths. */ res = ntrSquare(dd,edges,zadd,yadd,xadd,nvars,pr,selectiveTrace); if (res == NULL) return(0); Cudd_Ref(res); /* Dispose of the extra variables. */ for(i = 0; i < nvars; i++) { Cudd_RecursiveDeref(dd,zadd[i]); } FREE(zadd); if (pr >= 0) { (void) fprintf(stdout,"Distance Matrix"); Cudd_PrintDebug(dd,res,2*nvars,pr); } break; default: (void) printf("Unrecognized method. Try again.\n"); return(0); } /* Here we should compute the paths. */ /* Clean up. */ Ntr_freeTR(dd,TR); Cudd_RecursiveDeref(dd,edges); Cudd_RecursiveDeref(dd,res); for(i = 0; i < nvars; i++) { Cudd_RecursiveDeref(dd,xadd[i]); Cudd_RecursiveDeref(dd,yadd[i]); } FREE(xadd); FREE(yadd); if (option->autoDyn & 1) { (void) printf("Order after short path computation\n"); if (!Bnet_PrintOrder(net,dd)) return(0); } return(1); } /* end of Ntr_ShortestPaths */
/* Convert function to ADD. This should only be done after all BDD variables have been declared */ static DdNode *aconvert(shadow_mgr mgr, DdNode *n) { DdNode *an = Cudd_BddToAdd(mgr->bdd_manager, n); reference_dd(mgr, an); return an; }
static int compute_prob(void) /* this is the function that implements the compute_prob predicate used in pp.pl */ { YAP_Term out,arg1,arg2,arg3,arg4; array_t * variables,* expression, * bVar2mVar; DdNode * function, * add; DdManager * mgr; int nBVar,i,j,intBits,create_dot; FILE * file; DdNode * array[1]; char * onames[1]; char inames[1000][20]; char * names[1000]; GHashTable * nodes; /* hash table that associates nodes with their probability if already computed, it is defined in glib */ Cudd_ReorderingType order; arg1=YAP_ARG1; arg2=YAP_ARG2; arg3=YAP_ARG3; arg4=YAP_ARG4; mgr=Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); variables=array_alloc(variable,0); bVar2mVar=array_alloc(int,0); create_dot=YAP_IntOfTerm(arg4); createVars(variables,arg1,mgr,bVar2mVar,create_dot,inames); //Cudd_PrintInfo(mgr,stderr); /* automatic variable reordering, default method CUDD_REORDER_SIFT used */ //printf("status %d\n",Cudd_ReorderingStatus(mgr,&order)); //printf("order %d\n",order); Cudd_AutodynEnable(mgr,CUDD_REORDER_SAME); /* Cudd_AutodynEnable(mgr, CUDD_REORDER_RANDOM_PIVOT); printf("status %d\n",Cudd_ReorderingStatus(mgr,&order)); printf("order %d\n",order); printf("%d",CUDD_REORDER_RANDOM_PIVOT); */ expression=array_alloc(array_t *,0); createExpression(expression,arg2); function=retFunction(mgr,expression,variables); /* the BDD build by retFunction is converted to an ADD (algebraic decision diagram) because it is easier to interpret and to print */ add=Cudd_BddToAdd(mgr,function); //Cudd_PrintInfo(mgr,stderr); if (create_dot) /* if specified by the user, a dot file for the BDD is written to cpl.dot */ { nBVar=array_n(bVar2mVar); for(i=0;i<nBVar;i++) names[i]=inames[i]; array[0]=add; onames[0]="Out"; file = open_file("cpl.dot", "w"); Cudd_DumpDot(mgr,1,array,names,onames,file); fclose(file); } nodes=g_hash_table_new(my_hash,my_equal); intBits=sizeof(unsigned int)*8; /* dividend is a global variable used by my_hash it is equal to an unsigned int with binary representation 11..1 */ dividend=1; for(j=1;j<intBits;j++) { dividend=(dividend<<1)+1; } out=YAP_MkFloatTerm(Prob(add,variables,bVar2mVar,nodes)); g_hash_table_foreach (nodes,dealloc,NULL); g_hash_table_destroy(nodes); Cudd_Quit(mgr); array_free(variables); array_free(bVar2mVar); array_free(expression); return(YAP_Unify(out,arg3)); }