/**Function************************************************************* Synopsis [Reorders the DD using REO and CUDD.] Description [This function can be used to test the performance of the reordering package.] SideEffects [] SeeAlso [] ***********************************************************************/ void Extra_ReorderTestArray( DdManager * dd, DdNode * Funcs[], int nFuncs ) { reo_man * pReo; DdNode * FuncsRes[1000]; int pOrder[1000]; int i; pReo = Extra_ReorderInit( 100, 100 ); Extra_ReorderArray( pReo, dd, Funcs, FuncsRes, nFuncs, pOrder ); Extra_ReorderQuit( pReo ); printf( "Initial = %d. Final = %d.\n", Cudd_SharingSize(Funcs,nFuncs), Cudd_SharingSize(FuncsRes,nFuncs) ); for ( i = 0; i < nFuncs; i++ ) Cudd_RecursiveDeref( dd, FuncsRes[i] ); }
/**Function************************************************************* Synopsis [Returns the shared size of global BDDs of the COs.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Aig_ManSizeOfGlobalBdds( Aig_Man_t * p ) { Vec_Ptr_t * vFuncsGlob; Aig_Obj_t * pObj; int RetValue, i; // complement the global functions vFuncsGlob = Vec_PtrAlloc( Aig_ManCoNum(p) ); Aig_ManForEachCo( p, pObj, i ) Vec_PtrPush( vFuncsGlob, Aig_ObjGlobalBdd(pObj) ); RetValue = Cudd_SharingSize( (DdNode **)Vec_PtrArray(vFuncsGlob), Vec_PtrSize(vFuncsGlob) ); Vec_PtrFree( vFuncsGlob ); return RetValue; }
/* Use CUDD to compute number of BDD nodes to represent set of functions */ size_t cudd_size(shadow_mgr mgr, set_ptr roots) { if (!mgr->do_cudd) return 0; size_t nele = roots->nelements; DdNode **croots = calloc_or_fail(nele, sizeof(DdNode *), "cudd_size"); word_t wr; int i = 0; set_iterstart(roots); while (set_iternext(roots, &wr)) { ref_t r = (ref_t) wr; DdNode *n = get_ddnode(mgr, r); croots[i++] = n; } int cnt = Cudd_SharingSize(croots, nele); free_array(croots, nele, sizeof(DdNode *)); return (size_t) cnt; }
/**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void reoReorderArray( reo_man * p, DdManager * dd, DdNode * Funcs[], DdNode * FuncsRes[], int nFuncs, int * pOrder ) { int Counter, i; // set the initial parameters p->dd = dd; p->pOrder = pOrder; p->nTops = nFuncs; // get the initial number of nodes p->nNodesBeg = Cudd_SharingSize( Funcs, nFuncs ); // resize the internal data structures of the manager if necessary reoResizeStructures( p, ddMax(dd->size,dd->sizeZ), p->nNodesBeg, nFuncs ); // compute the support p->pSupp = Extra_VectorSupportArray( dd, Funcs, nFuncs, p->pSupp ); // get the number of support variables p->nSupp = 0; for ( i = 0; i < dd->size; i++ ) p->nSupp += p->pSupp[i]; // if it is the constant function, no need to reorder if ( p->nSupp == 0 ) { for ( i = 0; i < nFuncs; i++ ) { FuncsRes[i] = Funcs[i]; Cudd_Ref( FuncsRes[i] ); } return; } // create the internal variable maps // go through variable levels in the manager Counter = 0; for ( i = 0; i < dd->size; i++ ) if ( p->pSupp[ dd->invperm[i] ] ) { p->pMapToPlanes[ dd->invperm[i] ] = Counter; p->pMapToDdVarsOrig[Counter] = dd->invperm[i]; if ( !p->fRemapUp ) p->pMapToDdVarsFinal[Counter] = dd->invperm[i]; else p->pMapToDdVarsFinal[Counter] = dd->invperm[Counter]; p->pOrderInt[Counter] = Counter; Counter++; } // set the initial parameters p->nUnitsUsed = 0; p->nNodesCur = 0; p->fThisIsAdd = 0; p->Signature++; // transfer the function from the CUDD package into REO"s internal data structure for ( i = 0; i < nFuncs; i++ ) p->pTops[i] = reoTransferNodesToUnits_rec( p, Funcs[i] ); assert( p->nNodesBeg == p->nNodesCur ); if ( !p->fThisIsAdd && p->fMinWidth ) { printf( "An important message from the REO reordering engine:\n" ); printf( "The BDD given to the engine for reordering contains complemented edges.\n" ); printf( "Currently, such BDDs cannot be reordered for the minimum width.\n" ); printf( "Therefore, minimization for the number of BDD nodes is performed.\n" ); fflush( stdout ); p->fMinApl = 0; p->fMinWidth = 0; } if ( p->fMinWidth ) reoProfileWidthStart(p); else if ( p->fMinApl ) reoProfileAplStart(p); else reoProfileNodesStart(p); if ( p->fVerbose ) { printf( "INITIAL: " ); if ( p->fMinWidth ) reoProfileWidthPrint(p); else if ( p->fMinApl ) reoProfileAplPrint(p); else reoProfileNodesPrint(p); } /////////////////////////////////////////////////////////////////// // performs the reordering p->nSwaps = 0; p->nNISwaps = 0; for ( i = 0; i < p->nIters; i++ ) { reoReorderSift( p ); // print statistics after each iteration if ( p->fVerbose ) { printf( "ITER #%d: ", i+1 ); if ( p->fMinWidth ) reoProfileWidthPrint(p); else if ( p->fMinApl ) reoProfileAplPrint(p); else reoProfileNodesPrint(p); } // if the cost function did not change, stop iterating if ( p->fMinWidth ) { p->nWidthEnd = p->nWidthCur; assert( p->nWidthEnd <= p->nWidthBeg ); if ( p->nWidthEnd == p->nWidthBeg ) break; } else if ( p->fMinApl ) { p->nAplEnd = p->nAplCur; assert( p->nAplEnd <= p->nAplBeg ); if ( p->nAplEnd == p->nAplBeg ) break; } else { p->nNodesEnd = p->nNodesCur; assert( p->nNodesEnd <= p->nNodesBeg ); if ( p->nNodesEnd == p->nNodesBeg ) break; } } assert( reoCheckLevels( p ) ); /////////////////////////////////////////////////////////////////// s_AplBefore = p->nAplBeg; s_AplAfter = p->nAplEnd; // set the initial parameters p->nRefNodes = 0; p->nNodesCur = 0; p->Signature++; // transfer the BDDs from REO's internal data structure to CUDD for ( i = 0; i < nFuncs; i++ ) { FuncsRes[i] = reoTransferUnitsToNodes_rec( p, p->pTops[i] ); Cudd_Ref( FuncsRes[i] ); } // undo the DDs referenced for storing in the cache for ( i = 0; i < p->nRefNodes; i++ ) Cudd_RecursiveDeref( dd, p->pRefNodes[i] ); // verify zero refs of the terminal nodes for ( i = 0; i < nFuncs; i++ ) { assert( reoRecursiveDeref( p->pTops[i] ) ); } assert( reoCheckZeroRefs( &(p->pPlanes[p->nSupp]) ) ); // prepare the variable map to return to the user if ( p->pOrder ) { // i is the current level in the planes data structure // p->pOrderInt[i] is the original level in the planes data structure // p->pMapToDdVarsOrig[i] is the variable, into which we remap when we construct the BDD from planes // p->pMapToDdVarsOrig[ p->pOrderInt[i] ] is the original BDD variable corresponding to this level // Therefore, p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ] // creates the permutation, which remaps the resulting BDD variable into the original BDD variable for ( i = 0; i < p->nSupp; i++ ) p->pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ]; } if ( p->fVerify ) { int fVerification; DdNode * FuncRemapped; int * pOrder; if ( p->pOrder == NULL ) { pOrder = ABC_ALLOC( int, p->nSupp ); for ( i = 0; i < p->nSupp; i++ ) pOrder[ p->pMapToDdVarsFinal[i] ] = p->pMapToDdVarsOrig[ p->pOrderInt[i] ]; }
/**Function******************************************************************** Synopsis [Main program for ntr.] Description [Main program for ntr. Performs initialization. Reads command line options and network(s). Builds BDDs with reordering, and optionally does reachability analysis. Prints stats.] SideEffects [None] SeeAlso [] ******************************************************************************/ int main( int argc, char ** argv) { NtrOptions *option; /* options */ FILE *fp1; /* first network file pointer */ BnetNetwork *net1 = NULL; /* first network */ FILE *fp2; /* second network file pointer */ BnetNetwork *net2 = NULL; /* second network */ DdManager *dd; /* pointer to DD manager */ int exitval; /* return value of Cudd_CheckZeroRef */ int ok; /* overall return value from main() */ int result; /* stores the return value of functions */ BnetNode *node; /* auxiliary pointer to network node */ int i; /* loop index */ int j; /* loop index */ double *signatures; /* array of signatures */ int pr; /* verbosity level */ int reencoded; /* linear transformations attempted */ /* Initialize. */ option = mainInit(); ntrReadOptions(argc,argv,option); pr = option->verb; reencoded = option->reordering == CUDD_REORDER_LINEAR || option->reordering == CUDD_REORDER_LINEAR_CONVERGE || option->autoMethod == CUDD_REORDER_LINEAR || option->autoMethod == CUDD_REORDER_LINEAR_CONVERGE; /* Currently traversal requires global BDDs. Override whatever ** was specified for locGlob. */ if (option->traverse == TRUE || option->envelope == TRUE || option->scc == TRUE) { option->locGlob = BNET_GLOBAL_DD; } /* Read the first network... */ fp1 = open_file(option->file1, "r"); net1 = Bnet_ReadNetwork(fp1,pr); (void) fclose(fp1); if (net1 == NULL) { (void) fprintf(stderr,"Syntax error in %s.\n",option->file1); exit(2); } /* ... and optionally echo it to the standard output. */ if (pr > 2) { Bnet_PrintNetwork(net1); } /* Read the second network... */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares) { fp2 = open_file(option->file2, "r"); net2 = Bnet_ReadNetwork(fp2,pr); (void) fclose(fp2); if (net2 == NULL) { (void) fprintf(stderr,"Syntax error in %s.\n",option->file2); exit(2); } /* ... and optionally echo it to the standard output. */ if (pr > 2) { Bnet_PrintNetwork(net2); } } /* Initialize manager. We start with 0 variables, because ** Ntr_buildDDs will create new variables rather than using ** whatever already exists. */ dd = startCudd(option,net1->ninputs); if (dd == NULL) { exit(2); } /* Build the BDDs for the nodes of the first network. */ result = Ntr_buildDDs(net1,dd,option,NULL); if (result == 0) { exit(2); } /* Build the BDDs for the nodes of the second network if requested. */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares == TRUE) { char *nodesave = option->node; option->node = NULL; result = Ntr_buildDDs(net2,dd,option,net1); option->node = nodesave; if (result == 0) { exit(2); } } if (option->noBuild == TRUE) { Bnet_FreeNetwork(net1); if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0) { Bnet_FreeNetwork(net2); } freeOption(option); exit(0); } if (option->locGlob != BNET_LOCAL_DD) { /* Print the order before the final reordering. */ (void) printf("Order before final reordering\n"); result = Bnet_PrintOrder(net1,dd); if (result == 0) exit(2); } /* Perform final reordering */ if (option->zddtest == FALSE) { result = reorder(net1,dd,option); if (result == 0) exit(2); /* Print final order. */ if ((option->reordering != CUDD_REORDER_NONE || option->gaOnOff) && option->locGlob != BNET_LOCAL_DD) { (void) printf("New order\n"); result = Bnet_PrintOrder(net1,dd); if (result == 0) exit(2); } /* Print the re-encoded inputs. */ if (pr >= 1 && reencoded == 1) { for (i = 0; i < net1->npis; i++) { if (!st_lookup(net1->hash,net1->inputs[i],&node)) { exit(2); } (void) fprintf(stdout,"%s:",node->name); Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr); } for (i = 0; i < net1->nlatches; i++) { if (!st_lookup(net1->hash,net1->latches[i][1],&node)) { exit(2); } (void) fprintf(stdout,"%s:",node->name); Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr); } if (pr >= 3) { result = Cudd_PrintLinear(dd); if (result == 0) exit(2); } } } /* Verify (combinational) equivalence. */ if (option->verify == TRUE) { result = Ntr_VerifyEquivalence(dd,net1,net2,option); if (result == 0) { (void) printf("Verification abnormally terminated\n"); exit(2); } else if (result == -1) { (void) printf("Combinational verification failed\n"); } else { (void) printf("Verification succeeded\n"); } } /* Traverse if requested and if the circuit is sequential. */ result = Ntr_Trav(dd,net1,option); if (result == 0) exit(2); /* Traverse with trasitive closure. */ result = Ntr_ClosureTrav(dd,net1,option); if (result == 0) exit(2); /* Compute outer envelope if requested and if the circuit is sequential. */ if (option->envelope == TRUE && net1->nlatches > 0) { NtrPartTR *T; T = Ntr_buildTR(dd,net1,option,option->image); result = Ntr_Envelope(dd,T,NULL,option); Ntr_freeTR(dd,T); } /* Compute SCCs if requested and if the circuit is sequential. */ result = Ntr_SCC(dd,net1,option); if (result == 0) exit(2); /* Test Constrain Decomposition. */ if (option->partition == TRUE && net1->nlatches > 0) { NtrPartTR *T; DdNode *product; DdNode **decomp; int sharingSize; T = Ntr_buildTR(dd,net1,option,NTR_IMAGE_MONO); decomp = Cudd_bddConstrainDecomp(dd,T->part[0]); if (decomp == NULL) exit(2); sharingSize = Cudd_SharingSize(decomp, Cudd_ReadSize(dd)); (void) fprintf(stdout, "Decomposition Size: %d components %d nodes\n", Cudd_ReadSize(dd), sharingSize); product = Cudd_ReadOne(dd); Cudd_Ref(product); for (i = 0; i < Cudd_ReadSize(dd); i++) { DdNode *intermediate = Cudd_bddAnd(dd, product, decomp[i]); if (intermediate == NULL) { exit(2); } Cudd_Ref(intermediate); Cudd_IterDerefBdd(dd, product); product = intermediate; } if (product != T->part[0]) exit(2); Cudd_IterDerefBdd(dd, product); for (i = 0; i < Cudd_ReadSize(dd); i++) { Cudd_IterDerefBdd(dd, decomp[i]); } FREE(decomp); Ntr_freeTR(dd,T); } /* Test char-to-vect conversion. */ result = Ntr_TestCharToVect(dd,net1,option); if (result == 0) exit(2); /* Test extraction of two-literal clauses. */ result = Ntr_TestTwoLiteralClauses(dd,net1,option); if (result == 0) exit(2); /* Test BDD minimization functions. */ result = Ntr_TestMinimization(dd,net1,net2,option); if (result == 0) exit(2); /* Test density-related functions. */ result = Ntr_TestDensity(dd,net1,option); if (result == 0) exit(2); /* Test decomposition functions. */ result = Ntr_TestDecomp(dd,net1,option); if (result == 0) exit(2); /* Test cofactor estimation functions. */ result = Ntr_TestCofactorEstimate(dd,net1,option); if (result == 0) exit(2); /* Test BDD clipping functions. */ result = Ntr_TestClipping(dd,net1,net2,option); if (result == 0) exit(2); /* Test BDD equivalence and containment under DC functions. */ result = Ntr_TestEquivAndContain(dd,net1,net2,option); if (result == 0) exit(2); /* Test BDD Cudd_bddClosestCube. */ result = Ntr_TestClosestCube(dd,net1,option); if (result == 0) exit(2); /* Test ZDDs if requested. */ if (option->stateOnly == FALSE && option->zddtest == TRUE) { result = Ntr_testZDD(dd,net1,option); if (result == 0) (void) fprintf(stdout,"ZDD test failed.\n"); result = Ntr_testISOP(dd,net1,option); if (result == 0) (void) fprintf(stdout,"ISOP test failed.\n"); } /* Compute maximum flow if requested and if the circuit is sequential. */ if (option->maxflow == TRUE && net1->nlatches > 0) { result = Ntr_maxflow(dd,net1,option); if (result == 0) (void) fprintf(stdout,"Maxflow computation failed.\n"); } /* Compute shortest paths if requested and if the circuit is sequential. */ if (option->shortPath != NTR_SHORT_NONE && net1->nlatches > 0) { result = Ntr_ShortestPaths(dd,net1,option); if (result == 0) (void) fprintf(stdout,"Shortest paths computation failed.\n"); } /* Compute output signatures if so requested. */ if (option->signatures) { (void) printf("Positive cofactor measures\n"); for (i = 0; i < net1->noutputs; i++) { if (!st_lookup(net1->hash,net1->outputs[i],&node)) { exit(2); } signatures = Cudd_CofMinterm(dd, node->dd); if (signatures) { (void) printf("%s:\n", node->name); for (j = 0; j < Cudd_ReadSize(dd); j++) { if((j%5 == 0)&&i) (void) printf("\n"); (void) printf("%5d: %-#8.4g ", j, signatures[j]); } (void) printf("\n"); FREE(signatures); } else { (void) printf("Signature computation failed.\n"); } } } /* Dump BDDs if so requested. */ if (option->bdddump && option->second == FALSE && option->density == FALSE && option->decomp == FALSE && option->cofest == FALSE && option->clip < 0.0 && option->scc == FALSE) { (void) printf("Dumping BDDs to %s\n", option->dumpfile); if (option->node != NULL) { if (!st_lookup(net1->hash,option->node,&node)) { exit(2); } result = Bnet_bddArrayDump(dd,net1,option->dumpfile,&(node->dd), &(node->name),1,option->dumpFmt); } else { result = Bnet_bddDump(dd, net1, option->dumpfile, option->dumpFmt, reencoded); } if (result != 1) { (void) printf("BDD dump failed.\n"); } } /* Print stats and clean up. */ if (pr >= 0) { result = Cudd_PrintInfo(dd,stdout); if (result != 1) { (void) printf("Cudd_PrintInfo failed.\n"); } } #if defined(DD_DEBUG) && !defined(DD_NO_DEATH_ROW) (void) fprintf(dd->err,"%d empty slots in death row\n", cuddTimesInDeathRow(dd,NULL)); #endif (void) printf("Final size: %ld\n", Cudd_ReadNodeCount(dd)); /* Dispose of node BDDs. */ node = net1->nodes; while (node != NULL) { if (node->dd != NULL && node->type != BNET_INPUT_NODE && node->type != BNET_PRESENT_STATE_NODE) { Cudd_IterDerefBdd(dd,node->dd); } node = node->next; } /* Dispose of network. */ Bnet_FreeNetwork(net1); /* Do the same cleanup for the second network if it was created. */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares == TRUE) { node = net2->nodes; while (node != NULL) { if (node->dd != NULL && node->type != BNET_INPUT_NODE && node->type != BNET_PRESENT_STATE_NODE) { Cudd_IterDerefBdd(dd,node->dd); } node = node->next; } Bnet_FreeNetwork(net2); } /* Check reference counts: At this point we should have dereferenced ** everything we had, except in the case of re-encoding. */ exitval = Cudd_CheckZeroRef(dd); ok = exitval != 0; /* ok == 0 means O.K. */ if (exitval != 0) { (void) fflush(stdout); (void) fprintf(stderr, "%d non-zero DD reference counts after dereferencing\n", exitval); } #ifdef DD_DEBUG Cudd_CheckKeys(dd); #endif Cudd_Quit(dd); if (pr >= 0) (void) printf("total time = %s\n", util_print_time(util_cpu_time() - option->initialTime)); freeOption(option); if (pr >= 0) util_print_cpu_stats(stdout); #ifdef MNEMOSYNE mnem_writestats(); #endif exit(ok); /* NOTREACHED */ } /* end of main */