mirror of https://github.com/YosysHQ/abc.git
1475 lines
46 KiB
C
1475 lines
46 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [extraBddSymm.c]
|
|
|
|
PackageName [extra]
|
|
|
|
Synopsis [Efficient methods to compute the information about
|
|
symmetric variables using the algorithm presented in the paper:
|
|
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: extraBddSymm.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 */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#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 [Computes the classical symmetry information as a ZDD.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * Extra_zddSymmPairsCompute(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF,
|
|
DdNode * bVars)
|
|
{
|
|
DdNode * res;
|
|
do {
|
|
dd->reordered = 0;
|
|
res = extraZddSymmPairsCompute( dd, bF, bVars );
|
|
} while (dd->reordered == 1);
|
|
return(res);
|
|
|
|
} /* end of Extra_zddSymmPairsCompute */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Returns a singleton-set ZDD containing all variables that are symmetric with the given one.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * Extra_zddGetSymmetricVars(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF, /* the first function - originally, the positive cofactor */
|
|
DdNode * bG, /* the second fucntion - originally, the negative cofactor */
|
|
DdNode * bVars) /* the set of variables, on which F and G depend */
|
|
{
|
|
DdNode * res;
|
|
do {
|
|
dd->reordered = 0;
|
|
res = extraZddGetSymmetricVars( dd, bF, bG, bVars );
|
|
} while (dd->reordered == 1);
|
|
return(res);
|
|
|
|
} /* end of Extra_zddGetSymmetricVars */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Converts a set of variables into a set of singleton subsets.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * Extra_zddGetSingletons(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bVars) /* the set of variables */
|
|
{
|
|
DdNode * res;
|
|
do {
|
|
dd->reordered = 0;
|
|
res = extraZddGetSingletons( dd, bVars );
|
|
} while (dd->reordered == 1);
|
|
return(res);
|
|
|
|
} /* end of Extra_zddGetSingletons */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Filters the set of variables using the support of the function.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * Extra_bddReduceVarSet(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bVars, /* the set of variables to be reduced */
|
|
DdNode * bF) /* the function whose support is used for reduction */
|
|
{
|
|
DdNode * res;
|
|
do {
|
|
dd->reordered = 0;
|
|
res = extraBddReduceVarSet( dd, bVars, bF );
|
|
} while (dd->reordered == 1);
|
|
return(res);
|
|
|
|
} /* end of Extra_bddReduceVarSet */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Allocates symmetry information structure.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
Extra_SymmInfo_t * Extra_SymmPairsAllocate( int nVars )
|
|
{
|
|
int i;
|
|
Extra_SymmInfo_t * p;
|
|
|
|
// allocate and clean the storage for symmetry info
|
|
p = ABC_ALLOC( Extra_SymmInfo_t, 1 );
|
|
memset( p, 0, sizeof(Extra_SymmInfo_t) );
|
|
p->nVars = nVars;
|
|
p->pVars = ABC_ALLOC( int, nVars );
|
|
p->pSymms = ABC_ALLOC( char *, nVars );
|
|
p->pSymms[0] = ABC_ALLOC( char , nVars * nVars );
|
|
memset( p->pSymms[0], 0, nVars * nVars * sizeof(char) );
|
|
|
|
for ( i = 1; i < nVars; i++ )
|
|
p->pSymms[i] = p->pSymms[i-1] + nVars;
|
|
|
|
return p;
|
|
} /* end of Extra_SymmPairsAllocate */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Deallocates symmetry information structure.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void Extra_SymmPairsDissolve( Extra_SymmInfo_t * p )
|
|
{
|
|
ABC_FREE( p->pVars );
|
|
ABC_FREE( p->pSymms[0] );
|
|
ABC_FREE( p->pSymms );
|
|
ABC_FREE( p );
|
|
} /* end of Extra_SymmPairsDissolve */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Allocates symmetry information structure.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void Extra_SymmPairsPrint( Extra_SymmInfo_t * p )
|
|
{
|
|
int i, k;
|
|
printf( "\n" );
|
|
for ( i = 0; i < p->nVars; i++ )
|
|
{
|
|
for ( k = 0; k <= i; k++ )
|
|
printf( " " );
|
|
for ( k = i+1; k < p->nVars; k++ )
|
|
if ( p->pSymms[i][k] )
|
|
printf( "1" );
|
|
else
|
|
printf( "." );
|
|
printf( "\n" );
|
|
}
|
|
} /* end of Extra_SymmPairsPrint */
|
|
|
|
|
|
/**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_SymmInfo_t * Extra_SymmPairsCreateFromZdd( DdManager * dd, DdNode * zPairs, DdNode * bSupp )
|
|
{
|
|
int i;
|
|
int nSuppSize;
|
|
Extra_SymmInfo_t * p;
|
|
int * pMapVars2Nums;
|
|
DdNode * bTemp;
|
|
DdNode * zSet, * zCube, * zTemp;
|
|
int iVar1, iVar2;
|
|
|
|
nSuppSize = Extra_bddSuppSize( dd, bSupp );
|
|
|
|
// allocate and clean the storage for symmetry info
|
|
p = Extra_SymmPairsAllocate( 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;
|
|
// p->nNodes = Cudd_DagSize( zPairs );
|
|
p->nNodes = 0;
|
|
for ( i = 0, bTemp = bSupp; bTemp != b1; bTemp = cuddT(bTemp), i++ )
|
|
{
|
|
p->pVars[i] = bTemp->index;
|
|
pMapVars2Nums[bTemp->index] = i;
|
|
}
|
|
|
|
// write the symmetry info into the structure
|
|
zSet = zPairs; Cudd_Ref( zSet );
|
|
while ( zSet != z0 )
|
|
{
|
|
// get the next cube
|
|
zCube = Extra_zddSelectOneSubset( dd, zSet ); Cudd_Ref( zCube );
|
|
|
|
// add these two variables to the data structure
|
|
assert( cuddT( cuddT(zCube) ) == z1 );
|
|
iVar1 = zCube->index/2;
|
|
iVar2 = cuddT(zCube)->index/2;
|
|
if ( pMapVars2Nums[iVar1] < pMapVars2Nums[iVar2] )
|
|
p->pSymms[ pMapVars2Nums[iVar1] ][ pMapVars2Nums[iVar2] ] = 1;
|
|
else
|
|
p->pSymms[ pMapVars2Nums[iVar2] ][ pMapVars2Nums[iVar1] ] = 1;
|
|
// count the symmetric pairs
|
|
p->nSymms ++;
|
|
|
|
// 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_SymmPairsCreateFromZdd */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Checks the possibility of two variables being symmetric.]
|
|
|
|
Description [Returns 0 if vars are not symmetric. Return 1 if vars can be symmetric.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
int Extra_bddCheckVarsSymmetric(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF,
|
|
int iVar1,
|
|
int iVar2)
|
|
{
|
|
DdNode * bVars;
|
|
int Res;
|
|
|
|
// return 1;
|
|
|
|
assert( iVar1 != iVar2 );
|
|
assert( iVar1 < dd->size );
|
|
assert( iVar2 < dd->size );
|
|
|
|
bVars = Cudd_bddAnd( dd, dd->vars[iVar1], dd->vars[iVar2] ); Cudd_Ref( bVars );
|
|
|
|
Res = (int)( extraBddCheckVarsSymmetric( dd, bF, bVars ) == b1 );
|
|
|
|
Cudd_RecursiveDeref( dd, bVars );
|
|
|
|
return Res;
|
|
} /* end of Extra_bddCheckVarsSymmetric */
|
|
|
|
|
|
/**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 [Checks if the two variables are symmetric.]
|
|
|
|
Description [Returns 0 if vars are not symmetric. Return 1 if vars are symmetric.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
int Extra_bddCheckVarsSymmetricNaive(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF,
|
|
int iVar1,
|
|
int iVar2)
|
|
{
|
|
DdNode * bCube1, * bCube2;
|
|
DdNode * bCof01, * bCof10;
|
|
int Res;
|
|
|
|
assert( iVar1 != iVar2 );
|
|
assert( iVar1 < dd->size );
|
|
assert( iVar2 < dd->size );
|
|
|
|
bCube1 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar1] ), dd->vars[iVar2] ); Cudd_Ref( bCube1 );
|
|
bCube2 = Cudd_bddAnd( dd, Cudd_Not( dd->vars[iVar2] ), dd->vars[iVar1] ); Cudd_Ref( bCube2 );
|
|
|
|
bCof01 = Cudd_Cofactor( dd, bF, bCube1 ); Cudd_Ref( bCof01 );
|
|
bCof10 = Cudd_Cofactor( dd, bF, bCube2 ); Cudd_Ref( bCof10 );
|
|
|
|
Res = (int)( bCof10 == bCof01 );
|
|
|
|
Cudd_RecursiveDeref( dd, bCof01 );
|
|
Cudd_RecursiveDeref( dd, bCof10 );
|
|
Cudd_RecursiveDeref( dd, bCube1 );
|
|
Cudd_RecursiveDeref( dd, bCube2 );
|
|
|
|
return Res;
|
|
} /* end of Extra_bddCheckVarsSymmetricNaive */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Builds ZDD representing the set of fixed-size variable tuples.]
|
|
|
|
Description [Creates ZDD of all combinations of variables in Support that
|
|
is represented by a BDD.]
|
|
|
|
SideEffects [New ZDD variables are created if indices of the variables
|
|
present in the combination are larger than the currently
|
|
allocated number of ZDD variables.]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode* Extra_zddTuplesFromBdd(
|
|
DdManager * dd, /* the DD manager */
|
|
int K, /* the number of variables in tuples */
|
|
DdNode * bVarsN) /* the set of all variables represented as a BDD */
|
|
{
|
|
DdNode *zRes;
|
|
int autoDynZ;
|
|
|
|
autoDynZ = dd->autoDynZ;
|
|
dd->autoDynZ = 0;
|
|
|
|
do {
|
|
/* transform the numeric arguments (K) into a DdNode* argument;
|
|
* this allows us to use the standard internal CUDD cache */
|
|
DdNode *bVarSet = bVarsN, *bVarsK = bVarsN;
|
|
int nVars = 0, i;
|
|
|
|
/* determine the number of variables in VarSet */
|
|
while ( bVarSet != b1 )
|
|
{
|
|
nVars++;
|
|
/* make sure that the VarSet is a cube */
|
|
if ( cuddE( bVarSet ) != b0 )
|
|
return NULL;
|
|
bVarSet = cuddT( bVarSet );
|
|
}
|
|
/* make sure that the number of variables in VarSet is less or equal
|
|
that the number of variables that should be present in the tuples
|
|
*/
|
|
if ( K > nVars )
|
|
return NULL;
|
|
|
|
/* the second argument in the recursive call stannds for <n>;
|
|
* reate the first argument, which stands for <k>
|
|
* as when we are talking about the tuple of <k> out of <n> */
|
|
for ( i = 0; i < nVars-K; i++ )
|
|
bVarsK = cuddT( bVarsK );
|
|
|
|
dd->reordered = 0;
|
|
zRes = extraZddTuplesFromBdd(dd, bVarsK, bVarsN );
|
|
|
|
} while (dd->reordered == 1);
|
|
dd->autoDynZ = autoDynZ;
|
|
return zRes;
|
|
|
|
} /* end of Extra_zddTuplesFromBdd */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Selects one subset from the set of subsets represented by a ZDD.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode* Extra_zddSelectOneSubset(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * zS) /* the ZDD */
|
|
{
|
|
DdNode *res;
|
|
do {
|
|
dd->reordered = 0;
|
|
res = extraZddSelectOneSubset(dd, zS);
|
|
} while (dd->reordered == 1);
|
|
return(res);
|
|
|
|
} /* end of Extra_zddSelectOneSubset */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs a recursive step of Extra_SymmPairsCompute.]
|
|
|
|
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 *
|
|
extraZddSymmPairsCompute(
|
|
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) )
|
|
{
|
|
int nVars, i;
|
|
|
|
// determine how many vars are in the bVars
|
|
nVars = Extra_bddSuppSize( dd, bVars );
|
|
if ( nVars < 2 )
|
|
return z0;
|
|
else
|
|
{
|
|
DdNode * bVarsK;
|
|
|
|
// create the BDD bVarsK corresponding to K = 2;
|
|
bVarsK = bVars;
|
|
for ( i = 0; i < nVars-2; i++ )
|
|
bVarsK = cuddT( bVarsK );
|
|
return extraZddTuplesFromBdd( dd, bVarsK, bVars );
|
|
}
|
|
}
|
|
assert( bVars != b1 );
|
|
|
|
if ( (zRes = cuddCacheLookup2Zdd(dd, extraZddSymmPairsCompute, bFunc, bVars)) )
|
|
return zRes;
|
|
else
|
|
{
|
|
DdNode * zRes0, * zRes1;
|
|
DdNode * zTemp, * zPlus, * zSymmVars;
|
|
DdNode * bF0, * bF1;
|
|
DdNode * bVarsNew;
|
|
int nVarsExtra;
|
|
int LevelF;
|
|
|
|
// 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 = extraZddSymmPairsCompute( 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 = extraZddSymmPairsCompute( 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 and find all the vars
|
|
// that are pairwise symmetric with it
|
|
// these variables are returned as a set of ZDD singletons
|
|
zSymmVars = extraZddGetSymmetricVars( dd, bF1, bF0, cuddT(bVarsNew) );
|
|
if ( zSymmVars == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( zSymmVars );
|
|
|
|
// attach the topmost variable to the set, to get the variable pairs
|
|
// use the positive polarity ZDD variable for the purpose
|
|
|
|
// there is no need to do so, if zSymmVars is empty
|
|
if ( zSymmVars == z0 )
|
|
Cudd_RecursiveDerefZdd( dd, zSymmVars );
|
|
else
|
|
{
|
|
zPlus = cuddZddGetNode( dd, 2*bFR->index, zSymmVars, z0 );
|
|
if ( zPlus == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
Cudd_RecursiveDerefZdd( dd, zSymmVars );
|
|
return NULL;
|
|
}
|
|
cuddRef( zPlus );
|
|
cuddDeref( zSymmVars );
|
|
|
|
// add these variable pairs 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
|
|
if ( nVarsExtra )
|
|
{
|
|
// it is possible to improve this step:
|
|
// (1) there is no need to enter here, if nVarsExtra < 2
|
|
|
|
// create the set of topmost nVarsExtra in bVars
|
|
DdNode * bVarsExtra;
|
|
int nVars;
|
|
|
|
// remove from bVars all the variable that are in the support of bFunc
|
|
bVarsExtra = extraBddReduceVarSet( dd, bVars, bFunc );
|
|
if ( bVarsExtra == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( bVarsExtra );
|
|
|
|
// determine how many vars are in the bVarsExtra
|
|
nVars = Extra_bddSuppSize( dd, bVarsExtra );
|
|
if ( nVars < 2 )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
DdNode * bVarsK;
|
|
|
|
// create the BDD bVarsK corresponding to K = 2;
|
|
bVarsK = bVarsExtra;
|
|
for ( i = 0; i < nVars-2; i++ )
|
|
bVarsK = cuddT( bVarsK );
|
|
|
|
// create the 2 variable tuples
|
|
zPlus = extraZddTuplesFromBdd( dd, bVarsK, bVarsExtra );
|
|
if ( zPlus == NULL )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( zPlus );
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
|
|
// 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, extraZddSymmPairsCompute, bFunc, bVars, zRes);
|
|
return zRes;
|
|
}
|
|
} /* end of extraZddSymmPairsCompute */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs a recursive step of Extra_zddGetSymmetricVars.]
|
|
|
|
Description [Returns the set of ZDD singletons, containing those positive
|
|
ZDD variables that correspond to BDD variables x, for which it is true
|
|
that bF(x=0) == bG(x=1).]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * extraZddGetSymmetricVars(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF, /* the first function - originally, the positive cofactor */
|
|
DdNode * bG, /* the second function - originally, the negative cofactor */
|
|
DdNode * bVars) /* the set of variables, on which F and G depend */
|
|
{
|
|
DdNode * zRes;
|
|
DdNode * bFR = Cudd_Regular(bF);
|
|
DdNode * bGR = Cudd_Regular(bG);
|
|
|
|
if ( cuddIsConstant(bFR) && cuddIsConstant(bGR) )
|
|
{
|
|
if ( bF == bG )
|
|
return extraZddGetSingletons( dd, bVars );
|
|
else
|
|
return z0;
|
|
}
|
|
assert( bVars != b1 );
|
|
|
|
if ( (zRes = cuddCacheLookupZdd(dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars)) )
|
|
return zRes;
|
|
else
|
|
{
|
|
DdNode * zRes0, * zRes1;
|
|
DdNode * zPlus, * zTemp;
|
|
DdNode * bF0, * bF1;
|
|
DdNode * bG0, * bG1;
|
|
DdNode * bVarsNew;
|
|
|
|
int LevelF = cuddI(dd,bFR->index);
|
|
int LevelG = cuddI(dd,bGR->index);
|
|
int LevelFG;
|
|
|
|
if ( LevelF < LevelG )
|
|
LevelFG = LevelF;
|
|
else
|
|
LevelFG = LevelG;
|
|
|
|
// at least one of the arguments is not a constant
|
|
assert( LevelFG < dd->size );
|
|
|
|
// every variable in bF and bG should be also in bVars, therefore LevelFG cannot be above LevelV
|
|
// if LevelFG is below LevelV, scroll through the vars in bVars to the same level as LevelFG
|
|
for ( bVarsNew = bVars; LevelFG > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) );
|
|
assert( LevelFG == dd->perm[bVarsNew->index] );
|
|
|
|
// cofactor the functions
|
|
if ( LevelF == LevelFG )
|
|
{
|
|
if ( bFR != bF ) // bF is complemented
|
|
{
|
|
bF0 = Cudd_Not( cuddE(bFR) );
|
|
bF1 = Cudd_Not( cuddT(bFR) );
|
|
}
|
|
else
|
|
{
|
|
bF0 = cuddE(bFR);
|
|
bF1 = cuddT(bFR);
|
|
}
|
|
}
|
|
else
|
|
bF0 = bF1 = bF;
|
|
|
|
if ( LevelG == LevelFG )
|
|
{
|
|
if ( bGR != bG ) // bG is complemented
|
|
{
|
|
bG0 = Cudd_Not( cuddE(bGR) );
|
|
bG1 = Cudd_Not( cuddT(bGR) );
|
|
}
|
|
else
|
|
{
|
|
bG0 = cuddE(bGR);
|
|
bG1 = cuddT(bGR);
|
|
}
|
|
}
|
|
else
|
|
bG0 = bG1 = bG;
|
|
|
|
// solve subproblems
|
|
zRes0 = extraZddGetSymmetricVars( dd, bF0, bG0, cuddT(bVarsNew) );
|
|
if ( zRes0 == NULL )
|
|
return NULL;
|
|
cuddRef( zRes0 );
|
|
|
|
// if there is not symmetries in the negative cofactor
|
|
// there is no need to test the positive cofactor
|
|
if ( zRes0 == z0 )
|
|
zRes = zRes0; // zRes takes reference
|
|
else
|
|
{
|
|
zRes1 = extraZddGetSymmetricVars( dd, bF1, bG1, cuddT(bVarsNew) );
|
|
if ( zRes1 == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes0 );
|
|
return NULL;
|
|
}
|
|
cuddRef( zRes1 );
|
|
|
|
// only those variables should belong to the resulting set
|
|
// for which the property is true for both cofactors
|
|
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 );
|
|
}
|
|
|
|
// add one more singleton if the property is true for this variable
|
|
if ( bF0 == bG1 )
|
|
{
|
|
zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 );
|
|
if ( zPlus == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( zPlus );
|
|
|
|
// add these variable pairs 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 );
|
|
}
|
|
|
|
if ( bF == bG && bVars != bVarsNew )
|
|
{
|
|
// if the functions are equal, so are their cofactors
|
|
// add those variables from V that are above F and G
|
|
|
|
DdNode * bVarsExtra;
|
|
|
|
assert( LevelFG > dd->perm[bVars->index] );
|
|
|
|
// create the BDD of the extra variables
|
|
bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsNew );
|
|
if ( bVarsExtra == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( bVarsExtra );
|
|
|
|
zPlus = extraZddGetSingletons( dd, bVarsExtra );
|
|
if ( zPlus == NULL )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
Cudd_RecursiveDerefZdd( dd, zRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( zPlus );
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
|
|
// 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 );
|
|
|
|
cuddCacheInsert( dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars, zRes );
|
|
return zRes;
|
|
}
|
|
} /* end of extraZddGetSymmetricVars */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs a recursive step of Extra_zddGetSingletons.]
|
|
|
|
Description [Returns the set of ZDD singletons, containing those positive
|
|
polarity ZDD variables that correspond to the BDD variables in bVars.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * extraZddGetSingletons(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bVars) /* the set of variables */
|
|
{
|
|
DdNode * zRes;
|
|
|
|
if ( bVars == b1 )
|
|
// if ( bVars == b0 ) // bug fixed by Jin Zhang, Jan 23, 2004
|
|
return z1;
|
|
|
|
if ( (zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletons, bVars)) )
|
|
return zRes;
|
|
else
|
|
{
|
|
DdNode * zTemp, * zPlus;
|
|
|
|
// solve subproblem
|
|
zRes = extraZddGetSingletons( dd, cuddT(bVars) );
|
|
if ( zRes == NULL )
|
|
return NULL;
|
|
cuddRef( zRes );
|
|
|
|
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, extraZddGetSingletons, bVars, zRes );
|
|
return zRes;
|
|
}
|
|
} /* end of extraZddGetSingletons */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs a recursive step of Extra_bddReduceVarSet.]
|
|
|
|
Description [Returns the set of all variables in the given set that are not in the
|
|
support of the given function.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * extraBddReduceVarSet(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bVars, /* the set of variables to be reduced */
|
|
DdNode * bF) /* the function whose support is used for reduction */
|
|
{
|
|
DdNode * bRes;
|
|
DdNode * bFR = Cudd_Regular(bF);
|
|
|
|
if ( cuddIsConstant(bFR) || bVars == b1 )
|
|
return bVars;
|
|
|
|
if ( (bRes = cuddCacheLookup2(dd, extraBddReduceVarSet, bVars, bF)) )
|
|
return bRes;
|
|
else
|
|
{
|
|
DdNode * bF0, * bF1;
|
|
DdNode * bVarsThis, * bVarsLower, * bTemp;
|
|
int LevelF;
|
|
|
|
// if LevelF is below LevelV, scroll through the vars in bVars
|
|
LevelF = dd->perm[bFR->index];
|
|
for ( bVarsThis = bVars; LevelF > cuddI(dd,bVarsThis->index); bVarsThis = cuddT(bVarsThis) );
|
|
// scroll also through the current var, because it should be not be added
|
|
if ( LevelF == cuddI(dd,bVarsThis->index) )
|
|
bVarsLower = cuddT(bVarsThis);
|
|
else
|
|
bVarsLower = bVarsThis;
|
|
|
|
// cofactor the function
|
|
if ( bFR != bF ) // bFunc is complemented
|
|
{
|
|
bF0 = Cudd_Not( cuddE(bFR) );
|
|
bF1 = Cudd_Not( cuddT(bFR) );
|
|
}
|
|
else
|
|
{
|
|
bF0 = cuddE(bFR);
|
|
bF1 = cuddT(bFR);
|
|
}
|
|
|
|
// solve subproblems
|
|
bRes = extraBddReduceVarSet( dd, bVarsLower, bF0 );
|
|
if ( bRes == NULL )
|
|
return NULL;
|
|
cuddRef( bRes );
|
|
|
|
bRes = extraBddReduceVarSet( dd, bTemp = bRes, bF1 );
|
|
if ( bRes == NULL )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
return NULL;
|
|
}
|
|
cuddRef( bRes );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
|
|
// the current var should not be added
|
|
// add the skipped vars
|
|
if ( bVarsThis != bVars )
|
|
{
|
|
DdNode * bVarsExtra;
|
|
|
|
// extract the skipped variables
|
|
bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsThis );
|
|
if ( bVarsExtra == NULL )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bRes );
|
|
return NULL;
|
|
}
|
|
cuddRef( bVarsExtra );
|
|
|
|
// add these variables
|
|
bRes = cuddBddAndRecur( dd, bTemp = bRes, bVarsExtra );
|
|
if ( bRes == NULL )
|
|
{
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
return NULL;
|
|
}
|
|
cuddRef( bRes );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
Cudd_RecursiveDeref( dd, bVarsExtra );
|
|
}
|
|
cuddDeref( bRes );
|
|
|
|
cuddCacheInsert2( dd, extraBddReduceVarSet, bVars, bF, bRes );
|
|
return bRes;
|
|
}
|
|
} /* end of extraBddReduceVarSet */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the recursive step of Extra_bddCheckVarsSymmetric().]
|
|
|
|
Description [Returns b0 if the variables are not symmetric. Returns b1 if the
|
|
variables can be symmetric. The variables are represented in the form of a
|
|
two-variable cube. In case the cube contains one variable (below Var1 level),
|
|
the cube's pointer is complemented if the variable Var1 occurred on the
|
|
current path; otherwise, the cube's pointer is regular. Uses additional
|
|
complemented bit (Hash_Not) to mark the result if in the BDD rooted that this
|
|
node there is a branch passing though the node labeled with Var2.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * extraBddCheckVarsSymmetric(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bF,
|
|
DdNode * bVars)
|
|
{
|
|
DdNode * bRes;
|
|
|
|
if ( bF == b0 )
|
|
return b1;
|
|
|
|
assert( bVars != b1 );
|
|
|
|
if ( (bRes = cuddCacheLookup2(dd, extraBddCheckVarsSymmetric, bF, bVars)) )
|
|
return bRes;
|
|
else
|
|
{
|
|
DdNode * bRes0, * bRes1;
|
|
DdNode * bF0, * bF1;
|
|
DdNode * bFR = Cudd_Regular(bF);
|
|
int LevelF = cuddI(dd,bFR->index);
|
|
|
|
DdNode * bVarsR = Cudd_Regular(bVars);
|
|
int fVar1Pres;
|
|
int iLev1;
|
|
int iLev2;
|
|
|
|
if ( bVarsR != bVars ) // cube's pointer is complemented
|
|
{
|
|
assert( cuddT(bVarsR) == b1 );
|
|
fVar1Pres = 1; // the first var is present on the path
|
|
iLev1 = -1; // we are already below the first var level
|
|
iLev2 = dd->perm[bVarsR->index]; // the level of the second var
|
|
}
|
|
else // cube's pointer is NOT complemented
|
|
{
|
|
fVar1Pres = 0; // the first var is absent on the path
|
|
if ( cuddT(bVars) == b1 )
|
|
{
|
|
iLev1 = -1; // we are already below the first var level
|
|
iLev2 = dd->perm[bVars->index]; // the level of the second var
|
|
}
|
|
else
|
|
{
|
|
assert( cuddT(cuddT(bVars)) == b1 );
|
|
iLev1 = dd->perm[bVars->index]; // the level of the first var
|
|
iLev2 = dd->perm[cuddT(bVars)->index]; // the level of the second var
|
|
}
|
|
}
|
|
|
|
// cofactor the function
|
|
// the cofactors are needed only if we are above the second level
|
|
if ( LevelF < iLev2 )
|
|
{
|
|
if ( bFR != bF ) // bFunc is complemented
|
|
{
|
|
bF0 = Cudd_Not( cuddE(bFR) );
|
|
bF1 = Cudd_Not( cuddT(bFR) );
|
|
}
|
|
else
|
|
{
|
|
bF0 = cuddE(bFR);
|
|
bF1 = cuddT(bFR);
|
|
}
|
|
}
|
|
else
|
|
bF0 = bF1 = NULL;
|
|
|
|
// consider five cases:
|
|
// (1) F is above iLev1
|
|
// (2) F is on the level iLev1
|
|
// (3) F is between iLev1 and iLev2
|
|
// (4) F is on the level iLev2
|
|
// (5) F is below iLev2
|
|
|
|
// (1) F is above iLev1
|
|
if ( LevelF < iLev1 )
|
|
{
|
|
// the returned result cannot have the hash attribute
|
|
// because we still did not reach the level of Var1;
|
|
// the attribute never travels above the level of Var1
|
|
bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars );
|
|
// assert( !Hash_IsComplement( bRes0 ) );
|
|
assert( bRes0 != z0 );
|
|
if ( bRes0 == b0 )
|
|
bRes = b0;
|
|
else
|
|
bRes = extraBddCheckVarsSymmetric( dd, bF1, bVars );
|
|
// assert( !Hash_IsComplement( bRes ) );
|
|
assert( bRes != z0 );
|
|
}
|
|
// (2) F is on the level iLev1
|
|
else if ( LevelF == iLev1 )
|
|
{
|
|
bRes0 = extraBddCheckVarsSymmetric( dd, bF0, Cudd_Not( cuddT(bVars) ) );
|
|
if ( bRes0 == b0 )
|
|
bRes = b0;
|
|
else
|
|
{
|
|
bRes1 = extraBddCheckVarsSymmetric( dd, bF1, Cudd_Not( cuddT(bVars) ) );
|
|
if ( bRes1 == b0 )
|
|
bRes = b0;
|
|
else
|
|
{
|
|
// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) )
|
|
if ( bRes0 == z0 || bRes1 == z0 )
|
|
bRes = b1;
|
|
else
|
|
bRes = b0;
|
|
}
|
|
}
|
|
}
|
|
// (3) F is between iLev1 and iLev2
|
|
else if ( LevelF < iLev2 )
|
|
{
|
|
bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars );
|
|
if ( bRes0 == b0 )
|
|
bRes = b0;
|
|
else
|
|
{
|
|
bRes1 = extraBddCheckVarsSymmetric( dd, bF1, bVars );
|
|
if ( bRes1 == b0 )
|
|
bRes = b0;
|
|
else
|
|
{
|
|
// if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) )
|
|
// bRes = Hash_Not( b1 );
|
|
if ( bRes0 == z0 || bRes1 == z0 )
|
|
bRes = z0;
|
|
else
|
|
bRes = b1;
|
|
}
|
|
}
|
|
}
|
|
// (4) F is on the level iLev2
|
|
else if ( LevelF == iLev2 )
|
|
{
|
|
// this is the only place where the hash attribute (Hash_Not) can be added
|
|
// to the result; it can be added only if the path came through the node
|
|
// lebeled with Var1; therefore, the hash attribute cannot be returned
|
|
// to the caller function
|
|
if ( fVar1Pres )
|
|
// bRes = Hash_Not( b1 );
|
|
bRes = z0;
|
|
else
|
|
bRes = b0;
|
|
}
|
|
// (5) F is below iLev2
|
|
else // if ( LevelF > iLev2 )
|
|
{
|
|
// it is possible that the path goes through the node labeled by Var1
|
|
// and still everything is okay; we do not label with Hash_Not here
|
|
// because the path does not go through node labeled by Var2
|
|
bRes = b1;
|
|
}
|
|
|
|
cuddCacheInsert2(dd, extraBddCheckVarsSymmetric, bF, bVars, bRes);
|
|
return bRes;
|
|
}
|
|
} /* end of extraBddCheckVarsSymmetric */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the reordering-sensitive step of Extra_zddTupleFromBdd().]
|
|
|
|
Description [Generates in a bottom-up fashion ZDD for all combinations
|
|
composed of k variables out of variables belonging to Support.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode* extraZddTuplesFromBdd(
|
|
DdManager * dd, /* the DD manager */
|
|
DdNode * bVarsK, /* the number of variables in tuples */
|
|
DdNode * bVarsN) /* the set of all variables */
|
|
{
|
|
DdNode *zRes, *zRes0, *zRes1;
|
|
statLine(dd);
|
|
|
|
/* terminal cases */
|
|
/* if ( k < 0 || k > n )
|
|
* return dd->zero;
|
|
* if ( n == 0 )
|
|
* return dd->one;
|
|
*/
|
|
if ( cuddI( dd, bVarsK->index ) < cuddI( dd, bVarsN->index ) )
|
|
return z0;
|
|
if ( bVarsN == b1 )
|
|
return z1;
|
|
|
|
/* check cache */
|
|
zRes = cuddCacheLookup2Zdd(dd, extraZddTuplesFromBdd, bVarsK, bVarsN);
|
|
if (zRes)
|
|
return(zRes);
|
|
|
|
/* ZDD in which this variable is 0 */
|
|
/* zRes0 = extraZddTuplesFromBdd( dd, k, n-1 ); */
|
|
zRes0 = extraZddTuplesFromBdd( dd, bVarsK, cuddT(bVarsN) );
|
|
if ( zRes0 == NULL )
|
|
return NULL;
|
|
cuddRef( zRes0 );
|
|
|
|
/* ZDD in which this variable is 1 */
|
|
/* zRes1 = extraZddTuplesFromBdd( dd, k-1, n-1 ); */
|
|
if ( bVarsK == b1 )
|
|
{
|
|
zRes1 = z0;
|
|
cuddRef( zRes1 );
|
|
}
|
|
else
|
|
{
|
|
zRes1 = extraZddTuplesFromBdd( dd, cuddT(bVarsK), cuddT(bVarsN) );
|
|
if ( zRes1 == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes0 );
|
|
return NULL;
|
|
}
|
|
cuddRef( zRes1 );
|
|
}
|
|
|
|
/* compose Res0 and Res1 with the given ZDD variable */
|
|
zRes = cuddZddGetNode( dd, 2*bVarsN->index, zRes1, zRes0 );
|
|
if ( zRes == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zRes0 );
|
|
Cudd_RecursiveDerefZdd( dd, zRes1 );
|
|
return NULL;
|
|
}
|
|
cuddDeref( zRes0 );
|
|
cuddDeref( zRes1 );
|
|
|
|
/* insert the result into cache */
|
|
cuddCacheInsert2(dd, extraZddTuplesFromBdd, bVarsK, bVarsN, zRes);
|
|
return zRes;
|
|
|
|
} /* end of extraZddTuplesFromBdd */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the recursive step of Extra_zddSelectOneSubset.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * extraZddSelectOneSubset(
|
|
DdManager * dd,
|
|
DdNode * zS )
|
|
// selects one subset from the ZDD zS
|
|
// returns z0 if and only if zS is an empty set of cubes
|
|
{
|
|
DdNode * zRes;
|
|
|
|
if ( zS == z0 ) return z0;
|
|
if ( zS == z1 ) return z1;
|
|
|
|
// check cache
|
|
if ( (zRes = cuddCacheLookup1Zdd( dd, extraZddSelectOneSubset, zS )) )
|
|
return zRes;
|
|
else
|
|
{
|
|
DdNode * zS0, * zS1, * zTemp;
|
|
|
|
zS0 = cuddE(zS);
|
|
zS1 = cuddT(zS);
|
|
|
|
if ( zS0 != z0 )
|
|
{
|
|
zRes = extraZddSelectOneSubset( dd, zS0 );
|
|
if ( zRes == NULL )
|
|
return NULL;
|
|
}
|
|
else // if ( zS0 == z0 )
|
|
{
|
|
assert( zS1 != z0 );
|
|
zRes = extraZddSelectOneSubset( dd, zS1 );
|
|
if ( zRes == NULL )
|
|
return NULL;
|
|
cuddRef( zRes );
|
|
|
|
zRes = cuddZddGetNode( dd, zS->index, zTemp = zRes, z0 );
|
|
if ( zRes == NULL )
|
|
{
|
|
Cudd_RecursiveDerefZdd( dd, zTemp );
|
|
return NULL;
|
|
}
|
|
cuddDeref( zTemp );
|
|
}
|
|
|
|
// insert the result into cache
|
|
cuddCacheInsert1( dd, extraZddSelectOneSubset, zS, zRes );
|
|
return zRes;
|
|
}
|
|
} /* end of extraZddSelectOneSubset */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static Functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
ABC_NAMESPACE_IMPL_END
|
|
|