mirror of https://github.com/YosysHQ/abc.git
1236 lines
43 KiB
C
1236 lines
43 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [extraBddCas.c]
|
|
|
|
PackageName [extra]
|
|
|
|
Synopsis [Procedures related to LUT cascade synthesis.]
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 2.0. Started - September 1, 2003.]
|
|
|
|
Revision [$Id: extraBddCas.c,v 1.0 2003/05/21 18:03:50 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "extraBdd.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Constant declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Stucture declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Type declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
// the table to store cofactor operations
|
|
#define _TABLESIZE_COF 51113
|
|
typedef struct
|
|
{
|
|
unsigned Sign;
|
|
DdNode * Arg1;
|
|
} _HashEntry_cof;
|
|
_HashEntry_cof HHTable1[_TABLESIZE_COF];
|
|
|
|
// the table to store the result of computation of the number of minterms
|
|
#define _TABLESIZE_MINT 15113
|
|
typedef struct
|
|
{
|
|
DdNode * Arg1;
|
|
unsigned Arg2;
|
|
unsigned Res;
|
|
} _HashEntry_mint;
|
|
_HashEntry_mint HHTable2[_TABLESIZE_MINT];
|
|
|
|
typedef struct
|
|
{
|
|
int nEdges; // the number of in-coming edges of the node
|
|
DdNode * bSum; // the sum of paths of the incoming edges
|
|
} traventry;
|
|
|
|
// the signature used for hashing
|
|
static unsigned s_Signature = 1;
|
|
|
|
static int s_CutLevel = 0;
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Variable declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
// because the proposed solution to the optimal encoding problem has exponential complexity
|
|
// we limit the depth of the branch and bound procedure to 5 levels
|
|
static int s_MaxDepth = 5;
|
|
|
|
static int s_nVarsBest; // the number of vars in the best ordering
|
|
static int s_VarOrderBest[32]; // storing the best ordering of vars in the "simple encoding"
|
|
static int s_VarOrderCur[32]; // storing the current ordering of vars
|
|
|
|
// the place to store the supports of the encoded function
|
|
static DdNode * s_Field[8][256]; // the size should be K, 2^K, where K is no less than MaxDepth
|
|
static DdNode * s_Encoded; // this is the original function
|
|
static DdNode * s_VarAll; // the set of all column variables
|
|
static int s_MultiStart; // the total number of encoding variables used
|
|
// the array field now stores the supports
|
|
|
|
static DdNode ** s_pbTemp; // the temporary storage for the columns
|
|
|
|
static int s_BackTracks;
|
|
static int s_BackTrackLimit = 100;
|
|
|
|
static DdNode * s_Terminal; // the terminal value for counting minterms
|
|
|
|
|
|
static int s_EncodingVarsLevel;
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Macro declarations */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
|
|
/**AutomaticStart*************************************************************/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Static function prototypes */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars );
|
|
static void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level );
|
|
// functions called from EvaluateEncodings_rec()
|
|
static DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost );
|
|
static DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost );
|
|
unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll );
|
|
static unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max );
|
|
|
|
static void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st__table * Visited );
|
|
static void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st__table * Visited, st__table * CutNodes );
|
|
|
|
/**AutomaticEnd***************************************************************/
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of exported functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Performs the binary encoding of the set of function using the given vars.]
|
|
|
|
Description [Performs a straight binary encoding of the set of functions using
|
|
the variable cubes formed from the given set of variables. ]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode *
|
|
Extra_bddEncodingBinary(
|
|
DdManager * dd,
|
|
DdNode ** pbFuncs, // pbFuncs is the array of columns to be encoded
|
|
int nFuncs, // nFuncs is the number of columns in the array
|
|
DdNode ** pbVars, // pbVars is the array of variables to use for the codes
|
|
int nVars ) // nVars is the column multiplicity, [log2(nFuncs)]
|
|
{
|
|
int i;
|
|
DdNode * bResult;
|
|
DdNode * bCube, * bTemp, * bProd;
|
|
|
|
assert( nVars >= Abc_Base2Log(nFuncs) );
|
|
|
|
bResult = b0; Cudd_Ref( bResult );
|
|
for ( i = 0; i < nFuncs; i++ )
|
|
{
|
|
bCube = Extra_bddBitsToCube( dd, i, nVars, pbVars, 1 ); Cudd_Ref( bCube );
|
|
bProd = Cudd_bddAnd( dd, bCube, pbFuncs[i] ); Cudd_Ref( bProd );
|
|
Cudd_RecursiveDeref( dd, bCube );
|
|
|
|
bResult = Cudd_bddOr( dd, bProd, bTemp = bResult ); Cudd_Ref( bResult );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
Cudd_RecursiveDeref( dd, bProd );
|
|
}
|
|
|
|
Cudd_Deref( bResult );
|
|
return bResult;
|
|
} /* end of Extra_bddEncodingBinary */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Solves the column encoding problem using a sophisticated method.]
|
|
|
|
Description [The encoding is based on the idea of deriving functions which
|
|
depend on only one variable, which corresponds to the case of non-disjoint
|
|
decompostion. It is assumed that the variables pCVars are ordered below the variables
|
|
representing the solumns, and the first variable pCVars[0] is the topmost one.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Extra_bddEncodingBinary]
|
|
|
|
******************************************************************************/
|
|
|
|
DdNode *
|
|
Extra_bddEncodingNonStrict(
|
|
DdManager * dd,
|
|
DdNode ** pbColumns, // pbColumns is the array of columns to be encoded;
|
|
int nColumns, // nColumns is the number of columns in the array
|
|
DdNode * bVarsCol, // bVarsCol is the cube of variables on which the columns depend
|
|
DdNode ** pCVars, // pCVars is the array of variables to use for the codes
|
|
int nMulti, // nMulti is the column multiplicity, [log2(nColumns)]
|
|
int * pSimple ) // pSimple gets the number of code variables taken from the input varibles without change
|
|
{
|
|
DdNode * bEncoded, * bResult;
|
|
int nVarsCol = Cudd_SupportSize(dd,bVarsCol);
|
|
abctime clk;
|
|
|
|
// cannot work with more that 32-bit codes
|
|
assert( nMulti < 32 );
|
|
|
|
// perform the preliminary encoding using the straight binary code
|
|
bEncoded = Extra_bddEncodingBinary( dd, pbColumns, nColumns, pCVars, nMulti ); Cudd_Ref( bEncoded );
|
|
//printf( "Node count = %d", Cudd_DagSize(bEncoded) );
|
|
|
|
// set the backgroup value for counting minterms
|
|
s_Terminal = b0;
|
|
// set the level of the encoding variables
|
|
s_EncodingVarsLevel = dd->invperm[pCVars[0]->index];
|
|
|
|
// the current number of backtracks
|
|
s_BackTracks = 0;
|
|
// the variables that are cofactored on the topmost level where everything starts (no vars)
|
|
s_Field[0][0] = b1;
|
|
// the size of the best set of "simple" encoding variables found so far
|
|
s_nVarsBest = 0;
|
|
|
|
// set the relation to be accessible to traversal procedures
|
|
s_Encoded = bEncoded;
|
|
// the set of all vars to be accessible to traversal procedures
|
|
s_VarAll = bVarsCol;
|
|
// the column multiplicity
|
|
s_MultiStart = nMulti;
|
|
|
|
|
|
clk = Abc_Clock();
|
|
// find the simplest encoding
|
|
if ( nColumns > 2 )
|
|
EvaluateEncodings_rec( dd, bVarsCol, nVarsCol, nMulti, 1 );
|
|
// printf( "The number of backtracks = %d\n", s_BackTracks );
|
|
// s_EncSearchTime += Abc_Clock() - clk;
|
|
|
|
// allocate the temporary storage for the columns
|
|
s_pbTemp = (DdNode **)ABC_ALLOC( char, nColumns * sizeof(DdNode *) );
|
|
|
|
// clk = Abc_Clock();
|
|
bResult = CreateTheCodes_rec( dd, bEncoded, 0, pCVars ); Cudd_Ref( bResult );
|
|
// s_EncComputeTime += Abc_Clock() - clk;
|
|
|
|
// delocate the preliminarily encoded set
|
|
Cudd_RecursiveDeref( dd, bEncoded );
|
|
// Cudd_RecursiveDeref( dd, aEncoded );
|
|
|
|
ABC_FREE( s_pbTemp );
|
|
|
|
*pSimple = s_nVarsBest;
|
|
Cudd_Deref( bResult );
|
|
return bResult;
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Collects the nodes under the cut and, for each node, computes the sum of paths leading to it from the root.]
|
|
|
|
Description [The table returned contains the set of BDD nodes pointed to under the cut
|
|
and, for each node, the BDD of the sum of paths leading to this node from the root
|
|
The sums of paths in the table are referenced. CutLevel is the first DD level
|
|
considered to be under the cut.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Extra_bddNodePaths]
|
|
|
|
******************************************************************************/
|
|
st__table * Extra_bddNodePathsUnderCut( DdManager * dd, DdNode * bFunc, int CutLevel )
|
|
{
|
|
st__table * Visited; // temporary table to remember the visited nodes
|
|
st__table * CutNodes; // the result goes here
|
|
st__table * Result; // the result goes here
|
|
DdNode * aFunc;
|
|
|
|
s_CutLevel = CutLevel;
|
|
|
|
Result = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
// the terminal cases
|
|
if ( Cudd_IsConstant( bFunc ) )
|
|
{
|
|
if ( bFunc == b1 )
|
|
{
|
|
st__insert( Result, (char*)b1, (char*)b1 );
|
|
Cudd_Ref( b1 );
|
|
Cudd_Ref( b1 );
|
|
}
|
|
else
|
|
{
|
|
st__insert( Result, (char*)b0, (char*)b0 );
|
|
Cudd_Ref( b0 );
|
|
Cudd_Ref( b0 );
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
// create the ADD to simplify processing (no complemented edges)
|
|
aFunc = Cudd_BddToAdd( dd, bFunc ); Cudd_Ref( aFunc );
|
|
|
|
// Step 1: Start the tables and collect information about the nodes above the cut
|
|
// this information tells how many edges point to each node
|
|
Visited = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
CutNodes = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
|
|
CountNodeVisits_rec( dd, aFunc, Visited );
|
|
|
|
// Step 2: Traverse the BDD using the visited table and compute the sum of paths
|
|
CollectNodesAndComputePaths_rec( dd, aFunc, b1, Visited, CutNodes );
|
|
|
|
// at this point the table of cut nodes is ready and the table of visited is useless
|
|
{
|
|
st__generator * gen;
|
|
DdNode * aNode;
|
|
traventry * p;
|
|
st__foreach_item( Visited, gen, (const char**)&aNode, (char**)&p )
|
|
{
|
|
Cudd_RecursiveDeref( dd, p->bSum );
|
|
ABC_FREE( p );
|
|
}
|
|
st__free_table( Visited );
|
|
}
|
|
|
|
// go through the table CutNodes and create the BDD and the path to be returned
|
|
{
|
|
st__generator * gen;
|
|
DdNode * aNode, * bNode, * bSum;
|
|
st__foreach_item( CutNodes, gen, (const char**)&aNode, (char**)&bSum)
|
|
{
|
|
// aNode is not referenced, because aFunc is holding it
|
|
bNode = Cudd_addBddPattern( dd, aNode ); Cudd_Ref( bNode );
|
|
st__insert( Result, (char*)bNode, (char*)bSum );
|
|
// the new table takes both refs
|
|
}
|
|
st__free_table( CutNodes );
|
|
}
|
|
|
|
// dereference the ADD
|
|
Cudd_RecursiveDeref( dd, aFunc );
|
|
|
|
// return the table
|
|
return Result;
|
|
|
|
} /* end of Extra_bddNodePathsUnderCut */
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Collects the nodes under the cut in the ADD starting from the given set of ADD nodes.]
|
|
|
|
Description [Takes the array, paNodes, of ADD nodes to start the traversal,
|
|
the array, pbCubes, of BDD cubes to start the traversal with in each node,
|
|
and the number, nNodes, of ADD nodes and BDD cubes in paNodes and pbCubes.
|
|
Returns the number of columns found. Fills in paNodesRes (pbCubesRes)
|
|
with the set of ADD columns (BDD paths). These arrays should be allocated
|
|
by the user.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso [Extra_bddNodePaths]
|
|
|
|
******************************************************************************/
|
|
int Extra_bddNodePathsUnderCutArray( DdManager * dd, DdNode ** paNodes, DdNode ** pbCubes, int nNodes, DdNode ** paNodesRes, DdNode ** pbCubesRes, int CutLevel )
|
|
{
|
|
st__table * Visited; // temporary table to remember the visited nodes
|
|
st__table * CutNodes; // the nodes under the cut go here
|
|
int i, Counter;
|
|
|
|
s_CutLevel = CutLevel;
|
|
|
|
// there should be some nodes
|
|
assert( nNodes > 0 );
|
|
if ( nNodes == 1 && Cudd_IsConstant( paNodes[0] ) )
|
|
{
|
|
if ( paNodes[0] == a1 )
|
|
{
|
|
paNodesRes[0] = a1; Cudd_Ref( a1 );
|
|
pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] );
|
|
}
|
|
else
|
|
{
|
|
paNodesRes[0] = a0; Cudd_Ref( a0 );
|
|
pbCubesRes[0] = pbCubes[0]; Cudd_Ref( pbCubes[0] );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
// Step 1: Start the table and collect information about the nodes above the cut
|
|
// this information tells how many edges point to each node
|
|
CutNodes = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
Visited = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
|
|
for ( i = 0; i < nNodes; i++ )
|
|
CountNodeVisits_rec( dd, paNodes[i], Visited );
|
|
|
|
// Step 2: Traverse the BDD using the visited table and compute the sum of paths
|
|
for ( i = 0; i < nNodes; i++ )
|
|
CollectNodesAndComputePaths_rec( dd, paNodes[i], pbCubes[i], Visited, CutNodes );
|
|
|
|
// at this point, the table of cut nodes is ready and the table of visited is useless
|
|
{
|
|
st__generator * gen;
|
|
DdNode * aNode;
|
|
traventry * p;
|
|
st__foreach_item( Visited, gen, (const char**)&aNode, (char**)&p )
|
|
{
|
|
Cudd_RecursiveDeref( dd, p->bSum );
|
|
ABC_FREE( p );
|
|
}
|
|
st__free_table( Visited );
|
|
}
|
|
|
|
// go through the table CutNodes and create the BDD and the path to be returned
|
|
{
|
|
st__generator * gen;
|
|
DdNode * aNode, * bSum;
|
|
Counter = 0;
|
|
st__foreach_item( CutNodes, gen, (const char**)&aNode, (char**)&bSum)
|
|
{
|
|
paNodesRes[Counter] = aNode; Cudd_Ref( aNode );
|
|
pbCubesRes[Counter] = bSum;
|
|
Counter++;
|
|
}
|
|
st__free_table( CutNodes );
|
|
}
|
|
|
|
// return the number of cofactors found
|
|
return Counter;
|
|
|
|
} /* end of Extra_bddNodePathsUnderCutArray */
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects all the BDD nodes into the table.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void extraCollectNodes( DdNode * Func, st__table * tNodes )
|
|
{
|
|
DdNode * FuncR;
|
|
FuncR = Cudd_Regular(Func);
|
|
if ( st__find_or_add( tNodes, (char*)FuncR, NULL ) )
|
|
return;
|
|
if ( cuddIsConstant(FuncR) )
|
|
return;
|
|
extraCollectNodes( cuddE(FuncR), tNodes );
|
|
extraCollectNodes( cuddT(FuncR), tNodes );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Collects all the nodes of one DD into the table.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
st__table * Extra_CollectNodes( DdNode * Func )
|
|
{
|
|
st__table * tNodes;
|
|
tNodes = st__init_table( st__ptrcmp, st__ptrhash );
|
|
extraCollectNodes( Func, tNodes );
|
|
return tNodes;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Updates the topmost level from which the given node is referenced.]
|
|
|
|
Description [Takes the table which maps each BDD nodes (including the constants)
|
|
into the topmost level on which this node counts as a cofactor. Takes the topmost
|
|
level, on which this node counts as a cofactor (see Extra_ProfileWidthFast().
|
|
Takes the node, for which the table entry should be updated.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void extraProfileUpdateTopLevel( st__table * tNodeTopRef, int TopLevelNew, DdNode * node )
|
|
{
|
|
int * pTopLevel;
|
|
|
|
if ( st__find_or_add( tNodeTopRef, (char*)node, (char***)&pTopLevel ) )
|
|
{ // the node is already referenced
|
|
// the current top level should be updated if it is larger than the new level
|
|
if ( *pTopLevel > TopLevelNew )
|
|
*pTopLevel = TopLevelNew;
|
|
}
|
|
else
|
|
{ // the node is not referenced
|
|
// its level should be set to the current new level
|
|
*pTopLevel = TopLevelNew;
|
|
}
|
|
}
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Fast computation of the BDD profile.]
|
|
|
|
Description [The array to store the profile is given by the user and should
|
|
contain at least as many entries as there is the maximum of the BDD/ZDD
|
|
size of the manager PLUS ONE.
|
|
When we say that the widths of the DD on level L is W, we mean the following.
|
|
Let us create the cut between the level L-1 and the level L and count the number
|
|
of different DD nodes pointed to across the cut. This number is the width W.
|
|
From this it follows the on level 0, the width is equal to the number of external
|
|
pointers to the considered DDs. If there is only one DD, then the profile on
|
|
level 0 is always 1. If this DD is rooted in the topmost variable, then the width
|
|
on level 1 is always 2, etc. The width at the level equal to dd->size is the
|
|
number of terminal nodes in the DD. (Because we consider the first level #0
|
|
and the last level #dd->size, the profile array should contain dd->size+1 entries.)
|
|
]
|
|
|
|
SideEffects [This procedure will not work for BDDs w/ complement edges, only for ADDs and ZDDs]
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Extra_ProfileWidth( DdManager * dd, DdNode * Func, int * pProfile, int CutLevel )
|
|
{
|
|
st__generator * gen;
|
|
st__table * tNodeTopRef; // this table stores the top level from which this node is pointed to
|
|
st__table * tNodes;
|
|
DdNode * node;
|
|
DdNode * nodeR;
|
|
int LevelStart, Limit;
|
|
int i, size;
|
|
int WidthMax;
|
|
|
|
// start the mapping table
|
|
tNodeTopRef = st__init_table( st__ptrcmp, st__ptrhash);;
|
|
// add the topmost node to the profile
|
|
extraProfileUpdateTopLevel( tNodeTopRef, 0, Func );
|
|
|
|
// collect all nodes
|
|
tNodes = Extra_CollectNodes( Func );
|
|
// go though all the nodes and set the top level the cofactors are pointed from
|
|
// Cudd_ForeachNode( dd, Func, genDD, node )
|
|
st__foreach_item( tNodes, gen, (const char**)&node, NULL )
|
|
{
|
|
// assert( Cudd_Regular(node) ); // this procedure works only with ADD/ZDD (not BDD w/ compl.edges)
|
|
nodeR = Cudd_Regular(node);
|
|
if ( cuddIsConstant(nodeR) )
|
|
continue;
|
|
// this node is not a constant - consider its cofactors
|
|
extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddE(nodeR) );
|
|
extraProfileUpdateTopLevel( tNodeTopRef, dd->perm[node->index]+1, cuddT(nodeR) );
|
|
}
|
|
st__free_table( tNodes );
|
|
|
|
// clean the profile
|
|
size = ddMax(dd->size, dd->sizeZ) + 1;
|
|
for ( i = 0; i < size; i++ )
|
|
pProfile[i] = 0;
|
|
|
|
// create the profile
|
|
st__foreach_item( tNodeTopRef, gen, (const char**)&node, (char**)&LevelStart )
|
|
{
|
|
nodeR = Cudd_Regular(node);
|
|
Limit = (cuddIsConstant(nodeR))? dd->size: dd->perm[nodeR->index];
|
|
for ( i = LevelStart; i <= Limit; i++ )
|
|
pProfile[i]++;
|
|
}
|
|
|
|
if ( CutLevel != -1 && CutLevel != 0 )
|
|
size = CutLevel;
|
|
|
|
// get the max width
|
|
WidthMax = 0;
|
|
for ( i = 0; i < size; i++ )
|
|
if ( WidthMax < pProfile[i] )
|
|
WidthMax = pProfile[i];
|
|
|
|
// deref the table
|
|
st__free_table( tNodeTopRef );
|
|
|
|
return WidthMax;
|
|
} /* end of Extra_ProfileWidth */
|
|
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of internal functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Definition of static functions */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes the non-strict codes when evaluation is finished.]
|
|
|
|
Description [The information about the best code is stored in s_VarOrderBest,
|
|
which has s_nVarsBest entries.]
|
|
|
|
SideEffects [None]
|
|
|
|
******************************************************************************/
|
|
DdNode * CreateTheCodes_rec( DdManager * dd, DdNode * bEncoded, int Level, DdNode ** pCVars )
|
|
// bEncoded is the preliminarily encoded set of columns
|
|
// Level is the current level in the recursion
|
|
// pCVars are the variables to be used for encoding
|
|
{
|
|
DdNode * bRes;
|
|
if ( Level == s_nVarsBest )
|
|
{ // the terminal case, when we need to remap the encoded function
|
|
// from the preliminary encoded variables to the new ones
|
|
st__table * CutNodes;
|
|
int nCols;
|
|
// double nMints;
|
|
/*
|
|
#ifdef _DEBUG
|
|
|
|
{
|
|
DdNode * bTemp;
|
|
// make sure that the given number of variables is enough
|
|
bTemp = Cudd_bddExistAbstract( dd, bEncoded, s_VarAll ); Cudd_Ref( bTemp );
|
|
// nMints = Cudd_CountMinterm( dd, bTemp, s_MultiStart );
|
|
nMints = Extra_CountMintermsSimple( bTemp, (1<<s_MultiStart) );
|
|
if ( nMints > Extra_Power2( s_MultiStart-Level ) )
|
|
{ // the number of minterms is too large to encode the columns
|
|
// using the given minimum number of encoding variables
|
|
assert( 0 );
|
|
}
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
}
|
|
#endif
|
|
*/
|
|
// get the columns to be re-encoded
|
|
CutNodes = Extra_bddNodePathsUnderCut( dd, bEncoded, s_EncodingVarsLevel );
|
|
// LUT size is the cut level because because the temporary encoding variables
|
|
// are above the functional variables - this is not true!!!
|
|
// the temporary variables are below!
|
|
|
|
// put the entries from the table into the temporary array
|
|
{
|
|
st__generator * gen;
|
|
DdNode * bColumn, * bCode;
|
|
nCols = 0;
|
|
st__foreach_item( CutNodes, gen, (const char**)&bCode, (char**)&bColumn )
|
|
{
|
|
if ( bCode == b0 )
|
|
{ // the unused part of the columns
|
|
Cudd_RecursiveDeref( dd, bColumn );
|
|
Cudd_RecursiveDeref( dd, bCode );
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
s_pbTemp[ nCols ] = bColumn; // takes ref
|
|
Cudd_RecursiveDeref( dd, bCode );
|
|
nCols++;
|
|
}
|
|
}
|
|
st__free_table( CutNodes );
|
|
// assert( nCols == (int)nMints );
|
|
}
|
|
|
|
// encode the columns
|
|
if ( s_MultiStart-Level == 0 ) // we reached the bottom level of recursion
|
|
{
|
|
assert( nCols == 1 );
|
|
// assert( (int)nMints == 1 );
|
|
bRes = s_pbTemp[0]; Cudd_Ref( bRes );
|
|
}
|
|
else
|
|
{
|
|
bRes = Extra_bddEncodingBinary( dd, s_pbTemp, nCols, pCVars+Level, s_MultiStart-Level ); Cudd_Ref( bRes );
|
|
}
|
|
|
|
// deref the columns
|
|
{
|
|
int i;
|
|
for ( i = 0; i < nCols; i++ )
|
|
Cudd_RecursiveDeref( dd, s_pbTemp[i] );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// cofactor the problem as specified in the best solution
|
|
DdNode * bCof0, * bCof1;
|
|
DdNode * bRes0, * bRes1;
|
|
DdNode * bProd0, * bProd1;
|
|
DdNode * bTemp;
|
|
DdNode * bVarNext = dd->vars[ s_VarOrderBest[Level] ];
|
|
|
|
bCof0 = Cudd_Cofactor( dd, bEncoded, Cudd_Not( bVarNext ) ); Cudd_Ref( bCof0 );
|
|
bCof1 = Cudd_Cofactor( dd, bEncoded, bVarNext ); Cudd_Ref( bCof1 );
|
|
|
|
// call recursively
|
|
bRes0 = CreateTheCodes_rec( dd, bCof0, Level+1, pCVars ); Cudd_Ref( bRes0 );
|
|
bRes1 = CreateTheCodes_rec( dd, bCof1, Level+1, pCVars ); Cudd_Ref( bRes1 );
|
|
|
|
Cudd_RecursiveDeref( dd, bCof0 );
|
|
Cudd_RecursiveDeref( dd, bCof1 );
|
|
|
|
// compose the result using the identity (bVarNext <=> pCVars[Level]) - this is wrong!
|
|
// compose the result as follows: x'y'F0 + xyF1
|
|
bProd0 = Cudd_bddAnd( dd, Cudd_Not(bVarNext), Cudd_Not(pCVars[Level]) ); Cudd_Ref( bProd0 );
|
|
bProd1 = Cudd_bddAnd( dd, bVarNext , pCVars[Level] ); Cudd_Ref( bProd1 );
|
|
|
|
bProd0 = Cudd_bddAnd( dd, bTemp = bProd0, bRes0 ); Cudd_Ref( bProd0 );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
Cudd_RecursiveDeref( dd, bRes0 );
|
|
|
|
bProd1 = Cudd_bddAnd( dd, bTemp = bProd1, bRes1 ); Cudd_Ref( bProd1 );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
Cudd_RecursiveDeref( dd, bRes1 );
|
|
|
|
bRes = Cudd_bddOr( dd, bProd0, bProd1 ); Cudd_Ref( bRes );
|
|
|
|
Cudd_RecursiveDeref( dd, bProd0 );
|
|
Cudd_RecursiveDeref( dd, bProd1 );
|
|
}
|
|
Cudd_Deref( bRes );
|
|
return bRes;
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes the current set of variables and counts the number of minterms.]
|
|
|
|
Description [Old implementation.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void EvaluateEncodings_rec( DdManager * dd, DdNode * bVarsCol, int nVarsCol, int nMulti, int Level )
|
|
// bVarsCol is the set of remaining variables
|
|
// nVarsCol is the number of remaining variables
|
|
// nMulti is the number of encoding variables to be used
|
|
// Level is the level of recursion, from which this function is called
|
|
// if we successfully finish this procedure, Level also stands for how many encoding variabled we saved
|
|
{
|
|
int i, k;
|
|
int nEntries = (1<<(Level-1)); // the number of entries in the field of the previous level
|
|
DdNode * bVars0, * bVars1; // the cofactors
|
|
unsigned nMint0, nMint1; // the number of minterms
|
|
DdNode * bTempV;
|
|
DdNode * bVarTop;
|
|
int fBreak;
|
|
|
|
|
|
// there is no need to search above this level
|
|
if ( Level > s_MaxDepth )
|
|
return;
|
|
|
|
// if there are no variables left, quit the research
|
|
if ( bVarsCol == b1 )
|
|
return;
|
|
|
|
if ( s_BackTracks > s_BackTrackLimit )
|
|
return;
|
|
|
|
s_BackTracks++;
|
|
|
|
// otherwise, go through the remaining variables
|
|
for ( bTempV = bVarsCol; bTempV != b1; bTempV = cuddT(bTempV) )
|
|
{
|
|
// the currently tested variable
|
|
bVarTop = dd->vars[bTempV->index];
|
|
|
|
// put it into the array
|
|
s_VarOrderCur[Level-1] = bTempV->index;
|
|
|
|
// go through the entries and fill them out by cofactoring
|
|
fBreak = 0;
|
|
for ( i = 0; i < nEntries; i++ )
|
|
{
|
|
bVars0 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], Cudd_Not(bVarTop), &nMint0 );
|
|
Cudd_Ref( bVars0 );
|
|
|
|
if ( nMint0 > Extra_Power2( nMulti-1 ) )
|
|
{
|
|
// there is no way to encode - dereference and return
|
|
Cudd_RecursiveDeref( dd, bVars0 );
|
|
fBreak = 1;
|
|
break;
|
|
}
|
|
|
|
bVars1 = ComputeVarSetAndCountMinterms( dd, s_Field[Level-1][i], bVarTop, &nMint1 );
|
|
Cudd_Ref( bVars1 );
|
|
|
|
if ( nMint1 > Extra_Power2( nMulti-1 ) )
|
|
{
|
|
// there is no way to encode - dereference and return
|
|
Cudd_RecursiveDeref( dd, bVars0 );
|
|
Cudd_RecursiveDeref( dd, bVars1 );
|
|
fBreak = 1;
|
|
break;
|
|
}
|
|
|
|
// otherwise, add these two cofactors
|
|
s_Field[Level][2*i + 0] = bVars0; // takes ref
|
|
s_Field[Level][2*i + 1] = bVars1; // takes ref
|
|
}
|
|
|
|
if ( !fBreak )
|
|
{
|
|
DdNode * bVarsRem;
|
|
// if we ended up here, it means that the cofactors w.r.t. variable bVarTop satisfy the condition
|
|
// save this situation
|
|
if ( s_nVarsBest < Level )
|
|
{
|
|
s_nVarsBest = Level;
|
|
// copy the variable assignment
|
|
for ( k = 0; k < Level; k++ )
|
|
s_VarOrderBest[k] = s_VarOrderCur[k];
|
|
}
|
|
|
|
// call recursively
|
|
// get the new variable set
|
|
if ( nMulti-1 > 0 )
|
|
{
|
|
bVarsRem = Cudd_bddExistAbstract( dd, bVarsCol, bVarTop ); Cudd_Ref( bVarsRem );
|
|
EvaluateEncodings_rec( dd, bVarsRem, nVarsCol-1, nMulti-1, Level+1 );
|
|
Cudd_RecursiveDeref( dd, bVarsRem );
|
|
}
|
|
}
|
|
|
|
// deref the contents of the array
|
|
for ( k = 0; k < i; k++ )
|
|
{
|
|
Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 0] );
|
|
Cudd_RecursiveDeref( dd, s_Field[Level][2*k + 1] );
|
|
}
|
|
|
|
// if the solution is found, there is no need to continue
|
|
if ( s_nVarsBest == s_MaxDepth )
|
|
return;
|
|
|
|
// if the solution is found, there is no need to continue
|
|
if ( s_nVarsBest == s_MultiStart )
|
|
return;
|
|
}
|
|
// at this point, we have tried all possible directions in the space of variables
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes the current set of variables and counts the number of minterms.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * ComputeVarSetAndCountMinterms( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost )
|
|
// takes bVars - the variables cofactored so far (some of them may be in negative polarity)
|
|
// bVarTop - the topmost variable w.r.t. which to cofactor (may be in negative polarity)
|
|
// returns the cost and the new set of variables (bVars & bVarTop)
|
|
{
|
|
DdNode * bVarsRes;
|
|
|
|
// get the resulting set of variables
|
|
bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes );
|
|
|
|
// increment signature before calling Cudd_CountCofactorMinterms()
|
|
s_Signature++;
|
|
*Cost = Extra_CountCofactorMinterms( dd, s_Encoded, bVarsRes, s_VarAll );
|
|
|
|
Cudd_Deref( bVarsRes );
|
|
// s_CountCalls++;
|
|
return bVarsRes;
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Computes the current set of variables and counts the number of minterms.]
|
|
|
|
Description [The old implementation, which is approximately 4 times slower.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
DdNode * ComputeVarSetAndCountMinterms2( DdManager * dd, DdNode * bVars, DdNode * bVarTop, unsigned * Cost )
|
|
{
|
|
DdNode * bVarsRes;
|
|
DdNode * bCof, * bFun;
|
|
|
|
bVarsRes = Cudd_bddAnd( dd, bVars, bVarTop ); Cudd_Ref( bVarsRes );
|
|
|
|
bCof = Cudd_Cofactor( dd, s_Encoded, bVarsRes ); Cudd_Ref( bCof );
|
|
bFun = Cudd_bddExistAbstract( dd, bCof, s_VarAll ); Cudd_Ref( bFun );
|
|
*Cost = (unsigned)Cudd_CountMinterm( dd, bFun, s_MultiStart );
|
|
Cudd_RecursiveDeref( dd, bFun );
|
|
Cudd_RecursiveDeref( dd, bCof );
|
|
|
|
Cudd_Deref( bVarsRes );
|
|
// s_CountCalls++;
|
|
return bVarsRes;
|
|
}
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Counts the number of encoding minterms pointed to by the cofactor of the function.]
|
|
|
|
Description []
|
|
|
|
SideEffects [None]
|
|
|
|
******************************************************************************/
|
|
unsigned Extra_CountCofactorMinterms( DdManager * dd, DdNode * bFunc, DdNode * bVarsCof, DdNode * bVarsAll )
|
|
// this function computes how many minterms depending on the encoding variables
|
|
// are there in the cofactor of bFunc w.r.t. variables bVarsCof
|
|
// bFunc is assumed to depend on variables s_VarsAll
|
|
// the variables s_VarsAll should be ordered above the encoding variables
|
|
{
|
|
unsigned HKey;
|
|
DdNode * bFuncR;
|
|
|
|
// if the function is zero, there are no minterms
|
|
// if ( bFunc == b0 )
|
|
// return 0;
|
|
|
|
// if ( st__lookup(Visited, (char*)bFunc, NULL) )
|
|
// return 0;
|
|
|
|
// HKey = hashKey2c( s_Signature, bFuncR );
|
|
// if ( HHTable1[HKey].Sign == s_Signature && HHTable1[HKey].Arg1 == bFuncR ) // this node is visited
|
|
// return 0;
|
|
|
|
|
|
// check the hash-table
|
|
bFuncR = Cudd_Regular(bFunc);
|
|
// HKey = hashKey2( s_Signature, bFuncR, _TABLESIZE_COF );
|
|
HKey = hashKey2( s_Signature, bFunc, _TABLESIZE_COF );
|
|
for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF )
|
|
// if ( HHTable1[HKey].Arg1 == bFuncR ) // this node is visited
|
|
if ( HHTable1[HKey].Arg1 == bFunc ) // this node is visited
|
|
return 0;
|
|
|
|
|
|
// if the function is already the code
|
|
if ( dd->perm[bFuncR->index] >= s_EncodingVarsLevel )
|
|
{
|
|
// st__insert(Visited, (char*)bFunc, NULL);
|
|
|
|
// HHTable1[HKey].Sign = s_Signature;
|
|
// HHTable1[HKey].Arg1 = bFuncR;
|
|
|
|
assert( HHTable1[HKey].Sign != s_Signature );
|
|
HHTable1[HKey].Sign = s_Signature;
|
|
// HHTable1[HKey].Arg1 = bFuncR;
|
|
HHTable1[HKey].Arg1 = bFunc;
|
|
|
|
return Extra_CountMintermsSimple( bFunc, (1<<s_MultiStart) );
|
|
}
|
|
else
|
|
{
|
|
DdNode * bFunc0, * bFunc1;
|
|
DdNode * bVarsCof0, * bVarsCof1;
|
|
DdNode * bVarsCofR = Cudd_Regular(bVarsCof);
|
|
unsigned Res;
|
|
|
|
// get the levels
|
|
int LevelF = dd->perm[bFuncR->index];
|
|
int LevelC = cuddI(dd,bVarsCofR->index);
|
|
int LevelA = dd->perm[bVarsAll->index];
|
|
|
|
int LevelTop = LevelF;
|
|
|
|
if ( LevelTop > LevelC )
|
|
LevelTop = LevelC;
|
|
|
|
if ( LevelTop > LevelA )
|
|
LevelTop = LevelA;
|
|
|
|
// the top var in the function or in cofactoring vars always belongs to the set of all vars
|
|
assert( !( LevelTop == LevelF || LevelTop == LevelC ) || LevelTop == LevelA );
|
|
|
|
// cofactor the function
|
|
if ( LevelTop == LevelF )
|
|
{
|
|
if ( bFuncR != bFunc ) // bFunc is complemented
|
|
{
|
|
bFunc0 = Cudd_Not( cuddE(bFuncR) );
|
|
bFunc1 = Cudd_Not( cuddT(bFuncR) );
|
|
}
|
|
else
|
|
{
|
|
bFunc0 = cuddE(bFuncR);
|
|
bFunc1 = cuddT(bFuncR);
|
|
}
|
|
}
|
|
else // bVars is higher in the variable order
|
|
bFunc0 = bFunc1 = bFunc;
|
|
|
|
// cofactor the cube
|
|
if ( LevelTop == LevelC )
|
|
{
|
|
if ( bVarsCofR != bVarsCof ) // bFunc is complemented
|
|
{
|
|
bVarsCof0 = Cudd_Not( cuddE(bVarsCofR) );
|
|
bVarsCof1 = Cudd_Not( cuddT(bVarsCofR) );
|
|
}
|
|
else
|
|
{
|
|
bVarsCof0 = cuddE(bVarsCofR);
|
|
bVarsCof1 = cuddT(bVarsCofR);
|
|
}
|
|
}
|
|
else // bVars is higher in the variable order
|
|
bVarsCof0 = bVarsCof1 = bVarsCof;
|
|
|
|
// there are two cases:
|
|
// (1) the top variable belongs to the cofactoring variables
|
|
// (2) the top variable does not belong to the cofactoring variables
|
|
|
|
// (1) the top variable belongs to the cofactoring variables
|
|
Res = 0;
|
|
if ( LevelTop == LevelC )
|
|
{
|
|
if ( bVarsCof1 == b0 ) // this is a negative cofactor
|
|
{
|
|
if ( bFunc0 != b0 )
|
|
Res = Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) );
|
|
}
|
|
else // this is a positive cofactor
|
|
{
|
|
if ( bFunc1 != b0 )
|
|
Res = Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( bFunc0 != b0 )
|
|
Res += Extra_CountCofactorMinterms( dd, bFunc0, bVarsCof0, cuddT(bVarsAll) );
|
|
|
|
if ( bFunc1 != b0 )
|
|
Res += Extra_CountCofactorMinterms( dd, bFunc1, bVarsCof1, cuddT(bVarsAll) );
|
|
}
|
|
|
|
// st__insert(Visited, (char*)bFunc, NULL);
|
|
|
|
// HHTable1[HKey].Sign = s_Signature;
|
|
// HHTable1[HKey].Arg1 = bFuncR;
|
|
|
|
// skip through the entries with the same signatures
|
|
// (these might have been created at the time of recursive calls)
|
|
for ( ; HHTable1[HKey].Sign == s_Signature; HKey = (HKey+1) % _TABLESIZE_COF );
|
|
assert( HHTable1[HKey].Sign != s_Signature );
|
|
HHTable1[HKey].Sign = s_Signature;
|
|
// HHTable1[HKey].Arg1 = bFuncR;
|
|
HHTable1[HKey].Arg1 = bFunc;
|
|
|
|
return Res;
|
|
}
|
|
}
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Counts the number of minterms.]
|
|
|
|
Description [This function counts minterms for functions up to 32 variables
|
|
using a local cache. The terminal value (s_Termina) should be adjusted for
|
|
BDDs and ADDs.]
|
|
|
|
SideEffects [None]
|
|
|
|
******************************************************************************/
|
|
unsigned Extra_CountMintermsSimple( DdNode * bFunc, unsigned max )
|
|
{
|
|
unsigned HKey;
|
|
|
|
// normalize
|
|
if ( Cudd_IsComplement(bFunc) )
|
|
return max - Extra_CountMintermsSimple( Cudd_Not(bFunc), max );
|
|
|
|
// now it is known that the function is not complemented
|
|
if ( cuddIsConstant(bFunc) )
|
|
return ((bFunc==s_Terminal)? 0: max);
|
|
|
|
// check cache
|
|
HKey = hashKey2( bFunc, max, _TABLESIZE_MINT );
|
|
if ( HHTable2[HKey].Arg1 == bFunc && HHTable2[HKey].Arg2 == max )
|
|
return HHTable2[HKey].Res;
|
|
else
|
|
{
|
|
// min = min0/2 + min1/2;
|
|
unsigned min = (Extra_CountMintermsSimple( cuddE(bFunc), max ) >> 1) +
|
|
(Extra_CountMintermsSimple( cuddT(bFunc), max ) >> 1);
|
|
|
|
HHTable2[HKey].Arg1 = bFunc;
|
|
HHTable2[HKey].Arg2 = max;
|
|
HHTable2[HKey].Res = min;
|
|
|
|
return min;
|
|
}
|
|
} /* end of Extra_CountMintermsSimple */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Visits the nodes.]
|
|
|
|
Description [Visits the nodes above the cut and the nodes pointed to below the cut;
|
|
collects the visited nodes, counts how many times each node is visited, and sets
|
|
the path-sum to be the constant zero BDD.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void CountNodeVisits_rec( DdManager * dd, DdNode * aFunc, st__table * Visited )
|
|
|
|
{
|
|
traventry * p;
|
|
char **slot;
|
|
if ( st__find_or_add(Visited, (char*)aFunc, &slot) )
|
|
{ // the entry already exists
|
|
p = (traventry*) *slot;
|
|
// increment the counter of incoming edges
|
|
p->nEdges++;
|
|
return;
|
|
}
|
|
// this node has not been visited
|
|
assert( !Cudd_IsComplement(aFunc) );
|
|
|
|
// create the new traversal entry
|
|
p = (traventry *) ABC_ALLOC( char, sizeof(traventry) );
|
|
// set the initial sum of edges to zero BDD
|
|
p->bSum = b0; Cudd_Ref( b0 );
|
|
// set the starting number of incoming edges
|
|
p->nEdges = 1;
|
|
// set this entry into the slot
|
|
*slot = (char*)p;
|
|
|
|
// recur if the node is above the cut
|
|
if ( cuddI(dd,aFunc->index) < s_CutLevel )
|
|
{
|
|
CountNodeVisits_rec( dd, cuddE(aFunc), Visited );
|
|
CountNodeVisits_rec( dd, cuddT(aFunc), Visited );
|
|
}
|
|
} /* end of CountNodeVisits_rec */
|
|
|
|
|
|
/**Function********************************************************************
|
|
|
|
Synopsis [Revisits the nodes and computes the paths.]
|
|
|
|
Description [This function visits the nodes above the cut having the goal of
|
|
summing all the incomming BDD edges; when this function comes across the node
|
|
below the cut, it saves this node in the CutNode table.]
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
******************************************************************************/
|
|
void CollectNodesAndComputePaths_rec( DdManager * dd, DdNode * aFunc, DdNode * bCube, st__table * Visited, st__table * CutNodes )
|
|
{
|
|
// find the node in the visited table
|
|
DdNode * bTemp;
|
|
traventry * p;
|
|
char **slot;
|
|
if ( st__find_or_add(Visited, (char*)aFunc, &slot) )
|
|
{ // the node is found
|
|
// get the pointer to the traversal entry
|
|
p = (traventry*) *slot;
|
|
|
|
// make sure that the counter of incoming edges is positive
|
|
assert( p->nEdges > 0 );
|
|
|
|
// add the cube to the currently accumulated cubes
|
|
p->bSum = Cudd_bddOr( dd, bTemp = p->bSum, bCube ); Cudd_Ref( p->bSum );
|
|
Cudd_RecursiveDeref( dd, bTemp );
|
|
|
|
// decrement the number of visits
|
|
p->nEdges--;
|
|
|
|
// if more visits to this node are expected, return
|
|
if ( p->nEdges )
|
|
return;
|
|
else // if ( p->nEdges == 0 )
|
|
{ // this is the last visit - propagate the cube
|
|
|
|
// check where this node is
|
|
if ( cuddI(dd,aFunc->index) < s_CutLevel )
|
|
{ // the node is above the cut
|
|
DdNode * bCube0, * bCube1;
|
|
|
|
// get the top-most variable
|
|
DdNode * bVarTop = dd->vars[aFunc->index];
|
|
|
|
// compute the propagated cubes
|
|
bCube0 = Cudd_bddAnd( dd, p->bSum, Cudd_Not( bVarTop ) ); Cudd_Ref( bCube0 );
|
|
bCube1 = Cudd_bddAnd( dd, p->bSum, bVarTop ); Cudd_Ref( bCube1 );
|
|
|
|
// call recursively
|
|
CollectNodesAndComputePaths_rec( dd, cuddE(aFunc), bCube0, Visited, CutNodes );
|
|
CollectNodesAndComputePaths_rec( dd, cuddT(aFunc), bCube1, Visited, CutNodes );
|
|
|
|
// dereference the cubes
|
|
Cudd_RecursiveDeref( dd, bCube0 );
|
|
Cudd_RecursiveDeref( dd, bCube1 );
|
|
return;
|
|
}
|
|
else
|
|
{ // the node is below the cut
|
|
// add this node to the cut node table, if it is not yet there
|
|
|
|
// DdNode * bNode;
|
|
// bNode = Cudd_addBddPattern( dd, aFunc ); Cudd_Ref( bNode );
|
|
if ( st__find_or_add(CutNodes, (char*)aFunc, &slot) )
|
|
{ // the node exists - should never happen
|
|
assert( 0 );
|
|
}
|
|
*slot = (char*) p->bSum; Cudd_Ref( p->bSum );
|
|
// the table takes the reference of bNode
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// the node does not exist in the visited table - should never happen
|
|
assert(0);
|
|
|
|
} /* end of CollectNodesAndComputePaths_rec */
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
ABC_NAMESPACE_IMPL_END
|
|
|