Commit 98cf5698 by Alan Mishchenko

New fast extract.

parent 7a78e303
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
PackageName [Network and node package.] PackageName [Network and node package.]
Synopsis [Interface with the fast_extract package.] Synopsis [Implementation of traditional "fast_extract" algorithm.]
Author [Alan Mishchenko] Author [Alan Mishchenko]
...@@ -29,6 +29,59 @@ ABC_NAMESPACE_IMPL_START ...@@ -29,6 +29,59 @@ ABC_NAMESPACE_IMPL_START
/// DECLARATIONS /// /// DECLARATIONS ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/*
The code in this file implements the traditional "fast_extract" algorithm,
which extracts two-cube divisors concurrently with single-cube two-literal divisors,
as proposed in the TCAD'92 paper by J. Rajski and J. Vasudevamurthi.
Integration notes:
It is assumed that each object (primary input or internal node) in the original network
is associated with a unique integer number, called object identifier (ObjId, for short).
The user's input data given to 'fast_extract" is an array of cubes (pMan->vCubes).
Each cube is an array of integers, in which the first entry contains ObjId of the node,
to which this cube belongs in the original network. The following entries of a cube are
SOP literals of this cube. Each literal is represtned as 2*FaninId + ComplAttr, where FaninId
is ObjId of the fanin node and ComplAttr is 1 if literal is complemented, and 0 otherwise.
The user's output data produced by 'fast_extract' is also an array of cubes (pMan->vCubes).
If no divisors have been extracted, the output array is the same as the input array.
If some divisors have been extracted, the output array contains updated old cubes and new cubes
representing the extracted divisors. The new divisors have their ObjId starting from the
largest ObjId used in the cubes. To give the user more flexibility, which may be needed when some
ObjIds are already used for primary output nodes, which do not participate in fast_extract,
the parameter ObjIdMax is passed to procedure Fx_FastExtract(). The new divisors will receive
their ObjId starting from ObjIdMax onward, as divisor extaction proceeds.
The following two requirements are imposed on the input and output array of cubes:
(1) The array of cubes should be sorted by the first entry in each cube (that is, cubes belonging
to the same node should form a contiguous range).
(2) Literals in a cube should be sorted in the increasing order of the integer numbers.
To integrate this code into a calling application, such as ABC, the input cube array should
be generated (below this is done by the procedure Abc_NtkFxRetrieve) and the output cube array
should be incorporated into the current network (below this is done by the procedure Abc_NtkFxInsert).
In essence, the latter procedure performs the following:
- removes the current fanins and SOPs of each node in the network
- adds new nodes for each new divisor introduced by "fast_extract"
- populates fanins and SOPs of each node, both old and new, as indicaded by the resulting cube array.
Implementation notes:
The implementation is optimized for simplicity and speed of computation.
(1) Main input/output data-structure (pMan->vCubes) is the array of cubes which is dynamically updated by the algorithm.
(2) Auxiliary data-structure (pMan->vLits) is the array of arrays. The i-th array contains IDs of cubes which have literal i.
It may be convenient to think about the first (second) array as rows (columns) of a sparse matrix,
although the sparse matrix data-structure is not used in the proposed implementation.
(3) Hash table (pMan->pHash) hashes the normalized divisors (represented as integer arrays) into integer numbers.
(4) Array of divisor weights (pMan->vWeights), that is, the number of SOP literals to be saved by extacting each divisor.
(5) Priority queue (pMan->vPrio), which sorts divisor (integer numbers) by their weight
(6) Integer array (pMan->vVarCube), which maps each ObjId into the first cube of this object,
or -1, if there is no cubes as in the case of a primary input.
*/
typedef struct Fx_Man_t_ Fx_Man_t; typedef struct Fx_Man_t_ Fx_Man_t;
struct Fx_Man_t_ struct Fx_Man_t_
{ {
...@@ -36,22 +89,23 @@ struct Fx_Man_t_ ...@@ -36,22 +89,23 @@ struct Fx_Man_t_
Vec_Wec_t * vCubes; // cube -> lit Vec_Wec_t * vCubes; // cube -> lit
// internal data // internal data
Vec_Wec_t * vLits; // lit -> cube Vec_Wec_t * vLits; // lit -> cube
Vec_Int_t * vCounts; // literal counts (currently unused) Vec_Int_t * vCounts; // literal counts (currently not used)
Hsh_VecMan_t * pHash; // hash table of divisors Hsh_VecMan_t * pHash; // hash table for normalized divisors
Vec_Flt_t * vWeights; // divisor weights Vec_Flt_t * vWeights; // divisor weights
Vec_Que_t * vPrio; // priority queue Vec_Que_t * vPrio; // priority queue for divisors by weight
Vec_Int_t * vVarCube; // mapping var into its first cube Vec_Int_t * vVarCube; // mapping ObjId into its first cube
// temporary arrays used for updating data-structure after one extraction // temporary data to update the data-structure when a divisor is extracted
Vec_Int_t * vCubesS; // single cubes for the given divisor Vec_Int_t * vCubesS; // single cubes for the given divisor
Vec_Int_t * vCubesD; // cube pairs for the given divisor Vec_Int_t * vCubesD; // cube pairs for the given divisor
Vec_Int_t * vCompls; // complements of cube pairs Vec_Int_t * vCompls; // complemented attribute of each cube pair
Vec_Int_t * vCubeFree; // cube-free divisor Vec_Int_t * vCubeFree; // cube-free divisor
Vec_Int_t * vDiv; // divisor Vec_Int_t * vDiv; // selected divisor
// statistics // statistics
clock_t timeStart; // starting time clock_t timeStart; // starting time
int nVars; // original problem variables int nVars; // original problem variables
int nLits; // the number of SOP literals int nLits; // the number of SOP literals
int nDivs; // the number of extracted divisors int nDivs; // the number of extracted divisors
int nCompls; // the number of complements
int nPairsS; // number of lit pairs int nPairsS; // number of lit pairs
int nPairsD; // number of cube pairs int nPairsD; // number of cube pairs
int nDivsS; // single cube divisors int nDivsS; // single cube divisors
...@@ -63,8 +117,6 @@ static inline int Fx_ManGetFirstVarCube( Fx_Man_t * p, Vec_Int_t * vCube ) { ret ...@@ -63,8 +117,6 @@ static inline int Fx_ManGetFirstVarCube( Fx_Man_t * p, Vec_Int_t * vCube ) { ret
#define Fx_ManForEachCubeVec( vVec, vCubes, vCube, i ) \ #define Fx_ManForEachCubeVec( vVec, vCubes, vCube, i ) \
for ( i = 0; (i < Vec_IntSize(vVec)) && ((vCube) = Vec_WecEntry(vCubes, Vec_IntEntry(vVec, i))); i++ ) for ( i = 0; (i < Vec_IntSize(vVec)) && ((vCube) = Vec_WecEntry(vCubes, Vec_IntEntry(vVec, i))); i++ )
static int Fx_FastExtract( Vec_Wec_t * vCubes, int nVars, int fVerbose );
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS /// /// FUNCTION DEFINITIONS ///
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
...@@ -248,6 +300,7 @@ int Abc_NtkFxCheck( Abc_Ntk_t * pNtk ) ...@@ -248,6 +300,7 @@ int Abc_NtkFxCheck( Abc_Ntk_t * pNtk )
***********************************************************************/ ***********************************************************************/
int Abc_NtkFxPerform( Abc_Ntk_t * pNtk, int fVerbose ) int Abc_NtkFxPerform( Abc_Ntk_t * pNtk, int fVerbose )
{ {
extern int Fx_FastExtract( Vec_Wec_t * vCubes, int ObjIdMax, int fVerbose );
Vec_Wec_t * vCubes; Vec_Wec_t * vCubes;
assert( Abc_NtkIsSopLogic(pNtk) ); assert( Abc_NtkIsSopLogic(pNtk) );
// check unique fanins // check unique fanins
...@@ -372,8 +425,9 @@ static inline void Fx_PrintDiv( Fx_Man_t * p, int iDiv ) ...@@ -372,8 +425,9 @@ static inline void Fx_PrintDiv( Fx_Man_t * p, int iDiv )
printf( "%4d : ", p->nDivs ); printf( "%4d : ", p->nDivs );
printf( "Div %7d : ", iDiv ); printf( "Div %7d : ", iDiv );
printf( "Weight %5d ", (int)Vec_FltEntry(p->vWeights, iDiv) ); printf( "Weight %5d ", (int)Vec_FltEntry(p->vWeights, iDiv) );
// printf( "Compl %4d ", p->nCompls );
Fx_PrintDivOne( Hsh_VecReadEntry(p->pHash, iDiv) ); Fx_PrintDivOne( Hsh_VecReadEntry(p->pHash, iDiv) );
for ( i = Vec_IntSize(Hsh_VecReadEntry(p->pHash, iDiv)) + 3; i < 20; i++ ) for ( i = Vec_IntSize(Hsh_VecReadEntry(p->pHash, iDiv)) + 3; i < 16; i++ )
printf( " " ); printf( " " );
printf( "Lits =%7d ", p->nLits ); printf( "Lits =%7d ", p->nLits );
printf( "Divs =%8d ", Hsh_VecSize(p->pHash) ); printf( "Divs =%8d ", Hsh_VecSize(p->pHash) );
...@@ -873,7 +927,7 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv ) ...@@ -873,7 +927,7 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv )
Vec_Int_t * vCube, * vCube2, * vLitP, * vLitN; Vec_Int_t * vCube, * vCube2, * vLitP, * vLitN;
Vec_Int_t * vDiv = p->vDiv; Vec_Int_t * vDiv = p->vDiv;
int nLitsNew = p->nLits - (int)Vec_FltEntry(p->vWeights, iDiv); int nLitsNew = p->nLits - (int)Vec_FltEntry(p->vWeights, iDiv);
int i, k, Lit0, Lit1, iVarNew, fComplAny, RetValue; int i, k, Lit0, Lit1, iVarNew, RetValue;
// get the divisor and select pivot variables // get the divisor and select pivot variables
p->nDivs++; p->nDivs++;
...@@ -952,13 +1006,13 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv ) ...@@ -952,13 +1006,13 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv )
} }
// create updated double-cube divisor cube pairs // create updated double-cube divisor cube pairs
k = 0; k = 0;
fComplAny = 0; p->nCompls = 0;
assert( Vec_IntSize(p->vCubesD) % 2 == 0 ); assert( Vec_IntSize(p->vCubesD) % 2 == 0 );
assert( Vec_IntSize(p->vCubesD) == 2 * Vec_IntSize(p->vCompls) ); assert( Vec_IntSize(p->vCubesD) == 2 * Vec_IntSize(p->vCompls) );
for ( i = 0; i < Vec_IntSize(p->vCubesD); i += 2 ) for ( i = 0; i < Vec_IntSize(p->vCubesD); i += 2 )
{ {
int fCompl = Vec_IntEntry(p->vCompls, i/2); int fCompl = Vec_IntEntry(p->vCompls, i/2);
fComplAny |= fCompl; p->nCompls += fCompl;
vCube = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i) ); vCube = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i) );
vCube2 = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i+1) ); vCube2 = Vec_WecEntry( p->vCubes, Vec_IntEntry(p->vCubesD, i+1) );
RetValue = Fx_ManDivRemoveLits( vCube, vDiv, fCompl ); // cube 2*i RetValue = Fx_ManDivRemoveLits( vCube, vDiv, fCompl ); // cube 2*i
...@@ -1020,7 +1074,7 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv ) ...@@ -1020,7 +1074,7 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv )
Vec_IntForEachEntry( vDiv, Lit0, i ) Vec_IntForEachEntry( vDiv, Lit0, i )
{ {
Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_Lit2Var(Lit0)), p->vCubesD ); Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_Lit2Var(Lit0)), p->vCubesD );
if ( fComplAny && i > 1 ) // the last two lits are possibly complemented if ( p->nCompls && i > 1 ) // the last two lits are possibly complemented
Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_LitNot(Abc_Lit2Var(Lit0))), p->vCubesD ); Vec_IntTwoRemove( Vec_WecEntry(p->vLits, Abc_LitNot(Abc_Lit2Var(Lit0))), p->vCubesD );
} }
...@@ -1041,14 +1095,14 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv ) ...@@ -1041,14 +1095,14 @@ void Fx_ManUpdate( Fx_Man_t * p, int iDiv )
SeeAlso [] SeeAlso []
***********************************************************************/ ***********************************************************************/
int Fx_FastExtract( Vec_Wec_t * vCubes, int nVars, int fVerbose ) int Fx_FastExtract( Vec_Wec_t * vCubes, int ObjIdMax, int fVerbose )
{ {
int fVeryVerbose = 0; int fVeryVerbose = 0;
Fx_Man_t * p; Fx_Man_t * p;
clock_t clk = clock(); clock_t clk = clock();
// initialize the data-structure // initialize the data-structure
p = Fx_ManStart( vCubes ); p = Fx_ManStart( vCubes );
Fx_ManCreateLiterals( p, nVars ); Fx_ManCreateLiterals( p, ObjIdMax );
Fx_ManCreateDivisors( p ); Fx_ManCreateDivisors( p );
if ( fVeryVerbose ) if ( fVeryVerbose )
Fx_PrintMatrix( p ); Fx_PrintMatrix( p );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment