blob: 78a8b2111ca78a05019a8d09e89500a7fe95c3bd [file] [log] [blame]
/**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