| /**CFile**************************************************************** |
| |
| FileName [extraBddImage.c] |
| |
| PackageName [extra] |
| |
| Synopsis [Various reusable software utilities.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - September 1, 2003.] |
| |
| Revision [$Id: extraBddImage.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "extraBdd.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| /* |
| The ideas implemented in this file are inspired by the paper: |
| Pankaj Chauhan, Edmund Clarke, Somesh Jha, Jim Kukula, Tom Shiple, |
| Helmut Veith, Dong Wang. Non-linear Quantification Scheduling in |
| Image Computation. ICCAD, 2001. |
| */ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Constant declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Stucture declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| typedef struct Extra_ImageNode_t_ Extra_ImageNode_t; |
| typedef struct Extra_ImagePart_t_ Extra_ImagePart_t; |
| typedef struct Extra_ImageVar_t_ Extra_ImageVar_t; |
| |
| struct Extra_ImageTree_t_ |
| { |
| Extra_ImageNode_t * pRoot; // the root of quantification tree |
| Extra_ImageNode_t * pCare; // the leaf node with the care set |
| DdNode * bCareSupp; // the cube to quantify from the care |
| int fVerbose; // the verbosity flag |
| int nNodesMax; // the max number of nodes in one iter |
| int nNodesMaxT; // the overall max number of nodes |
| int nIter; // the number of iterations with this tree |
| }; |
| |
| struct Extra_ImageNode_t_ |
| { |
| DdManager * dd; // the manager |
| DdNode * bCube; // the cube to quantify |
| DdNode * bImage; // the partial image |
| Extra_ImageNode_t * pNode1; // the first branch |
| Extra_ImageNode_t * pNode2; // the second branch |
| Extra_ImagePart_t * pPart; // the partition (temporary) |
| }; |
| |
| struct Extra_ImagePart_t_ |
| { |
| DdNode * bFunc; // the partition |
| DdNode * bSupp; // the support of this partition |
| int nNodes; // the number of BDD nodes |
| short nSupp; // the number of support variables |
| short iPart; // the number of this partition |
| }; |
| |
| struct Extra_ImageVar_t_ |
| { |
| int iNum; // the BDD index of this variable |
| DdNode * bParts; // the partition numbers |
| int nParts; // the number of partitions |
| }; |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Type declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Variable declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Macro declarations */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**AutomaticStart*************************************************************/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Static function prototypes */ |
| /*---------------------------------------------------------------------------*/ |
| |
| static Extra_ImagePart_t ** Extra_CreateParts( DdManager * dd, |
| int nParts, DdNode ** pbParts, DdNode * bCare ); |
| static Extra_ImageVar_t ** Extra_CreateVars( DdManager * dd, |
| int nParts, Extra_ImagePart_t ** pParts, |
| int nVars, DdNode ** pbVarsNs ); |
| static Extra_ImageNode_t ** Extra_CreateNodes( DdManager * dd, |
| int nParts, Extra_ImagePart_t ** pParts, |
| int nVars, Extra_ImageVar_t ** pVars ); |
| static void Extra_DeleteParts_rec( Extra_ImageNode_t * pNode ); |
| static int Extra_BuildTreeNode( DdManager * dd, |
| int nNodes, Extra_ImageNode_t ** pNodes, |
| int nVars, Extra_ImageVar_t ** pVars ); |
| static Extra_ImageNode_t * Extra_MergeTopNodes( DdManager * dd, |
| int nNodes, Extra_ImageNode_t ** pNodes ); |
| static void Extra_bddImageTreeDelete_rec( Extra_ImageNode_t * pNode ); |
| static void Extra_bddImageCompute_rec( Extra_ImageTree_t * pTree, Extra_ImageNode_t * pNode ); |
| static int Extra_FindBestVariable( DdManager * dd, |
| int nNodes, Extra_ImageNode_t ** pNodes, |
| int nVars, Extra_ImageVar_t ** pVars ); |
| static void Extra_FindBestPartitions( DdManager * dd, DdNode * bParts, |
| int nNodes, Extra_ImageNode_t ** pNodes, |
| int * piNode1, int * piNode2 ); |
| static Extra_ImageNode_t * Extra_CombineTwoNodes( DdManager * dd, DdNode * bCube, |
| Extra_ImageNode_t * pNode1, Extra_ImageNode_t * pNode2 ); |
| |
| static void Extra_bddImagePrintLatchDependency( DdManager * dd, DdNode * bCare, |
| int nParts, DdNode ** pbParts, |
| int nVars, DdNode ** pbVars ); |
| static void Extra_bddImagePrintLatchDependencyOne( DdManager * dd, DdNode * bFunc, |
| DdNode * bVarsCs, DdNode * bVarsNs, int iPart ); |
| |
| static void Extra_bddImagePrintTree( Extra_ImageTree_t * pTree ); |
| static void Extra_bddImagePrintTree_rec( Extra_ImageNode_t * pNode, int nOffset ); |
| |
| |
| /**AutomaticEnd***************************************************************/ |
| |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of exported functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**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 [Delete the tree.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImageTreeDelete( Extra_ImageTree_t * pTree ) |
| { |
| if ( pTree->bCareSupp ) |
| Cudd_RecursiveDeref( pTree->pRoot->dd, pTree->bCareSupp ); |
| Extra_bddImageTreeDelete_rec( pTree->pRoot ); |
| ABC_FREE( pTree ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads the image from the tree.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Extra_bddImageRead( Extra_ImageTree_t * pTree ) |
| { |
| return pTree->pRoot->bImage; |
| } |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of internal functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /*---------------------------------------------------------------------------*/ |
| /* Definition of static Functions */ |
| /*---------------------------------------------------------------------------*/ |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates partitions.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImagePart_t ** Extra_CreateParts( DdManager * dd, |
| int nParts, DdNode ** pbParts, DdNode * bCare ) |
| { |
| Extra_ImagePart_t ** pParts; |
| int i; |
| |
| // start the partitions |
| pParts = ABC_ALLOC( Extra_ImagePart_t *, nParts + 1 ); |
| // create structures for each variable |
| for ( i = 0; i < nParts; i++ ) |
| { |
| pParts[i] = ABC_ALLOC( Extra_ImagePart_t, 1 ); |
| pParts[i]->bFunc = pbParts[i]; Cudd_Ref( pParts[i]->bFunc ); |
| pParts[i]->bSupp = Cudd_Support( dd, pParts[i]->bFunc ); Cudd_Ref( pParts[i]->bSupp ); |
| pParts[i]->nSupp = Extra_bddSuppSize( dd, pParts[i]->bSupp ); |
| pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); |
| pParts[i]->iPart = i; |
| } |
| // add the care set as the last partition |
| pParts[nParts] = ABC_ALLOC( Extra_ImagePart_t, 1 ); |
| pParts[nParts]->bFunc = bCare; Cudd_Ref( pParts[nParts]->bFunc ); |
| pParts[nParts]->bSupp = Cudd_Support( dd, pParts[nParts]->bFunc ); Cudd_Ref( pParts[nParts]->bSupp ); |
| pParts[nParts]->nSupp = Extra_bddSuppSize( dd, pParts[nParts]->bSupp ); |
| pParts[nParts]->nNodes = Cudd_DagSize( pParts[nParts]->bFunc ); |
| pParts[nParts]->iPart = nParts; |
| return pParts; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImageVar_t ** Extra_CreateVars( DdManager * dd, |
| int nParts, Extra_ImagePart_t ** pParts, |
| int nVars, DdNode ** pbVars ) |
| { |
| Extra_ImageVar_t ** pVars; |
| DdNode ** pbFuncs; |
| DdNode * bCubeNs, * bSupp, * bParts, * bTemp, * bSuppTemp; |
| int nVarsTotal, iVar, p, Counter; |
| |
| // put all the functions into one array |
| pbFuncs = ABC_ALLOC( DdNode *, nParts ); |
| for ( p = 0; p < nParts; p++ ) |
| pbFuncs[p] = pParts[p]->bSupp; |
| bSupp = Cudd_VectorSupport( dd, pbFuncs, nParts ); Cudd_Ref( bSupp ); |
| ABC_FREE( pbFuncs ); |
| |
| // remove the NS vars |
| bCubeNs = Cudd_bddComputeCube( dd, pbVars, NULL, nVars ); Cudd_Ref( bCubeNs ); |
| bSupp = Cudd_bddExistAbstract( dd, bTemp = bSupp, bCubeNs ); Cudd_Ref( bSupp ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| Cudd_RecursiveDeref( dd, bCubeNs ); |
| |
| // get the number of I and CS variables to be quantified |
| nVarsTotal = Extra_bddSuppSize( dd, bSupp ); |
| |
| // start the variables |
| pVars = ABC_ALLOC( Extra_ImageVar_t *, dd->size ); |
| memset( pVars, 0, sizeof(Extra_ImageVar_t *) * dd->size ); |
| // create structures for each variable |
| for ( bSuppTemp = bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) ) |
| { |
| iVar = bSuppTemp->index; |
| pVars[iVar] = ABC_ALLOC( Extra_ImageVar_t, 1 ); |
| pVars[iVar]->iNum = iVar; |
| // collect all the parts this var belongs to |
| Counter = 0; |
| bParts = b1; Cudd_Ref( bParts ); |
| for ( p = 0; p < nParts; p++ ) |
| if ( Cudd_bddLeq( dd, pParts[p]->bSupp, dd->vars[bSuppTemp->index] ) ) |
| { |
| bParts = Cudd_bddAnd( dd, bTemp = bParts, dd->vars[p] ); Cudd_Ref( bParts ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| Counter++; |
| } |
| pVars[iVar]->bParts = bParts; // takes ref |
| pVars[iVar]->nParts = Counter; |
| } |
| Cudd_RecursiveDeref( dd, bSupp ); |
| return pVars; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Creates variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImageNode_t ** Extra_CreateNodes( DdManager * dd, |
| int nParts, Extra_ImagePart_t ** pParts, |
| int nVars, Extra_ImageVar_t ** pVars ) |
| { |
| Extra_ImageNode_t ** pNodes; |
| Extra_ImageNode_t * pNode; |
| DdNode * bTemp; |
| int i, v, iPart; |
| /* |
| DdManager * dd; // the manager |
| DdNode * bCube; // the cube to quantify |
| DdNode * bImage; // the partial image |
| Extra_ImageNode_t * pNode1; // the first branch |
| Extra_ImageNode_t * pNode2; // the second branch |
| Extra_ImagePart_t * pPart; // the partition (temporary) |
| */ |
| // start the partitions |
| pNodes = ABC_ALLOC( Extra_ImageNode_t *, nParts ); |
| // create structures for each leaf nodes |
| for ( i = 0; i < nParts; i++ ) |
| { |
| pNodes[i] = ABC_ALLOC( Extra_ImageNode_t, 1 ); |
| memset( pNodes[i], 0, sizeof(Extra_ImageNode_t) ); |
| pNodes[i]->dd = dd; |
| pNodes[i]->pPart = pParts[i]; |
| } |
| // find the quantification cubes for each leaf node |
| for ( v = 0; v < nVars; v++ ) |
| { |
| if ( pVars[v] == NULL ) |
| continue; |
| assert( pVars[v]->nParts > 0 ); |
| if ( pVars[v]->nParts > 1 ) |
| continue; |
| iPart = pVars[v]->bParts->index; |
| if ( pNodes[iPart]->bCube == NULL ) |
| { |
| pNodes[iPart]->bCube = dd->vars[v]; |
| Cudd_Ref( dd->vars[v] ); |
| } |
| else |
| { |
| pNodes[iPart]->bCube = Cudd_bddAnd( dd, bTemp = pNodes[iPart]->bCube, dd->vars[v] ); |
| Cudd_Ref( pNodes[iPart]->bCube ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| } |
| // remove these variables |
| Cudd_RecursiveDeref( dd, pVars[v]->bParts ); |
| ABC_FREE( pVars[v] ); |
| } |
| |
| // assign the leaf node images |
| for ( i = 0; i < nParts; i++ ) |
| { |
| pNode = pNodes[i]; |
| if ( pNode->bCube ) |
| { |
| // update the partition |
| pParts[i]->bFunc = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bFunc, pNode->bCube ); |
| Cudd_Ref( pParts[i]->bFunc ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| // update the support the partition |
| pParts[i]->bSupp = Cudd_bddExistAbstract( dd, bTemp = pParts[i]->bSupp, pNode->bCube ); |
| Cudd_Ref( pParts[i]->bSupp ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| // update the numbers |
| pParts[i]->nSupp = Extra_bddSuppSize( dd, pParts[i]->bSupp ); |
| pParts[i]->nNodes = Cudd_DagSize( pParts[i]->bFunc ); |
| // get rid of the cube |
| // save the last (care set) quantification cube |
| if ( i < nParts - 1 ) |
| { |
| Cudd_RecursiveDeref( dd, pNode->bCube ); |
| pNode->bCube = NULL; |
| } |
| } |
| // copy the function |
| pNode->bImage = pParts[i]->bFunc; Cudd_Ref( pNode->bImage ); |
| } |
| /* |
| for ( i = 0; i < nParts; i++ ) |
| { |
| pNode = pNodes[i]; |
| ABC_PRB( dd, pNode->bCube ); |
| ABC_PRB( dd, pNode->pPart->bFunc ); |
| ABC_PRB( dd, pNode->pPart->bSupp ); |
| printf( "\n" ); |
| } |
| */ |
| return pNodes; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Delete the partitions from the nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_DeleteParts_rec( Extra_ImageNode_t * pNode ) |
| { |
| Extra_ImagePart_t * pPart; |
| if ( pNode->pNode1 ) |
| Extra_DeleteParts_rec( pNode->pNode1 ); |
| if ( pNode->pNode2 ) |
| Extra_DeleteParts_rec( pNode->pNode2 ); |
| pPart = pNode->pPart; |
| Cudd_RecursiveDeref( pNode->dd, pPart->bFunc ); |
| Cudd_RecursiveDeref( pNode->dd, pPart->bSupp ); |
| ABC_FREE( pNode->pPart ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Delete the partitions from the nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImageTreeDelete_rec( Extra_ImageNode_t * pNode ) |
| { |
| if ( pNode->pNode1 ) |
| Extra_bddImageTreeDelete_rec( pNode->pNode1 ); |
| if ( pNode->pNode2 ) |
| Extra_bddImageTreeDelete_rec( pNode->pNode2 ); |
| if ( pNode->bCube ) |
| Cudd_RecursiveDeref( pNode->dd, pNode->bCube ); |
| if ( pNode->bImage ) |
| Cudd_RecursiveDeref( pNode->dd, pNode->bImage ); |
| assert( pNode->pPart == NULL ); |
| ABC_FREE( pNode ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Recompute the image.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImageCompute_rec( Extra_ImageTree_t * pTree, Extra_ImageNode_t * pNode ) |
| { |
| DdManager * dd = pNode->dd; |
| DdNode * bTemp; |
| int nNodes; |
| |
| // trivial case |
| if ( pNode->pNode1 == NULL ) |
| { |
| if ( pNode->bCube ) |
| { |
| pNode->bImage = Cudd_bddExistAbstract( dd, bTemp = pNode->bImage, pNode->bCube ); |
| Cudd_Ref( pNode->bImage ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| } |
| return; |
| } |
| |
| // compute the children |
| if ( pNode->pNode1 ) |
| Extra_bddImageCompute_rec( pTree, pNode->pNode1 ); |
| if ( pNode->pNode2 ) |
| Extra_bddImageCompute_rec( pTree, pNode->pNode2 ); |
| |
| // clean the old image |
| if ( pNode->bImage ) |
| Cudd_RecursiveDeref( dd, pNode->bImage ); |
| pNode->bImage = NULL; |
| |
| // compute the new image |
| if ( pNode->bCube ) |
| pNode->bImage = Cudd_bddAndAbstract( dd, |
| pNode->pNode1->bImage, pNode->pNode2->bImage, pNode->bCube ); |
| else |
| pNode->bImage = Cudd_bddAnd( dd, pNode->pNode1->bImage, pNode->pNode2->bImage ); |
| Cudd_Ref( pNode->bImage ); |
| |
| if ( pTree->fVerbose ) |
| { |
| nNodes = Cudd_DagSize( pNode->bImage ); |
| if ( pTree->nNodesMax < nNodes ) |
| pTree->nNodesMax = nNodes; |
| } |
| } |
| |
| /**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; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Merges the nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImageNode_t * Extra_MergeTopNodes( |
| DdManager * dd, int nNodes, Extra_ImageNode_t ** pNodes ) |
| { |
| Extra_ImageNode_t * pNode; |
| int n1 = -1, n2 = -1, n; |
| |
| // find the first and the second non-empty spots |
| for ( n = 0; n < nNodes; n++ ) |
| if ( pNodes[n] ) |
| { |
| if ( n1 == -1 ) |
| n1 = n; |
| else if ( n2 == -1 ) |
| { |
| n2 = n; |
| break; |
| } |
| } |
| assert( n1 != -1 ); |
| // check the situation when only one such node is detected |
| if ( n2 == -1 ) |
| { |
| // save the node |
| pNode = pNodes[n1]; |
| // clean the node |
| pNodes[n1] = NULL; |
| return pNode; |
| } |
| |
| // combines two nodes |
| pNode = Extra_CombineTwoNodes( dd, b1, pNodes[n1], pNodes[n2] ); |
| |
| // clean the old nodes |
| pNodes[n1] = pNode; |
| pNodes[n2] = NULL; |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Merges two nodes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImageNode_t * Extra_CombineTwoNodes( DdManager * dd, DdNode * bCube, |
| Extra_ImageNode_t * pNode1, Extra_ImageNode_t * pNode2 ) |
| { |
| Extra_ImageNode_t * pNode; |
| Extra_ImagePart_t * pPart; |
| |
| // create a new partition |
| pPart = ABC_ALLOC( Extra_ImagePart_t, 1 ); |
| memset( pPart, 0, sizeof(Extra_ImagePart_t) ); |
| // create the function |
| pPart->bFunc = Cudd_bddAndAbstract( dd, pNode1->pPart->bFunc, pNode2->pPart->bFunc, bCube ); |
| Cudd_Ref( pPart->bFunc ); |
| // update the support the partition |
| pPart->bSupp = Cudd_bddAndAbstract( dd, pNode1->pPart->bSupp, pNode2->pPart->bSupp, bCube ); |
| Cudd_Ref( pPart->bSupp ); |
| // update the numbers |
| pPart->nSupp = Extra_bddSuppSize( dd, pPart->bSupp ); |
| pPart->nNodes = Cudd_DagSize( pPart->bFunc ); |
| pPart->iPart = -1; |
| /* |
| ABC_PRB( dd, pNode1->pPart->bSupp ); |
| ABC_PRB( dd, pNode2->pPart->bSupp ); |
| ABC_PRB( dd, pPart->bSupp ); |
| */ |
| // create a new node |
| pNode = ABC_ALLOC( Extra_ImageNode_t, 1 ); |
| memset( pNode, 0, sizeof(Extra_ImageNode_t) ); |
| pNode->dd = dd; |
| pNode->pPart = pPart; |
| pNode->pNode1 = pNode1; |
| pNode->pNode2 = pNode2; |
| // compute the image |
| pNode->bImage = Cudd_bddAndAbstract( dd, pNode1->bImage, pNode2->bImage, bCube ); |
| Cudd_Ref( pNode->bImage ); |
| // save the cube |
| if ( bCube != b1 ) |
| { |
| pNode->bCube = bCube; Cudd_Ref( bCube ); |
| } |
| return pNode; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes the best variable.] |
| |
| Description [The variables is the best if the sum of squares of the |
| BDD sizes of the partitions, in which it participates, is the minimum.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Extra_FindBestVariable( DdManager * dd, |
| int nNodes, Extra_ImageNode_t ** pNodes, |
| int nVars, Extra_ImageVar_t ** pVars ) |
| { |
| DdNode * bTemp; |
| int iVarBest, v; |
| double CostBest, CostCur; |
| |
| CostBest = 100000000000000.0; |
| iVarBest = -1; |
| for ( v = 0; v < nVars; v++ ) |
| if ( pVars[v] ) |
| { |
| CostCur = 0; |
| for ( bTemp = pVars[v]->bParts; bTemp != b1; bTemp = cuddT(bTemp) ) |
| CostCur += pNodes[bTemp->index]->pPart->nNodes * |
| pNodes[bTemp->index]->pPart->nNodes; |
| if ( CostBest > CostCur ) |
| { |
| CostBest = CostCur; |
| iVarBest = v; |
| } |
| } |
| return iVarBest; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes two smallest partions that have this var.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_FindBestPartitions( DdManager * dd, DdNode * bParts, |
| int nNodes, Extra_ImageNode_t ** pNodes, |
| int * piNode1, int * piNode2 ) |
| { |
| DdNode * bTemp; |
| int iPart1, iPart2; |
| int CostMin1, CostMin2, Cost; |
| |
| // go through the partitions |
| iPart1 = iPart2 = -1; |
| CostMin1 = CostMin2 = 1000000; |
| for ( bTemp = bParts; bTemp != b1; bTemp = cuddT(bTemp) ) |
| { |
| Cost = pNodes[bTemp->index]->pPart->nNodes; |
| if ( CostMin1 > Cost ) |
| { |
| CostMin2 = CostMin1; iPart2 = iPart1; |
| CostMin1 = Cost; iPart1 = bTemp->index; |
| } |
| else if ( CostMin2 > Cost ) |
| { |
| CostMin2 = Cost; iPart2 = bTemp->index; |
| } |
| } |
| |
| *piNode1 = iPart1; |
| *piNode2 = iPart2; |
| } |
| |
| /**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 [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 [Prints the tree for quenstification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImagePrintTree( Extra_ImageTree_t * pTree ) |
| { |
| printf( "The quantification scheduling tree:\n" ); |
| Extra_bddImagePrintTree_rec( pTree->pRoot, 1 ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints the tree for quenstification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImagePrintTree_rec( Extra_ImageNode_t * pNode, int Offset ) |
| { |
| DdNode * Cube; |
| int i; |
| |
| Cube = pNode->bCube; |
| |
| if ( pNode->pNode1 == NULL ) |
| { |
| printf( "<%d> ", pNode->pPart->iPart ); |
| if ( Cube != NULL ) |
| { |
| ABC_PRB( pNode->dd, Cube ); |
| } |
| else |
| printf( "\n" ); |
| return; |
| } |
| |
| printf( "<*> " ); |
| if ( Cube != NULL ) |
| { |
| ABC_PRB( pNode->dd, Cube ); |
| } |
| else |
| printf( "\n" ); |
| |
| for ( i = 0; i < Offset; i++ ) |
| printf( " " ); |
| Extra_bddImagePrintTree_rec( pNode->pNode1, Offset + 1 ); |
| |
| for ( i = 0; i < Offset; i++ ) |
| printf( " " ); |
| Extra_bddImagePrintTree_rec( pNode->pNode2, Offset + 1 ); |
| } |
| |
| |
| |
| |
| |
| struct Extra_ImageTree2_t_ |
| { |
| DdManager * dd; |
| DdNode * bRel; |
| DdNode * bCube; |
| DdNode * bImage; |
| }; |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts the monolithic image computation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Extra_ImageTree2_t * Extra_bddImageStart2( |
| DdManager * dd, DdNode * bCare, |
| int nParts, DdNode ** pbParts, |
| int nVars, DdNode ** pbVars, int fVerbose ) |
| { |
| Extra_ImageTree2_t * pTree; |
| DdNode * bCubeAll, * bCubeNot, * bTemp; |
| int i; |
| |
| pTree = ABC_ALLOC( Extra_ImageTree2_t, 1 ); |
| pTree->dd = dd; |
| pTree->bImage = NULL; |
| |
| bCubeAll = Extra_bddComputeCube( dd, dd->vars, dd->size ); Cudd_Ref( bCubeAll ); |
| bCubeNot = Extra_bddComputeCube( dd, pbVars, nVars ); Cudd_Ref( bCubeNot ); |
| pTree->bCube = Cudd_bddExistAbstract( dd, bCubeAll, bCubeNot ); Cudd_Ref( pTree->bCube ); |
| Cudd_RecursiveDeref( dd, bCubeAll ); |
| Cudd_RecursiveDeref( dd, bCubeNot ); |
| |
| // derive the monolithic relation |
| pTree->bRel = b1; Cudd_Ref( pTree->bRel ); |
| for ( i = 0; i < nParts; i++ ) |
| { |
| pTree->bRel = Cudd_bddAnd( dd, bTemp = pTree->bRel, pbParts[i] ); Cudd_Ref( pTree->bRel ); |
| Cudd_RecursiveDeref( dd, bTemp ); |
| } |
| Extra_bddImageCompute2( pTree, bCare ); |
| return pTree; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Extra_bddImageCompute2( Extra_ImageTree2_t * pTree, DdNode * bCare ) |
| { |
| if ( pTree->bImage ) |
| Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); |
| pTree->bImage = Cudd_bddAndAbstract( pTree->dd, pTree->bRel, bCare, pTree->bCube ); |
| Cudd_Ref( pTree->bImage ); |
| return pTree->bImage; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_bddImageTreeDelete2( Extra_ImageTree2_t * pTree ) |
| { |
| if ( pTree->bRel ) |
| Cudd_RecursiveDeref( pTree->dd, pTree->bRel ); |
| if ( pTree->bCube ) |
| Cudd_RecursiveDeref( pTree->dd, pTree->bCube ); |
| if ( pTree->bImage ) |
| Cudd_RecursiveDeref( pTree->dd, pTree->bImage ); |
| ABC_FREE( pTree ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the previously computed image.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Extra_bddImageRead2( Extra_ImageTree2_t * pTree ) |
| { |
| return pTree->bImage; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |