blob: 9ebdd4e5472f31974ff0077f5879ca803c059849 [file] [log] [blame]
/**CFile****************************************************************
FileName [extraBddUnate.c]
PackageName [extra]
Synopsis [Efficient methods to compute the information about
unate variables using an algorithm that is conceptually similar to
the algorithm for two-variable symmetry computation presented in:
A. Mishchenko. Fast Computation of Symmetries in Boolean Functions.
Transactions on CAD, Nov. 2003.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 2.0. Started - September 1, 2003.]
Revision [$Id: extraBddUnate.c,v 1.0 2003/09/01 00:00:00 alanmi Exp $]
***********************************************************************/
#include "extraBdd.h"
ABC_NAMESPACE_IMPL_START
/*---------------------------------------------------------------------------*/
/* Constant declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Stucture declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Type declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Variable declarations */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Macro declarations */
/*---------------------------------------------------------------------------*/
/**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_UnateInfo_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_UnateInfo_t * Extra_UnateComputeFast(
DdManager * dd, /* the manager */
DdNode * bFunc) /* the function whose symmetries are computed */
{
DdNode * bSupp;
DdNode * zRes;
Extra_UnateInfo_t * p;
bSupp = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupp );
zRes = Extra_zddUnateInfoCompute( dd, bFunc, bSupp ); Cudd_Ref( zRes );
p = Extra_UnateInfoCreateFromZdd( dd, zRes, bSupp );
Cudd_RecursiveDeref( dd, bSupp );
Cudd_RecursiveDerefZdd( dd, zRes );
return p;
} /* end of Extra_UnateInfoCompute */
/**Function********************************************************************
Synopsis [Computes the classical symmetry information as a ZDD.]
Description []
SideEffects []
SeeAlso []
******************************************************************************/
DdNode * Extra_zddUnateInfoCompute(
DdManager * dd, /* the DD manager */
DdNode * bF,
DdNode * bVars)
{
DdNode * res;
do {
dd->reordered = 0;
res = extraZddUnateInfoCompute( dd, bF, bVars );
} while (dd->reordered == 1);
return(res);
} /* end of Extra_zddUnateInfoCompute */
/**Function********************************************************************
Synopsis [Converts a set of variables into a set of singleton subsets.]
Description []
SideEffects []
SeeAlso []
******************************************************************************/
DdNode * Extra_zddGetSingletonsBoth(
DdManager * dd, /* the DD manager */
DdNode * bVars) /* the set of variables */
{
DdNode * res;
do {
dd->reordered = 0;
res = extraZddGetSingletonsBoth( dd, bVars );
} while (dd->reordered == 1);
return(res);
} /* end of Extra_zddGetSingletonsBoth */
/**Function********************************************************************
Synopsis [Allocates unateness information structure.]
Description []
SideEffects []
SeeAlso []
******************************************************************************/
Extra_UnateInfo_t * Extra_UnateInfoAllocate( int nVars )
{
Extra_UnateInfo_t * p;
// allocate and clean the storage for unateness info
p = ABC_ALLOC( Extra_UnateInfo_t, 1 );
memset( p, 0, sizeof(Extra_UnateInfo_t) );
p->nVars = nVars;
p->pVars = ABC_ALLOC( Extra_UnateVar_t, nVars );
memset( p->pVars, 0, nVars * sizeof(Extra_UnateVar_t) );
return p;
} /* end of Extra_UnateInfoAllocate */
/**Function********************************************************************
Synopsis [Deallocates symmetry information structure.]
Description []
SideEffects []
SeeAlso []
******************************************************************************/
void Extra_UnateInfoDissolve( Extra_UnateInfo_t * p )
{
ABC_FREE( p->pVars );
ABC_FREE( p );
} /* end of Extra_UnateInfoDissolve */
/**Function********************************************************************
Synopsis [Allocates symmetry information structure.]
Description []
SideEffects []
SeeAlso []
******************************************************************************/
void Extra_UnateInfoPrint( Extra_UnateInfo_t * p )
{
char * pBuffer;
int i;
pBuffer = ABC_ALLOC( char, p->nVarsMax+1 );
memset( pBuffer, ' ', p->nVarsMax );
pBuffer[p->nVarsMax] = 0;
for ( i = 0; i < p->nVars; i++ )
if ( p->pVars[i].Neg )
pBuffer[ p->pVars[i].iVar ] = 'n';
else if ( p->pVars[i].Pos )
pBuffer[ p->pVars[i].iVar ] = 'p';
else
pBuffer[ p->pVars[i].iVar ] = '.';
printf( "%s\n", pBuffer );
ABC_FREE( pBuffer );
} /* end of Extra_UnateInfoPrint */
/**Function********************************************************************
Synopsis [Creates the symmetry information structure from ZDD.]
Description [ZDD representation of symmetries is the set of cubes, each
of which has two variables in the positive polarity. These variables correspond
to the symmetric variable pair.]
SideEffects []
SeeAlso []
******************************************************************************/
Extra_UnateInfo_t * Extra_UnateInfoCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp )
{
Extra_UnateInfo_t * p;
DdNode * bTemp, * zSet, * zCube, * zTemp;
int * pMapVars2Nums;
int i, nSuppSize;
nSuppSize = Extra_bddSuppSize( dd, bSupp );
// allocate and clean the storage for symmetry info
p = Extra_UnateInfoAllocate( nSuppSize );
// allocate the storage for the temporary map
pMapVars2Nums = ABC_ALLOC( int, dd->size );
memset( pMapVars2Nums, 0, dd->size * sizeof(int) );
// assign the variables
p->nVarsMax = dd->size;
for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ )
{
p->pVars[i].iVar = bTemp->index;
pMapVars2Nums[bTemp->index] = i;
}
// write the symmetry info into the structure
zSet = zPairs; Cudd_Ref( zSet );
// Cudd_zddPrintCover( dd, zPairs ); printf( "\n" );
while ( zSet != z0 )
{
// get the next cube
zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube );
// add this var to the data structure
assert( cuddT(zCube) == z1 && cuddE(zCube) == z0 );
if ( zCube->index & 1 ) // neg
p->pVars[ pMapVars2Nums[zCube->index/2] ].Neg = 1;
else
p->pVars[ pMapVars2Nums[zCube->index/2] ].Pos = 1;
// count the unate vars
p->nUnate++;
// update the cuver and deref the cube
zSet = Cudd_zddDiff( dd, zTemp = zSet, zCube ); Cudd_Ref( zSet );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zCube );
} // for each cube
Cudd_RecursiveDerefZdd( dd, zSet );
ABC_FREE( pMapVars2Nums );
return p;
} /* end of Extra_UnateInfoCreateFromZdd */
/**Function********************************************************************
Synopsis [Computes the classical unateness information for the function.]
Description [Uses the naive way of comparing cofactors.]
SideEffects []
SeeAlso []
******************************************************************************/
Extra_UnateInfo_t * Extra_UnateComputeSlow( DdManager * dd, DdNode * bFunc )
{
int nSuppSize;
DdNode * bSupp, * bTemp;
Extra_UnateInfo_t * p;
int i, Res;
// 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_UnateInfoAllocate( nSuppSize );
// assign the variables
p->nVarsMax = dd->size;
for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ )
{
Res = Extra_bddCheckUnateNaive( dd, bFunc, bTemp->index );
p->pVars[i].iVar = bTemp->index;
if ( Res == -1 )
p->pVars[i].Neg = 1;
else if ( Res == 1 )
p->pVars[i].Pos = 1;
p->nUnate += (Res != 0);
}
Cudd_RecursiveDeref( dd, bSupp );
return p;
} /* end of Extra_UnateComputeSlow */
/**Function********************************************************************
Synopsis [Checks if the two variables are symmetric.]
Description [Returns 0 if vars are not unate. Return -1/+1 if the var is neg/pos unate.]
SideEffects []
SeeAlso []
******************************************************************************/
int Extra_bddCheckUnateNaive(
DdManager * dd, /* the DD manager */
DdNode * bF,
int iVar)
{
DdNode * bCof0, * bCof1;
int Res;
assert( iVar < dd->size );
bCof0 = Cudd_Cofactor( dd, bF, Cudd_Not(Cudd_bddIthVar(dd,iVar)) ); Cudd_Ref( bCof0 );
bCof1 = Cudd_Cofactor( dd, bF, Cudd_bddIthVar(dd,iVar) ); Cudd_Ref( bCof1 );
if ( Cudd_bddLeq( dd, bCof0, bCof1 ) )
Res = 1;
else if ( Cudd_bddLeq( dd, bCof1, bCof0 ) )
Res =-1;
else
Res = 0;
Cudd_RecursiveDeref( dd, bCof0 );
Cudd_RecursiveDeref( dd, bCof1 );
return Res;
} /* end of Extra_bddCheckUnateNaive */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Performs a recursive step of Extra_UnateInfoCompute.]
Description [Returns the set of symmetric variable pairs represented as a set
of two-literal ZDD cubes. Both variables always appear in the positive polarity
in the cubes. This function works without building new BDD nodes. Some relatively
small number of ZDD nodes may be built to ensure proper bookkeeping of the
symmetry information.]
SideEffects []
SeeAlso []
******************************************************************************/
DdNode *
extraZddUnateInfoCompute(
DdManager * dd, /* the manager */
DdNode * bFunc, /* the function whose symmetries are computed */
DdNode * bVars ) /* the set of variables on which this function depends */
{
DdNode * zRes;
DdNode * bFR = Cudd_Regular(bFunc);
if ( cuddIsConstant(bFR) )
{
if ( cuddIsConstant(bVars) )
return z0;
return extraZddGetSingletonsBoth( dd, bVars );
}
assert( bVars != b1 );
if ( (zRes = cuddCacheLookup2Zdd(dd, extraZddUnateInfoCompute, bFunc, bVars)) )
return zRes;
else
{
DdNode * zRes0, * zRes1;
DdNode * zTemp, * zPlus;
DdNode * bF0, * bF1;
DdNode * bVarsNew;
int nVarsExtra;
int LevelF;
int AddVar;
// every variable in bF should be also in bVars, therefore LevelF cannot be above LevelV
// if LevelF is below LevelV, scroll through the vars in bVars to the same level as F
// count how many extra vars are there in bVars
nVarsExtra = 0;
LevelF = dd->perm[bFR->index];
for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) )
nVarsExtra++;
// the indexes (level) of variables should be synchronized now
assert( bFR->index == bVarsNew->index );
// cofactor the function
if ( bFR != bFunc ) // bFunc is complemented
{
bF0 = Cudd_Not( cuddE(bFR) );
bF1 = Cudd_Not( cuddT(bFR) );
}
else
{
bF0 = cuddE(bFR);
bF1 = cuddT(bFR);
}
// solve subproblems
zRes0 = extraZddUnateInfoCompute( dd, bF0, cuddT(bVarsNew) );
if ( zRes0 == NULL )
return NULL;
cuddRef( zRes0 );
// if there is no symmetries in the negative cofactor
// there is no need to test the positive cofactor
if ( zRes0 == z0 )
zRes = zRes0; // zRes takes reference
else
{
zRes1 = extraZddUnateInfoCompute( dd, bF1, cuddT(bVarsNew) );
if ( zRes1 == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes0 );
return NULL;
}
cuddRef( zRes1 );
// only those variables are pair-wise symmetric
// that are pair-wise symmetric in both cofactors
// therefore, intersect the solutions
zRes = cuddZddIntersect( dd, zRes0, zRes1 );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes0 );
Cudd_RecursiveDerefZdd( dd, zRes1 );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zRes0 );
Cudd_RecursiveDerefZdd( dd, zRes1 );
}
// consider the current top-most variable
AddVar = -1;
if ( Cudd_bddLeq( dd, bF0, bF1 ) ) // pos
AddVar = 0;
else if ( Cudd_bddLeq( dd, bF1, bF0 ) ) // neg
AddVar = 1;
if ( AddVar >= 0 )
{
// create the singleton
zPlus = cuddZddGetNode( dd, 2*bFR->index + AddVar, z1, z0 );
if ( zPlus == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes );
return NULL;
}
cuddRef( zPlus );
// add these to the result
zRes = cuddZddUnion( dd, zTemp = zRes, zPlus );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
}
// only zRes is referenced at this point
// if we skipped some variables, these variables cannot be symmetric with
// any variables that are currently in the support of bF, but they can be
// symmetric with the variables that are in bVars but not in the support of bF
for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) )
{
// create the negative singleton
zPlus = cuddZddGetNode( dd, 2*bVarsNew->index+1, z1, z0 );
if ( zPlus == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes );
return NULL;
}
cuddRef( zPlus );
// add these to the result
zRes = cuddZddUnion( dd, zTemp = zRes, zPlus );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
// create the positive singleton
zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 );
if ( zPlus == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes );
return NULL;
}
cuddRef( zPlus );
// add these to the result
zRes = cuddZddUnion( dd, zTemp = zRes, zPlus );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
}
cuddDeref( zRes );
/* insert the result into cache */
cuddCacheInsert2(dd, extraZddUnateInfoCompute, bFunc, bVars, zRes);
return zRes;
}
} /* end of extraZddUnateInfoCompute */
/**Function********************************************************************
Synopsis [Performs a recursive step of Extra_zddGetSingletons.]
Description [Returns the set of ZDD singletons, containing those pos/neg
polarity ZDD variables that correspond to the BDD variables in bVars.]
SideEffects []
SeeAlso []
******************************************************************************/
DdNode * extraZddGetSingletonsBoth(
DdManager * dd, /* the DD manager */
DdNode * bVars) /* the set of variables */
{
DdNode * zRes;
if ( bVars == b1 )
return z1;
if ( (zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletonsBoth, bVars)) )
return zRes;
else
{
DdNode * zTemp, * zPlus;
// solve subproblem
zRes = extraZddGetSingletonsBoth( dd, cuddT(bVars) );
if ( zRes == NULL )
return NULL;
cuddRef( zRes );
// create the negative singleton
zPlus = cuddZddGetNode( dd, 2*bVars->index+1, z1, z0 );
if ( zPlus == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes );
return NULL;
}
cuddRef( zPlus );
// add these to the result
zRes = cuddZddUnion( dd, zTemp = zRes, zPlus );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
// create the positive singleton
zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 );
if ( zPlus == NULL )
{
Cudd_RecursiveDerefZdd( dd, zRes );
return NULL;
}
cuddRef( zPlus );
// add these to the result
zRes = cuddZddUnion( dd, zTemp = zRes, zPlus );
if ( zRes == NULL )
{
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
return NULL;
}
cuddRef( zRes );
Cudd_RecursiveDerefZdd( dd, zTemp );
Cudd_RecursiveDerefZdd( dd, zPlus );
cuddDeref( zRes );
cuddCacheInsert1( dd, extraZddGetSingletonsBoth, bVars, zRes );
return zRes;
}
} /* end of extraZddGetSingletonsBoth */
/*---------------------------------------------------------------------------*/
/* Definition of static Functions */
/*---------------------------------------------------------------------------*/
ABC_NAMESPACE_IMPL_END