/**Function******************************************************************** Synopsis [Computes the classical symmetry information for the function.] Description [Uses the naive way of comparing cofactors.] SideEffects [] SeeAlso [] ******************************************************************************/ Extra_SymmInfo_t * Extra_SymmPairsComputeNaive( DdManager * dd, DdNode * bFunc ) { DdNode * bSupp, * bTemp; int nSuppSize; Extra_SymmInfo_t * p; int i, k; // compute the support bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); nSuppSize = Extra_bddSuppSize( dd, bSupp ); //printf( "Support = %d. ", nSuppSize ); //Extra_bddPrint( dd, bSupp ); //printf( "%d ", nSuppSize ); // allocate the storage for symmetry info p = Extra_SymmPairsAllocate( nSuppSize ); // assign the variables p->nVarsMax = dd->size; for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ ) p->pVars[i] = bTemp->index; // go through the candidate pairs and check using Idea1 for ( i = 0; i < nSuppSize; i++ ) for ( k = i+1; k < nSuppSize; k++ ) { p->pSymms[k][i] = p->pSymms[i][k] = Extra_bddCheckVarsSymmetricNaive( dd, bFunc, p->pVars[i], p->pVars[k] ); if ( p->pSymms[i][k] ) p->nSymms++; } Cudd_RecursiveDeref( dd, bSupp ); return p; } /* end of Extra_SymmPairsComputeNaive */
/**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 ); }
/**Function************************************************************* Synopsis [Computes supports of the partitions.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Ptr_t * Llb_ImgSupports( Aig_Man_t * p, Vec_Ptr_t * vDdMans, Vec_Int_t * vStart, Vec_Int_t * vStop, int fAddPis, int fVerbose ) { Vec_Ptr_t * vSupps; Vec_Int_t * vOne; Aig_Obj_t * pObj; DdManager * dd; DdNode * bSupp, * bTemp; int i, Entry, nSize; nSize = Cudd_ReadSize( (DdManager *)Vec_PtrEntry( vDdMans, 0 ) ); vSupps = Vec_PtrAlloc( 100 ); // create initial vOne = Vec_IntStart( nSize ); Vec_IntForEachEntry( vStart, Entry, i ) Vec_IntWriteEntry( vOne, Entry, 1 ); Vec_PtrPush( vSupps, vOne ); // create intermediate Vec_PtrForEachEntry( DdManager *, vDdMans, dd, i ) { vOne = Vec_IntStart( nSize ); bSupp = Cudd_Support( dd, dd->bFunc ); Cudd_Ref( bSupp ); for ( bTemp = bSupp; bTemp != Cudd_ReadOne(dd); bTemp = cuddT(bTemp) ) Vec_IntWriteEntry( vOne, bTemp->index, 1 ); Cudd_RecursiveDeref( dd, bSupp ); Vec_PtrPush( vSupps, vOne ); }
/**Function************************************************************* Synopsis [Prints the latch dependency matrix.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Extra_bddImagePrintLatchDependency( DdManager * dd, DdNode * bCare, // the care set int nParts, DdNode ** pbParts, // the partitions for image computation int nVars, DdNode ** pbVars ) // the NS and parameter variables (not quantified!) { int i; DdNode * bVarsCs, * bVarsNs; bVarsCs = Cudd_Support( dd, bCare ); Cudd_Ref( bVarsCs ); bVarsNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bVarsNs ); printf( "The latch dependency matrix:\n" ); printf( "Partitions = %d Variables: total = %d non-quantifiable = %d\n", nParts, dd->size, nVars ); printf( " : " ); for ( i = 0; i < dd->size; i++ ) printf( "%d", i % 10 ); printf( "\n" ); for ( i = 0; i < nParts; i++ ) Extra_bddImagePrintLatchDependencyOne( dd, pbParts[i], bVarsCs, bVarsNs, i ); Extra_bddImagePrintLatchDependencyOne( dd, bCare, bVarsCs, bVarsNs, nParts ); Cudd_RecursiveDeref( dd, bVarsCs ); Cudd_RecursiveDeref( dd, bVarsNs ); }
/**Function************************************************************* Synopsis [Constructs the network isomorphic to the given BDD.] Description [Assumes that the BDD depends on the variables whose indexes correspond to the names in the array (pNamesPi). Otherwise, returns NULL. The resulting network comes with one node, whose functionality is equal to the given BDD. To decompose this BDD into the network of multiplexers use Abc_NtkBddToMuxes(). To decompose this BDD into an And-Inverter Graph, use Abc_NtkStrash().] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Ntk_t * Abc_NtkDeriveFromBdd( void * dd0, void * bFunc, char * pNamePo, Vec_Ptr_t * vNamesPi ) { DdManager * dd = (DdManager *)dd0; Abc_Ntk_t * pNtk; Vec_Ptr_t * vNamesPiFake = NULL; Abc_Obj_t * pNode, * pNodePi, * pNodePo; DdNode * bSupp, * bTemp; char * pName; int i; // supply fake names if real names are not given if ( pNamePo == NULL ) pNamePo = "F"; if ( vNamesPi == NULL ) { vNamesPiFake = Abc_NodeGetFakeNames( dd->size ); vNamesPi = vNamesPiFake; } // make sure BDD depends on the variables whose index // does not exceed the size of the array with PI names bSupp = Cudd_Support( dd, (DdNode *)bFunc ); Cudd_Ref( bSupp ); for ( bTemp = bSupp; bTemp != Cudd_ReadOne(dd); bTemp = cuddT(bTemp) ) if ( (int)Cudd_NodeReadIndex(bTemp) >= Vec_PtrSize(vNamesPi) ) break; Cudd_RecursiveDeref( dd, bSupp ); if ( bTemp != Cudd_ReadOne(dd) ) return NULL; // start the network pNtk = Abc_NtkAlloc( ABC_NTK_LOGIC, ABC_FUNC_BDD, 1 ); pNtk->pName = Extra_UtilStrsav(pNamePo); // make sure the new manager has enough inputs Cudd_bddIthVar( (DdManager *)pNtk->pManFunc, Vec_PtrSize(vNamesPi) ); // add the PIs corresponding to the names Vec_PtrForEachEntry( char *, vNamesPi, pName, i ) Abc_ObjAssignName( Abc_NtkCreatePi(pNtk), pName, NULL ); // create the node pNode = Abc_NtkCreateNode( pNtk ); pNode->pData = (DdNode *)Cudd_bddTransfer( dd, (DdManager *)pNtk->pManFunc, (DdNode *)bFunc ); Cudd_Ref((DdNode *)pNode->pData); Abc_NtkForEachPi( pNtk, pNodePi, i ) Abc_ObjAddFanin( pNode, pNodePi ); // create the only PO pNodePo = Abc_NtkCreatePo( pNtk ); Abc_ObjAddFanin( pNodePo, pNode ); Abc_ObjAssignName( pNodePo, pNamePo, NULL ); // make the network minimum base Abc_NtkMinimumBase( pNtk ); if ( vNamesPiFake ) Abc_NodeFreeNames( vNamesPiFake ); if ( !Abc_NtkCheck( pNtk ) ) fprintf( stdout, "Abc_NtkDeriveFromBdd(): Network check has failed.\n" ); return pNtk; }
/**Function************************************************************* Synopsis [Starts the image computation using tree-based scheduling.] Description [This procedure starts the image computation. It uses the given care set to test-run the image computation and creates the quantification tree by scheduling variable quantifications. The tree can be used to compute images for other care sets without rescheduling. In this case, Extra_bddImageCompute() should be called.] SideEffects [] SeeAlso [] ***********************************************************************/ Extra_ImageTree_t * Extra_bddImageStart( DdManager * dd, DdNode * bCare, // the care set int nParts, DdNode ** pbParts, // the partitions for image computation int nVars, DdNode ** pbVars, int fVerbose ) // the NS and parameter variables (not quantified!) { Extra_ImageTree_t * pTree; Extra_ImagePart_t ** pParts; Extra_ImageVar_t ** pVars; Extra_ImageNode_t ** pNodes; int v; if ( fVerbose && dd->size <= 80 ) Extra_bddImagePrintLatchDependency( dd, bCare, nParts, pbParts, nVars, pbVars ); // create variables, partitions and leaf nodes pParts = Extra_CreateParts( dd, nParts, pbParts, bCare ); pVars = Extra_CreateVars( dd, nParts + 1, pParts, nVars, pbVars ); pNodes = Extra_CreateNodes( dd, nParts + 1, pParts, dd->size, pVars ); // create the tree pTree = ABC_ALLOC( Extra_ImageTree_t, 1 ); memset( pTree, 0, sizeof(Extra_ImageTree_t) ); pTree->pCare = pNodes[nParts]; pTree->fVerbose = fVerbose; // process the nodes while ( Extra_BuildTreeNode( dd, nParts + 1, pNodes, dd->size, pVars ) ); // make sure the variables are gone for ( v = 0; v < dd->size; v++ ) assert( pVars[v] == NULL ); ABC_FREE( pVars ); // merge the topmost nodes while ( (pTree->pRoot = Extra_MergeTopNodes( dd, nParts + 1, pNodes )) == NULL ); // make sure the nodes are gone for ( v = 0; v < nParts + 1; v++ ) assert( pNodes[v] == NULL ); ABC_FREE( pNodes ); // if ( fVerbose ) // Extra_bddImagePrintTree( pTree ); // set the support of the care set pTree->bCareSupp = Cudd_Support( dd, bCare ); Cudd_Ref( pTree->bCareSupp ); // clean the partitions Extra_DeleteParts_rec( pTree->pRoot ); ABC_FREE( pParts ); return pTree; }
/**Function************************************************************* Synopsis [Compute the image.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * Extra_bddImageCompute( Extra_ImageTree_t * pTree, DdNode * bCare ) { DdManager * dd = pTree->pCare->dd; DdNode * bSupp, * bRem; pTree->nIter++; // make sure the supports are okay bSupp = Cudd_Support( dd, bCare ); Cudd_Ref( bSupp ); if ( bSupp != pTree->bCareSupp ) { bRem = Cudd_bddExistAbstract( dd, bSupp, pTree->bCareSupp ); Cudd_Ref( bRem ); if ( bRem != b1 ) { printf( "Original care set support: " ); ABC_PRB( dd, pTree->bCareSupp ); printf( "Current care set support: " ); ABC_PRB( dd, bSupp ); Cudd_RecursiveDeref( dd, bSupp ); Cudd_RecursiveDeref( dd, bRem ); printf( "The care set depends on some vars that were not in the care set during scheduling.\n" ); return NULL; } Cudd_RecursiveDeref( dd, bRem ); } Cudd_RecursiveDeref( dd, bSupp ); // remove the previous image Cudd_RecursiveDeref( dd, pTree->pCare->bImage ); pTree->pCare->bImage = bCare; Cudd_Ref( bCare ); // compute the image pTree->nNodesMax = 0; Extra_bddImageCompute_rec( pTree, pTree->pRoot ); if ( pTree->nNodesMaxT < pTree->nNodesMax ) pTree->nNodesMaxT = pTree->nNodesMax; // if ( pTree->fVerbose ) // printf( "Iter %2d : Max nodes = %5d.\n", pTree->nIter, pTree->nNodesMax ); return pTree->pRoot->bImage; }
/**Function******************************************************************** Synopsis [Computes the compatible projection of R w.r.t. cube Y.] Description [Computes the compatible projection of relation R with respect to cube Y. Returns a pointer to the c-projection if successful; NULL otherwise. For a comparison between Cudd_CProjection and Cudd_PrioritySelect, see the documentation of the latter.] SideEffects [None] SeeAlso [Cudd_PrioritySelect] ******************************************************************************/ DdNode * Cudd_CProjection( DdManager * dd, DdNode * R, DdNode * Y) { DdNode *res; DdNode *support; if (cuddCheckCube(dd,Y) == 0) { (void) fprintf(dd->err, "Error: The third argument of Cudd_CProjection should be a cube\n"); dd->errorCode = CUDD_INVALID_ARG; return(NULL); } /* Compute the support of Y, which is used by the abstraction step ** in cuddCProjectionRecur. */ support = Cudd_Support(dd,Y); if (support == NULL) return(NULL); cuddRef(support); do { dd->reordered = 0; res = cuddCProjectionRecur(dd,R,Y,support); } while (dd->reordered == 1); if (res == NULL) { Cudd_RecursiveDeref(dd,support); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd,support); cuddDeref(res); return(res); } /* end of Cudd_CProjection */
ABC_NAMESPACE_IMPL_START /*---------------------------------------------------------------------------*/ /* Constant declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Stucture declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Type declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Variable declarations */ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ /* Macro declarations */ /*---------------------------------------------------------------------------*/ #define DD_GET_SYMM_VARS_TAG 0x0a /* former DD_BDD_XOR_EXIST_ABSTRACT_TAG */ /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Computes the classical symmetry information for the function.] Description [Returns the symmetry information in the form of Extra_SymmInfo_t structure.] SideEffects [If the ZDD variables are not derived from BDD variables with multiplicity 2, this function may derive them in a wrong way.] SeeAlso [] ******************************************************************************/ Extra_SymmInfo_t * Extra_SymmPairsCompute( DdManager * dd, /* the manager */ DdNode * bFunc) /* the function whose symmetries are computed */ { DdNode * bSupp; DdNode * zRes; Extra_SymmInfo_t * p; bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp ); zRes = Extra_zddSymmPairsCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes ); p = Extra_SymmPairsCreateFromZdd( dd, zRes, bSupp ); Cudd_RecursiveDeref( dd, bSupp ); Cudd_RecursiveDerefZdd( dd, zRes ); return p; } /* end of Extra_SymmPairsCompute */
/**Function******************************************************************** Synopsis [Writes a dot file representing the argument ZDDs.] Description [Writes a file representing the argument ZDDs in a format suitable for the graph drawing program dot. It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file system full). Cudd_zddDumpDot does not close the file: This is the caller responsibility. Cudd_zddDumpDot uses a minimal unique subset of the hexadecimal address of a node as name for it. If the argument inames is non-null, it is assumed to hold the pointers to the names of the inputs. Similarly for onames. Cudd_zddDumpDot uses the following convention to draw arcs: <ul> <li> solid line: THEN arcs; <li> dashed line: ELSE arcs. </ul> The dot options are chosen so that the drawing fits on a letter-size sheet. ] SideEffects [None] SeeAlso [Cudd_DumpDot Cudd_zddPrintDebug] ******************************************************************************/ int Cudd_zddDumpDot( DdManager * dd /* manager */, int n /* number of output nodes to be dumped */, DdNode ** f /* array of output nodes to be dumped */, char ** inames /* array of input names (or NULL) */, char ** onames /* array of output names (or NULL) */, FILE * fp /* pointer to the dump file */) { DdNode *support = NULL; DdNode *scan; int *sorted = NULL; int nvars = dd->sizeZ; st_table *visited = NULL; st_generator *gen; int retval; int i, j; int slots; DdNodePtr *nodelist; long refAddr, diff, mask; /* Build a bit array with the support of f. */ sorted = ALLOC(int,nvars); if (sorted == NULL) { dd->errorCode = CUDD_MEMORY_OUT; goto failure; } for (i = 0; i < nvars; i++) sorted[i] = 0; /* Take the union of the supports of each output function. */ for (i = 0; i < n; i++) { support = Cudd_Support(dd,f[i]); if (support == NULL) goto failure; cuddRef(support); scan = support; while (!cuddIsConstant(scan)) { sorted[scan->index] = 1; scan = cuddT(scan); } Cudd_RecursiveDeref(dd,support); } support = NULL; /* so that we do not try to free it in case of failure */ /* Initialize symbol table for visited nodes. */ visited = st_init_table(st_ptrcmp, st_ptrhash); if (visited == NULL) goto failure; /* Collect all the nodes of this DD in the symbol table. */ for (i = 0; i < n; i++) { retval = cuddCollectNodes(f[i],visited); if (retval == 0) goto failure; } /* Find how many most significant hex digits are identical ** in the addresses of all the nodes. Build a mask based ** on this knowledge, so that digits that carry no information ** will not be printed. This is done in two steps. ** 1. We scan the symbol table to find the bits that differ ** in at least 2 addresses. ** 2. We choose one of the possible masks. There are 8 possible ** masks for 32-bit integer, and 16 possible masks for 64-bit ** integers. */ /* Find the bits that are different. */ refAddr = (long) f[0]; diff = 0; gen = st_init_gen(visited); while (st_gen(gen, (char **) &scan, NULL)) { diff |= refAddr ^ (long) scan; } st_free_gen(gen); /* Choose the mask. */ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) { mask = (1 << i) - 1; if (diff <= mask) break; } /* Write the header and the global attributes. */ retval = fprintf(fp,"digraph \"ZDD\" {\n"); if (retval == EOF) return(0); retval = fprintf(fp, "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n"); if (retval == EOF) return(0); /* Write the input name subgraph by scanning the support array. */ retval = fprintf(fp,"{ node [shape = plaintext];\n"); if (retval == EOF) goto failure; retval = fprintf(fp," edge [style = invis];\n"); if (retval == EOF) goto failure; /* We use a name ("CONST NODES") with an embedded blank, because ** it is unlikely to appear as an input name. */ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n"); if (retval == EOF) goto failure; for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { if (inames == NULL) { retval = fprintf(fp,"\" %d \" -> ", dd->invpermZ[i]); } else { retval = fprintf(fp,"\" %s \" -> ", inames[dd->invpermZ[i]]); } if (retval == EOF) goto failure; } } retval = fprintf(fp,"\"CONST NODES\"; \n}\n"); if (retval == EOF) goto failure; /* Write the output node subgraph. */ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n"); if (retval == EOF) goto failure; for (i = 0; i < n; i++) { if (onames == NULL) { retval = fprintf(fp,"\"F%d\"", i); } else { retval = fprintf(fp,"\" %s \"", onames[i]); } if (retval == EOF) goto failure; if (i == n - 1) { retval = fprintf(fp,"; }\n"); } else { retval = fprintf(fp," -> "); } if (retval == EOF) goto failure; } /* Write rank info: All nodes with the same index have the same rank. */ for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { retval = fprintf(fp,"{ rank = same; "); if (retval == EOF) goto failure; if (inames == NULL) { retval = fprintf(fp,"\" %d \";\n", dd->invpermZ[i]); } else { retval = fprintf(fp,"\" %s \";\n", inames[dd->invpermZ[i]]); } if (retval == EOF) goto failure; nodelist = dd->subtableZ[i].nodelist; slots = dd->subtableZ[i].slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } retval = fprintf(fp,"}\n"); if (retval == EOF) goto failure; } } /* All constants have the same rank. */ retval = fprintf(fp, "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; "); if (retval == EOF) goto failure; nodelist = dd->constants.nodelist; slots = dd->constants.slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } retval = fprintf(fp,"}\n}\n"); if (retval == EOF) goto failure; /* Write edge info. */ /* Edges from the output nodes. */ for (i = 0; i < n; i++) { if (onames == NULL) { retval = fprintf(fp,"\"F%d\"", i); } else { retval = fprintf(fp,"\" %s \"", onames[i]); } if (retval == EOF) goto failure; retval = fprintf(fp," -> \"%lx\" [style = solid];\n", (mask & (long) f[i]) / sizeof(DdNode)); if (retval == EOF) goto failure; } /* Edges from internal nodes. */ for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { nodelist = dd->subtableZ[i].nodelist; slots = dd->subtableZ[i].slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp, "\"%lx\" -> \"%lx\";\n", (mask & (long) scan) / sizeof(DdNode), (mask & (long) cuddT(scan)) / sizeof(DdNode)); if (retval == EOF) goto failure; retval = fprintf(fp, "\"%lx\" -> \"%lx\" [style = dashed];\n", (mask & (long) scan) / sizeof(DdNode), (mask & (long) cuddE(scan)) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } } } /* Write constant labels. */ nodelist = dd->constants.nodelist; slots = dd->constants.slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n", (mask & (long) scan) / sizeof(DdNode), cuddV(scan)); if (retval == EOF) goto failure; } scan = scan->next; } } /* Write trailer and return. */ retval = fprintf(fp,"}\n"); if (retval == EOF) goto failure; st_free_table(visited); FREE(sorted); return(1); failure: if (sorted != NULL) FREE(sorted); if (support != NULL) Cudd_RecursiveDeref(dd,support); if (visited != NULL) st_free_table(visited); return(0); } /* end of Cudd_zddDumpBlif */