| /**CFile**************************************************************** |
| |
| FileName [reoCore.c] |
| |
| PackageName [REO: A specialized DD reordering engine.] |
| |
| Synopsis [Implementation of the core reordering procedure.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - October 15, 2002.] |
| |
| Revision [$Id: reoCore.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "reo.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| static int reoRecursiveDeref( reo_unit * pUnit ); |
| static int reoCheckZeroRefs( reo_plane * pPlane ); |
| static int reoCheckLevels( reo_man * p ); |
| |
| double s_AplBefore; |
| double s_AplAfter; |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**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:\n" ); |
| 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:\n", 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] ]; |
| } |
| else |
| pOrder = p->pOrder; |
| |
| fVerification = 1; |
| for ( i = 0; i < nFuncs; i++ ) |
| { |
| // verify the result |
| if ( p->fThisIsAdd ) |
| FuncRemapped = Cudd_addPermute( dd, FuncsRes[i], pOrder ); |
| else |
| FuncRemapped = Cudd_bddPermute( dd, FuncsRes[i], pOrder ); |
| Cudd_Ref( FuncRemapped ); |
| |
| if ( FuncRemapped != Funcs[i] ) |
| { |
| fVerification = 0; |
| printf( "REO: Internal verification has failed!\n" ); |
| fflush( stdout ); |
| } |
| Cudd_RecursiveDeref( dd, FuncRemapped ); |
| } |
| if ( fVerification ) |
| printf( "REO: Internal verification is okay!\n" ); |
| |
| if ( p->pOrder == NULL ) |
| ABC_FREE( pOrder ); |
| } |
| |
| // recycle the data structure |
| for ( i = 0; i <= p->nSupp; i++ ) |
| reoUnitsRecycleUnitList( p, p->pPlanes + i ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Resizes the internal manager data structures.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void reoResizeStructures( reo_man * p, int nDdVarsMax, int nNodesMax, int nFuncs ) |
| { |
| // resize data structures depending on the number of variables in the DD manager |
| if ( p->nSuppAlloc == 0 ) |
| { |
| p->pSupp = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pOrderInt = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToPlanes = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToDdVarsOrig = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToDdVarsFinal = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pPlanes = ABC_CALLOC( reo_plane, nDdVarsMax + 1 ); |
| p->pVarCosts = ABC_ALLOC( double, nDdVarsMax + 1 ); |
| p->pLevelOrder = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->nSuppAlloc = nDdVarsMax + 1; |
| } |
| else if ( p->nSuppAlloc < nDdVarsMax ) |
| { |
| ABC_FREE( p->pSupp ); |
| ABC_FREE( p->pOrderInt ); |
| ABC_FREE( p->pMapToPlanes ); |
| ABC_FREE( p->pMapToDdVarsOrig ); |
| ABC_FREE( p->pMapToDdVarsFinal ); |
| ABC_FREE( p->pPlanes ); |
| ABC_FREE( p->pVarCosts ); |
| ABC_FREE( p->pLevelOrder ); |
| |
| p->pSupp = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pOrderInt = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToPlanes = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToDdVarsOrig = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pMapToDdVarsFinal = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->pPlanes = ABC_CALLOC( reo_plane, nDdVarsMax + 1 ); |
| p->pVarCosts = ABC_ALLOC( double, nDdVarsMax + 1 ); |
| p->pLevelOrder = ABC_ALLOC( int, nDdVarsMax + 1 ); |
| p->nSuppAlloc = nDdVarsMax + 1; |
| } |
| |
| // resize the data structures depending on the number of nodes |
| if ( p->nRefNodesAlloc == 0 ) |
| { |
| p->nNodesMaxAlloc = nNodesMax; |
| p->nTableSize = 3*nNodesMax + 1; |
| p->nRefNodesAlloc = 3*nNodesMax + 1; |
| p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1; |
| |
| p->HTable = ABC_CALLOC( reo_hash, p->nTableSize ); |
| p->pRefNodes = ABC_ALLOC( DdNode *, p->nRefNodesAlloc ); |
| p->pWidthCofs = ABC_ALLOC( reo_unit *, p->nRefNodesAlloc ); |
| p->pMemChunks = ABC_ALLOC( reo_unit *, p->nMemChunksAlloc ); |
| } |
| else if ( p->nNodesMaxAlloc < nNodesMax ) |
| { |
| reo_unit ** pTemp; |
| int nMemChunksAllocPrev = p->nMemChunksAlloc; |
| |
| p->nNodesMaxAlloc = nNodesMax; |
| p->nTableSize = 3*nNodesMax + 1; |
| p->nRefNodesAlloc = 3*nNodesMax + 1; |
| p->nMemChunksAlloc = (10*nNodesMax + 1)/REO_CHUNK_SIZE + 1; |
| |
| ABC_FREE( p->HTable ); |
| ABC_FREE( p->pRefNodes ); |
| ABC_FREE( p->pWidthCofs ); |
| p->HTable = ABC_CALLOC( reo_hash, p->nTableSize ); |
| p->pRefNodes = ABC_ALLOC( DdNode *, p->nRefNodesAlloc ); |
| p->pWidthCofs = ABC_ALLOC( reo_unit *, p->nRefNodesAlloc ); |
| // p->pMemChunks should be reallocated because it contains pointers currently in use |
| pTemp = ABC_ALLOC( reo_unit *, p->nMemChunksAlloc ); |
| memmove( pTemp, p->pMemChunks, sizeof(reo_unit *) * nMemChunksAllocPrev ); |
| ABC_FREE( p->pMemChunks ); |
| p->pMemChunks = pTemp; |
| } |
| |
| // resize the data structures depending on the number of functions |
| if ( p->nTopsAlloc == 0 ) |
| { |
| p->pTops = ABC_ALLOC( reo_unit *, nFuncs ); |
| p->nTopsAlloc = nFuncs; |
| } |
| else if ( p->nTopsAlloc < nFuncs ) |
| { |
| ABC_FREE( p->pTops ); |
| p->pTops = ABC_ALLOC( reo_unit *, nFuncs ); |
| p->nTopsAlloc = nFuncs; |
| } |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Dereferences units the data structure after reordering.] |
| |
| Description [This function is only useful for debugging.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int reoRecursiveDeref( reo_unit * pUnit ) |
| { |
| reo_unit * pUnitR; |
| pUnitR = Unit_Regular(pUnit); |
| pUnitR->n--; |
| if ( Unit_IsConstant(pUnitR) ) |
| return 1; |
| if ( pUnitR->n == 0 ) |
| { |
| reoRecursiveDeref( pUnitR->pE ); |
| reoRecursiveDeref( pUnitR->pT ); |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks the zero references for the given plane.] |
| |
| Description [This function is only useful for debugging.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int reoCheckZeroRefs( reo_plane * pPlane ) |
| { |
| reo_unit * pUnit; |
| for ( pUnit = pPlane->pHead; pUnit; pUnit = pUnit->Next ) |
| { |
| if ( pUnit->n != 0 ) |
| { |
| assert( 0 ); |
| } |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks the zero references for the given plane.] |
| |
| Description [This function is only useful for debugging.] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int reoCheckLevels( reo_man * p ) |
| { |
| reo_unit * pUnit; |
| int i; |
| |
| for ( i = 0; i < p->nSupp; i++ ) |
| { |
| // there are some nodes left on each level |
| assert( p->pPlanes[i].statsNodes ); |
| for ( pUnit = p->pPlanes[i].pHead; pUnit; pUnit = pUnit->Next ) |
| { |
| // the level is properly set |
| assert( pUnit->lev == i ); |
| } |
| } |
| return 1; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| ABC_NAMESPACE_IMPL_END |
| |