mirror of https://github.com/YosysHQ/abc.git
1113 lines
42 KiB
C
1113 lines
42 KiB
C
/**CFile****************************************************************
|
|
|
|
FileName [dau.c]
|
|
|
|
SystemName [ABC: Logic synthesis and verification system.]
|
|
|
|
PackageName [DAG-aware unmapping.]
|
|
|
|
Synopsis []
|
|
|
|
Author [Alan Mishchenko]
|
|
|
|
Affiliation [UC Berkeley]
|
|
|
|
Date [Ver. 1.0. Started - June 20, 2005.]
|
|
|
|
Revision [$Id: dau.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
|
|
|
***********************************************************************/
|
|
|
|
#include "dauInt.h"
|
|
#include "misc/util/utilTruth.h"
|
|
#include "misc/extra/extra.h"
|
|
#include "bool/lucky/lucky.h"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// DECLARATIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// FUNCTION DEFINITIONS ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Dau_TruthEnum(int nVars)
|
|
{
|
|
int fUseTable = 1;
|
|
abctime clk = Abc_Clock();
|
|
int nSizeLog = (1<<nVars) -2;
|
|
int nSizeW = 1 << nSizeLog;
|
|
int nPerms = Extra_Factorial( nVars );
|
|
int nMints = 1 << nVars;
|
|
int * pPerm = Extra_PermSchedule( nVars );
|
|
int * pComp = Extra_GreyCodeSchedule( nVars );
|
|
word nFuncs = ((word)1 << (((word)1 << nVars)-1));
|
|
word * pPres = ABC_CALLOC( word, 1 << ((1<<nVars)-7) );
|
|
unsigned * pTable = fUseTable ? (unsigned *)ABC_CALLOC(word, nSizeW) : NULL;
|
|
Vec_Int_t * vNpns = Vec_IntAlloc( 1000 );
|
|
word tMask = Abc_Tt6Mask( 1 << nVars );
|
|
word tTemp, tCur;
|
|
int i, k;
|
|
if ( pPres == NULL )
|
|
{
|
|
printf( "Cannot alloc memory for marks.\n" );
|
|
return;
|
|
}
|
|
if ( pTable == NULL )
|
|
printf( "Cannot alloc memory for table.\n" );
|
|
for ( tCur = 0; tCur < nFuncs; tCur++ )
|
|
{
|
|
if ( (tCur & 0x3FFFF) == 0 )
|
|
{
|
|
printf( "Finished %08x. Classes = %6d. ", (int)tCur, Vec_IntSize(vNpns) );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
|
fflush(stdout);
|
|
}
|
|
if ( Abc_TtGetBit(pPres, (int)tCur) )
|
|
continue;
|
|
//Extra_PrintBinary( stdout, (unsigned *)&tCur, 16 ); printf( " %04x\n", (int)tCur );
|
|
//Dau_DsdPrintFromTruth( &tCur, 4 ); printf( "\n" );
|
|
Vec_IntPush( vNpns, (int)tCur );
|
|
tTemp = tCur;
|
|
for ( i = 0; i < nPerms; i++ )
|
|
{
|
|
for ( k = 0; k < nMints; k++ )
|
|
{
|
|
if ( tCur < nFuncs )
|
|
{
|
|
if ( pTable ) pTable[(int)tCur] = tTemp;
|
|
Abc_TtSetBit( pPres, (int)tCur );
|
|
}
|
|
if ( (tMask & ~tCur) < nFuncs )
|
|
{
|
|
if ( pTable ) pTable[(int)(tMask & ~tCur)] = tTemp;
|
|
Abc_TtSetBit( pPres, (int)(tMask & ~tCur) );
|
|
}
|
|
tCur = Abc_Tt6Flip( tCur, pComp[k] );
|
|
}
|
|
tCur = Abc_Tt6SwapAdjacent( tCur, pPerm[i] );
|
|
}
|
|
assert( tTemp == tCur );
|
|
}
|
|
printf( "Computed %d NPN classes of %d variables. ", Vec_IntSize(vNpns), nVars );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
|
fflush(stdout);
|
|
Vec_IntFree( vNpns );
|
|
ABC_FREE( pPres );
|
|
ABC_FREE( pPerm );
|
|
ABC_FREE( pComp );
|
|
// write into file
|
|
if ( pTable )
|
|
{
|
|
FILE * pFile;
|
|
int RetValue;
|
|
char pFileName[200];
|
|
sprintf( pFileName, "tableW%d.data", nSizeLog );
|
|
pFile = fopen( pFileName, "wb" );
|
|
RetValue = fwrite( pTable, 8, nSizeW, pFile );
|
|
RetValue = 0;
|
|
fclose( pFile );
|
|
ABC_FREE( pTable );
|
|
}
|
|
}
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis []
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
unsigned * Dau_ReadFile( char * pFileName, int nSizeW )
|
|
{
|
|
abctime clk = Abc_Clock();
|
|
FILE * pFile = fopen( pFileName, "rb" );
|
|
unsigned * p = (unsigned *)ABC_CALLOC(word, nSizeW);
|
|
int RetValue = pFile ? fread( p, sizeof(word), nSizeW, pFile ) : 0;
|
|
RetValue = 0;
|
|
if ( pFile )
|
|
{
|
|
printf( "Finished reading file \"%s\".\n", pFileName );
|
|
fclose( pFile );
|
|
}
|
|
else
|
|
printf( "Cannot open input file \"%s\".\n", pFileName );
|
|
Abc_PrintTime( 1, "File reading", Abc_Clock() - clk );
|
|
return p;
|
|
}
|
|
int Dau_AddFunction( word tCur, int nVars, unsigned * pTable, Vec_Int_t * vNpns, Vec_Int_t * vNpns_ )
|
|
{
|
|
int Digit = (1 << nVars)-1;
|
|
word tMask = Abc_Tt6Mask( 1 << nVars );
|
|
word tNorm = (tCur >> Digit) & 1 ? ~tCur : tCur;
|
|
unsigned t = (unsigned)(tNorm & tMask);
|
|
unsigned tRep = pTable[t] & 0x7FFFFFFF;
|
|
unsigned tRep2 = pTable[tRep];
|
|
assert( ((tNorm >> Digit) & 1) == 0 );
|
|
if ( (tRep2 >> 31) == 0 ) // first time
|
|
{
|
|
Vec_IntPush( vNpns, tRep2 );
|
|
if ( Abc_TtSupportSize(&tCur, nVars) < nVars )
|
|
Vec_IntPush( vNpns_, tRep2 );
|
|
pTable[tRep] = tRep2 | (1 << 31);
|
|
return tRep2;
|
|
}
|
|
return 0;
|
|
}
|
|
void Dau_NetworkEnum(int nVars)
|
|
{
|
|
abctime clk = Abc_Clock();
|
|
int Limit = 2;
|
|
int UseTwo = 0;
|
|
int nSizeLog = (1<<nVars) -2;
|
|
int nSizeW = 1 << nSizeLog;
|
|
char pFileName[200];
|
|
unsigned * pTable;
|
|
Vec_Wec_t * vNpns = Vec_WecStart( 32 );
|
|
Vec_Wec_t * vNpns_ = Vec_WecStart( 32 );
|
|
int i, v, u, g, k, m, n, Res, Entry;
|
|
unsigned Inv = (unsigned)Abc_Tt6Mask(1 << (nVars-1));
|
|
sprintf( pFileName, "tableW%d.data", nSizeLog );
|
|
pTable = Dau_ReadFile( pFileName, nSizeW );
|
|
// create constant function and buffer/inverter function
|
|
pTable[0] |= (1 << 31);
|
|
pTable[Inv] |= (1 << 31);
|
|
Vec_IntPushTwo( Vec_WecEntry(vNpns, 0), 0, Inv );
|
|
Vec_IntPushTwo( Vec_WecEntry(vNpns_, 0), 0, Inv );
|
|
printf("Nodes = %2d. New = %6d. Total = %6d. New = %6d. Total = %6d. ",
|
|
0, Vec_IntSize(Vec_WecEntry(vNpns, 0)), Vec_WecSizeSize(vNpns),
|
|
Vec_IntSize(Vec_WecEntry(vNpns_, 0)), Vec_WecSizeSize(vNpns_) );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
|
// numerate other functions based on how many nodes they have
|
|
for ( n = 1; n < 32; n++ )
|
|
{
|
|
Vec_Int_t * vFuncsN2 = n > 1 ? Vec_WecEntry( vNpns, n-2 ) : NULL;
|
|
Vec_Int_t * vFuncsN1 = Vec_WecEntry( vNpns, n-1 );
|
|
Vec_Int_t * vFuncsN = Vec_WecEntry( vNpns, n );
|
|
Vec_Int_t * vFuncsN_ = Vec_WecEntry( vNpns_,n );
|
|
Vec_IntForEachEntry( vFuncsN1, Entry, i )
|
|
{
|
|
word uTruth = (((word)Entry) << 32) | (word)Entry;
|
|
int nSupp = Abc_TtSupportSize( &uTruth, nVars );
|
|
assert( nSupp == 6 || !Abc_Tt6HasVar(uTruth, nVars-1-nSupp) );
|
|
//printf( "Exploring function %4d with %d vars: ", i, nSupp );
|
|
//printf( " %04x\n", (int)uTruth );
|
|
//Dau_DsdPrintFromTruth( &uTruth, 4 );
|
|
for ( v = 0; v < nSupp; v++ )
|
|
{
|
|
word tGate, tCur;
|
|
word Cof0 = Abc_Tt6Cofactor0( uTruth, nVars-1-v );
|
|
word Cof1 = Abc_Tt6Cofactor1( uTruth, nVars-1-v );
|
|
for ( g = 0; g < Limit; g++ )
|
|
{
|
|
if ( nSupp < nVars )
|
|
{
|
|
if ( g == 0 )
|
|
{
|
|
tGate = s_Truths6[nVars-1-v] & s_Truths6[nVars-1-nSupp];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
else
|
|
{
|
|
tGate = s_Truths6[nVars-1-v] ^ s_Truths6[nVars-1-nSupp];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
}
|
|
}
|
|
for ( g = 0; g < Limit; g++ )
|
|
{
|
|
// add one cross bar
|
|
for ( k = 0; k < nSupp; k++ ) if ( k != v )
|
|
{
|
|
if ( g == 0 )
|
|
{
|
|
tGate = s_Truths6[nVars-1-v] & s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tGate = s_Truths6[nVars-1-v] & ~s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
else
|
|
{
|
|
tGate = s_Truths6[nVars-1-v] ^ s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
}
|
|
}
|
|
for ( g = 0; g < Limit; g++ )
|
|
{
|
|
// add two cross bars
|
|
for ( k = 0; k < nSupp; k++ ) if ( k != v )
|
|
for ( m = k+1; m < nSupp; m++ ) if ( m != v )
|
|
{
|
|
if ( g == 0 )
|
|
{
|
|
tGate = s_Truths6[nVars-1-m] & s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tGate = s_Truths6[nVars-1-m] & ~s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tGate = ~s_Truths6[nVars-1-m] & s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tGate = ~s_Truths6[nVars-1-m] & ~s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
else
|
|
{
|
|
tGate = s_Truths6[nVars-1-m] ^ s_Truths6[nVars-1-k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( UseTwo && vFuncsN2 )
|
|
Vec_IntForEachEntry( vFuncsN2, Entry, i )
|
|
{
|
|
word uTruth = (((word)Entry) << 32) | (word)Entry;
|
|
int nSupp = Abc_TtSupportSize( &uTruth, nVars );
|
|
assert( nSupp == 6 || !Abc_Tt6HasVar(uTruth, nVars-1-nSupp) );
|
|
//printf( "Exploring function %4d with %d vars: ", i, nSupp );
|
|
//printf( " %04x\n", (int)uTruth );
|
|
//Dau_DsdPrintFromTruth( &uTruth, 4 );
|
|
for ( v = 0; v < nSupp; v++ )
|
|
// for ( u = v+1; u < nSupp; u++ ) if ( u != v )
|
|
for ( u = 0; u < nSupp; u++ ) if ( u != v )
|
|
{
|
|
word tGate1, tGate2, tCur;
|
|
word Cof0 = Abc_Tt6Cofactor0( uTruth, nVars-1-v );
|
|
word Cof1 = Abc_Tt6Cofactor1( uTruth, nVars-1-v );
|
|
|
|
word Cof00 = Abc_Tt6Cofactor0( Cof0, nVars-1-u );
|
|
word Cof01 = Abc_Tt6Cofactor1( Cof0, nVars-1-u );
|
|
word Cof10 = Abc_Tt6Cofactor0( Cof1, nVars-1-u );
|
|
word Cof11 = Abc_Tt6Cofactor1( Cof1, nVars-1-u );
|
|
|
|
tGate1 = s_Truths6[nVars-1-v] & s_Truths6[nVars-1-u];
|
|
tGate2 = s_Truths6[nVars-1-v] ^ s_Truths6[nVars-1-u];
|
|
|
|
Cof0 = (tGate2 & Cof00) | (~tGate2 & Cof01);
|
|
Cof1 = (tGate2 & Cof10) | (~tGate2 & Cof11);
|
|
|
|
tCur = (tGate1 & Cof1) | (~tGate1 & Cof0);
|
|
Res = Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
if ( Res )
|
|
printf( "Found function %d\n", Res );
|
|
|
|
tCur = (tGate1 & Cof0) | (~tGate1 & Cof1);
|
|
Res = Dau_AddFunction( tCur, nVars, pTable, vFuncsN, vFuncsN_ );
|
|
if ( Res )
|
|
printf( "Found function %d\n", Res );
|
|
}
|
|
}
|
|
printf("Nodes = %2d. New = %6d. Total = %6d. New = %6d. Total = %6d. ",
|
|
n, Vec_IntSize(vFuncsN), Vec_WecSizeSize(vNpns), Vec_IntSize(vFuncsN_), Vec_WecSizeSize(vNpns_) );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
|
fflush(stdout);
|
|
if ( Vec_IntSize(vFuncsN) == 0 )
|
|
break;
|
|
}
|
|
// printf( "Functions with 7 nodes:\n" );
|
|
// Vec_IntForEachEntry( Vec_WecEntry(vNpns_,7), Entry, i )
|
|
// printf( "%04x ", Entry );
|
|
// printf( "\n" );
|
|
|
|
Vec_WecFree( vNpns );
|
|
Vec_WecFree( vNpns_ );
|
|
ABC_FREE( pTable );
|
|
Abc_PrintTime( 1, "Total time", Abc_Clock() - clk );
|
|
fflush(stdout);
|
|
}
|
|
void Dau_NetworkEnumTest()
|
|
{
|
|
//Dau_TruthEnum(3);
|
|
Dau_NetworkEnum(4);
|
|
}
|
|
|
|
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Count the number of symmetric pairs.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Dau_CountSymms( word t, int nVars )
|
|
{
|
|
word Cof0, Cof1;
|
|
int i, j, nPairs = 0;
|
|
for ( i = 0; i < nVars; i++ )
|
|
for ( j = i+1; j < nVars; j++ )
|
|
nPairs += Abc_TtVarsAreSymmetric(&t, nVars, i, j, &Cof0, &Cof1);
|
|
return nPairs;
|
|
}
|
|
int Dau_CountSymms2( word t, int nVars )
|
|
{
|
|
word Cof0, Cof1;
|
|
int i, j, SymVars = 0;
|
|
for ( i = 0; i < nVars; i++ )
|
|
for ( j = i+1; j < nVars; j++ )
|
|
if ( Abc_TtVarsAreSymmetric(&t, nVars, i, j, &Cof0, &Cof1) )
|
|
SymVars |= (1 << j);
|
|
return SymVars;
|
|
}
|
|
int Dau_CountCompl1( word t, int v, int nVars )
|
|
{
|
|
word tNew = Abc_Tt6Flip(t, v);
|
|
int k;
|
|
if ( tNew == ~t )
|
|
return 1;
|
|
for ( k = 0; k < nVars; k++ ) if ( k != v )
|
|
if ( tNew == Abc_Tt6Flip(t, k) )
|
|
return 1;
|
|
return 0;
|
|
}
|
|
int Dau_CountCompl( word t, int nVars )
|
|
{
|
|
int i, nPairs = 0;
|
|
for ( i = 0; i < nVars; i++ )
|
|
nPairs += Dau_CountCompl1(t, i, nVars);
|
|
return nPairs;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Performs exact canonicization of semi-canonical classes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Wrd_t * Dau_ExactNpnForClasses( Vec_Mem_t * vTtMem, Vec_Int_t * vNodSup, int nVars, int nInputs )
|
|
{
|
|
Vec_Wrd_t * vCanons = Vec_WrdStart( Vec_IntSize(vNodSup) );
|
|
word pAuxWord[1024], pAuxWord1[1024];
|
|
word uTruth; int i, Entry;
|
|
permInfo * pi = setPermInfoPtr(nVars);
|
|
Vec_IntForEachEntry( vNodSup, Entry, i )
|
|
{
|
|
if ( (Entry & 0xF) > nVars )
|
|
continue;
|
|
uTruth = *Vec_MemReadEntry( vTtMem, i );
|
|
simpleMinimal(&uTruth, pAuxWord, pAuxWord1, pi, nVars);
|
|
Vec_WrdWriteEntry( vCanons, i, uTruth );
|
|
}
|
|
freePermInfoPtr(pi);
|
|
return vCanons;
|
|
}
|
|
void Dau_ExactNpnPrint( Vec_Mem_t * vTtMem, Vec_Int_t * vNodSup, int nVars, int nInputs, int nNodesMax )
|
|
{
|
|
abctime clk = Abc_Clock(); int n, nTotal = 0;
|
|
Vec_Wrd_t * vCanons = Dau_ExactNpnForClasses( vTtMem, vNodSup, nVars, nInputs );
|
|
Vec_Mem_t * vTtMem2 = Vec_MemAlloc( Vec_MemEntrySize(vTtMem), 10 );
|
|
Vec_MemHashAlloc( vTtMem2, 1<<10 );
|
|
Abc_PrintTime( 1, "Exact NPN computation time", Abc_Clock() - clk );
|
|
printf( "Final results:\n" );
|
|
for ( n = 0; n <= nNodesMax; n++ )
|
|
{
|
|
int i, Entry, Entry2, nEntries2, Counter = 0, Counter2 = 0;
|
|
Vec_IntForEachEntry( vNodSup, Entry, i )
|
|
{
|
|
if ( (Entry & 0xF) > nVars || (Entry >> 16) != n )
|
|
continue;
|
|
Counter++;
|
|
nEntries2 = Vec_MemEntryNum(vTtMem2);
|
|
Entry2 = Vec_MemHashInsert( vTtMem2, Vec_WrdEntryP(vCanons, i) );
|
|
if ( nEntries2 == Vec_MemEntryNum(vTtMem2) ) // found in the table - not new
|
|
continue;
|
|
Counter2++;
|
|
}
|
|
nTotal += Counter2;
|
|
printf( "Nodes = %2d. ", n );
|
|
printf( "Semi-canonical = %8d. ", Counter );
|
|
printf( "Canonical = %8d. ", Counter2 );
|
|
printf( "Total = %8d.", nTotal );
|
|
printf( "\n" );
|
|
}
|
|
Vec_MemHashFree( vTtMem2 );
|
|
Vec_MemFreeP( &vTtMem2 );
|
|
Vec_WrdFree( vCanons );
|
|
fflush(stdout);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Saving hash tables.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Dau_TablesSave( int nInputs, int nVars, Vec_Mem_t * vTtMem, Vec_Int_t * vNodSup, int nFronts, abctime clk )
|
|
{
|
|
FILE * pFile;
|
|
char FileName[100];
|
|
int i, nWords = Abc_TtWordNum(nInputs);
|
|
// NPN classes
|
|
sprintf( FileName, "npn%d%d.ttd", nInputs, nVars );
|
|
pFile = fopen( FileName, "wb" );
|
|
for ( i = 0; i < Vec_MemEntryNum(vTtMem); i++ )
|
|
fwrite( Vec_MemReadEntry(vTtMem, i), 8, nWords, pFile );
|
|
fwrite( Vec_IntArray(vNodSup), 4, Vec_IntSize(vNodSup), pFile );
|
|
fclose( pFile );
|
|
// printf( "Dumped files with %10d classes after exploring %10d frontiers.\n",
|
|
// Vec_IntSize(vNodSup), nFronts );
|
|
printf( "Dumped file \"%s\" with %10d classes after exploring %10d frontiers. ",
|
|
FileName, Vec_IntSize(vNodSup), nFronts );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
|
fflush(stdout);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Dump functions by the number of nodes.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Dau_DumpFuncs( Vec_Mem_t * vTtMem, Vec_Int_t * vNodSup, int nVars, int nMax )
|
|
{
|
|
FILE * pFile[20];
|
|
int Counters[20] = {0};
|
|
int n, i;
|
|
assert( nVars == 4 || nVars == 5 );
|
|
for ( n = 0; n <= nMax; n++ )
|
|
{
|
|
char FileName[100];
|
|
sprintf( FileName, "func%d_min%d.tt", nVars, n );
|
|
pFile[n] = fopen( FileName, "wb" );
|
|
}
|
|
for ( i = 0; i < Vec_MemEntryNum(vTtMem); i++ )
|
|
{
|
|
word * pTruth = Vec_MemReadEntry( vTtMem, i );
|
|
int NodSup = Vec_IntEntry( vNodSup, i );
|
|
if ( (NodSup & 0xF) != nVars )
|
|
continue;
|
|
Counters[NodSup >> 16]++;
|
|
if ( nVars == 4 )
|
|
fprintf( pFile[NodSup >> 16], "%04x\n", (int)(0xFFFF & pTruth[0]) );
|
|
else if ( nVars == 5 )
|
|
fprintf( pFile[NodSup >> 16], "%08x\n", (int)(0xFFFFFFFF & pTruth[0]) );
|
|
}
|
|
for ( n = 0; n <= nMax; n++ )
|
|
{
|
|
printf( "Dumped %8d %d-node %d-input functions into file.\n", Counters[n], n, nVars );
|
|
fclose( pFile[n] );
|
|
}
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Function enumeration.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
int Dau_CountFuncs( Vec_Int_t * vNodSup, int iStart, int iStop, int nVars )
|
|
{
|
|
int i, Entry, Count = 0;
|
|
Vec_IntForEachEntryStartStop( vNodSup, Entry, i, iStart, iStop )
|
|
Count += ((Entry & 0xF) <= nVars);
|
|
return Count;
|
|
}
|
|
int Dau_PrintStats( int nNodes, int nInputs, int nVars, Vec_Int_t * vNodSup, int iStart, int iStop, word nSteps, int Count2, abctime clk )
|
|
{
|
|
int nNew;
|
|
printf("N =%2d | ", nNodes );
|
|
printf("C =%12.0f ", (double)(iword)nSteps );
|
|
printf("New%d =%10d ", nInputs, iStop-iStart );
|
|
printf("All%d =%10d | ", nInputs, iStop );
|
|
printf("New%d =%8d ", nVars, nNew = Dau_CountFuncs(vNodSup, iStart, iStop, nVars) );
|
|
printf("All%d =%8d ", nVars, Dau_CountFuncs(vNodSup, 0, iStop, nVars) );
|
|
printf("Two =%6d ", Count2 );
|
|
//Abc_PrintTime( 1, "T", Abc_Clock() - clk );
|
|
Abc_Print(1, "%9.2f sec\n", 1.0*(Abc_Clock() - clk)/(CLOCKS_PER_SEC));
|
|
fflush(stdout);
|
|
return nNew;
|
|
}
|
|
|
|
|
|
int Dau_InsertFunction( Abc_TtHieMan_t * pMan, word * pCur, int nNodes, int nInputs, int nVars0, int nVars,
|
|
Vec_Mem_t * vTtMem, Vec_Int_t * vNodSup, int nFronts, abctime clk )
|
|
{
|
|
int DumpDelta = 1000000;
|
|
char Perm[16] = {0};
|
|
int nVarsNew = Abc_TtMinBase( pCur, NULL, nVars, nInputs );
|
|
//unsigned Phase = Abc_TtCanonicizeHie( pMan, pCur, nVarsNew, Perm, 1 );
|
|
unsigned Phase = Abc_TtCanonicizeWrap( Abc_TtCanonicizeAda, pMan, pCur, nVarsNew, Perm, 99 );
|
|
int nEntries = Vec_MemEntryNum(vTtMem);
|
|
int Entry = Vec_MemHashInsert( vTtMem, pCur );
|
|
if ( nEntries == Vec_MemEntryNum(vTtMem) ) // found in the table - not new
|
|
return 0;
|
|
Entry = 0;
|
|
Phase = 0;
|
|
// this is a new class
|
|
Vec_IntPush( vNodSup, (nNodes << 16) | nVarsNew );
|
|
assert( Vec_MemEntryNum(vTtMem) == Vec_IntSize(vNodSup) );
|
|
if ( Vec_IntSize(vNodSup) % DumpDelta == 0 )
|
|
Dau_TablesSave( nInputs, nVars0, vTtMem, vNodSup, nFronts, clk );
|
|
return 1;
|
|
}
|
|
void Dau_FunctionEnum( int nInputs, int nVars, int nNodeMax, int fUseTwo, int fReduce, int fVerbose )
|
|
{
|
|
abctime clk = Abc_Clock();
|
|
int nWords = Abc_TtWordNum(nInputs); word nSteps = 0;
|
|
Abc_TtHieMan_t * pMan = Abc_TtHieManStart( nInputs, 5 );
|
|
Vec_Mem_t * vTtMem = Vec_MemAlloc( nWords, 16 );
|
|
Vec_Int_t * vNodSup = Vec_IntAlloc( 1 << 16 );
|
|
int v, u, k, m, n, Entry, nNew, Limit[32] = {1, 2};
|
|
word Truth[4] = {0};
|
|
assert( nVars >= 3 && nVars <= nInputs && nInputs <= 6 );
|
|
Vec_MemHashAlloc( vTtMem, 1<<16 );
|
|
// add constant 0
|
|
Vec_MemHashInsert( vTtMem, Truth );
|
|
Vec_IntPush( vNodSup, 0 ); // nodes=0, supp=0
|
|
// add buffer/inverter
|
|
Abc_TtIthVar( Truth, 0, nInputs );
|
|
Abc_TtNot( Truth, nWords );
|
|
Vec_MemHashInsert( vTtMem, Truth );
|
|
Vec_IntPush( vNodSup, 1 ); // nodes=0, supp=1
|
|
Dau_PrintStats( 0, nInputs, nVars, vNodSup, 0, 2, nSteps, 0, clk );
|
|
// numerate other functions based on how many nodes they have
|
|
for ( n = 1; n <= nNodeMax; n++ )
|
|
{
|
|
int Count2 = 0;
|
|
int fExpand = !(fReduce && n == nNodeMax);
|
|
for ( Entry = Limit[n-1]; Entry < Limit[n]; Entry++ )
|
|
{
|
|
word * pTruth = Vec_MemReadEntry( vTtMem, Entry );
|
|
int NodSup = Vec_IntEntry(vNodSup, Entry);
|
|
int nSupp = 0xF & NodSup;
|
|
int SymVars = Dau_CountSymms2( pTruth[0], nSupp );
|
|
assert( n-1 == (NodSup >> 16) );
|
|
assert( !Abc_Tt6HasVar(*pTruth, nSupp) );
|
|
//printf( "Exploring function %4d with %d vars: ", i, nSupp );
|
|
//printf( " %04x\n", (int)uTruth );
|
|
//Dau_DsdPrintFromTruth( &uTruth, 4 );
|
|
for ( v = 0; v < nSupp; v++ ) if ( (SymVars & (1 << v)) == 0 )
|
|
{
|
|
word tGate, tCur;
|
|
word Cof0 = Abc_Tt6Cofactor0( *pTruth, v );
|
|
word Cof1 = Abc_Tt6Cofactor1( *pTruth, v );
|
|
// add one extra variable to support
|
|
if ( nSupp < nInputs && fExpand )
|
|
{
|
|
tGate = s_Truths6[v] & s_Truths6[nSupp];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp+1, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp+1, vTtMem, vNodSup, Entry, clk );
|
|
|
|
|
|
tGate = s_Truths6[v] ^ s_Truths6[nSupp];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp+1, vTtMem, vNodSup, Entry, clk );
|
|
|
|
nSteps += 3;
|
|
}
|
|
// add one cross bar
|
|
if ( fExpand )
|
|
for ( k = 0; k < nSupp; k++ ) if ( k != v && ((SymVars & (1 << k)) == 0 || k == v+1) )
|
|
{
|
|
tGate = s_Truths6[v] & s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tGate = s_Truths6[v] & ~s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
|
|
tGate = s_Truths6[v] ^ s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
nSteps += 5;
|
|
}
|
|
// add two cross bars
|
|
for ( k = 0; k < nSupp; k++ ) if ( k != v )//&& ((SymVars & (1 << k)) == 0) )
|
|
for ( m = k+1; m < nSupp; m++ ) if ( m != v )//&& ((SymVars & (1 << m)) == 0 || m == k+1) )
|
|
{
|
|
tGate = s_Truths6[m] & s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tGate = s_Truths6[m] & ~s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tGate = ~s_Truths6[m] & s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tGate = ~s_Truths6[m] & ~s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
|
|
tGate = s_Truths6[m] ^ s_Truths6[k];
|
|
tCur = (tGate & Cof1) | (~tGate & Cof0);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
tGate = s_Truths6[m] ^ s_Truths6[k];
|
|
tCur = (tGate & Cof0) | (~tGate & Cof1);
|
|
Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
|
|
nSteps += 10;
|
|
}
|
|
}
|
|
}
|
|
if ( fUseTwo && n > 2 && fExpand )
|
|
for ( Entry = Limit[n-2]; Entry < Limit[n-1]; Entry++ )
|
|
{
|
|
word * pTruth = Vec_MemReadEntry( vTtMem, Entry );
|
|
int NodSup = Vec_IntEntry(vNodSup, Entry);
|
|
int nSupp = 0xF & NodSup; int g1, g2;
|
|
assert( n-2 == (NodSup >> 16) );
|
|
assert( !Abc_Tt6HasVar(*pTruth, nSupp) );
|
|
for ( v = 0; v < nSupp; v++ )
|
|
for ( u = 0; u < nSupp; u++ ) if ( u != v )
|
|
{
|
|
word Cof0 = Abc_Tt6Cofactor0( *pTruth, v );
|
|
word Cof1 = Abc_Tt6Cofactor1( *pTruth, v );
|
|
|
|
word Cof00 = Abc_Tt6Cofactor0( Cof0, u );
|
|
word Cof01 = Abc_Tt6Cofactor1( Cof0, u );
|
|
word Cof10 = Abc_Tt6Cofactor0( Cof1, u );
|
|
word Cof11 = Abc_Tt6Cofactor1( Cof1, u );
|
|
|
|
word tGates[5], tCur;
|
|
tGates[0] = s_Truths6[v] & s_Truths6[u];
|
|
tGates[1] = s_Truths6[v] & ~s_Truths6[u];
|
|
tGates[2] = ~s_Truths6[v] & s_Truths6[u];
|
|
tGates[3] = s_Truths6[v] | s_Truths6[u];
|
|
tGates[4] = s_Truths6[v] ^ s_Truths6[u];
|
|
|
|
for ( g1 = 0; g1 < 5; g1++ )
|
|
for ( g2 = g1+1; g2 < 5; g2++ )
|
|
{
|
|
Cof0 = (tGates[g1] & Cof01) | (~tGates[g1] & Cof00);
|
|
Cof1 = (tGates[g1] & Cof11) | (~tGates[g1] & Cof10);
|
|
|
|
tCur = (tGates[g2] & Cof1) | (~tGates[g2] & Cof0);
|
|
Count2 += Dau_InsertFunction( pMan, &tCur, n, nInputs, nVars, nSupp, vTtMem, vNodSup, Entry, clk );
|
|
}
|
|
}
|
|
}
|
|
Limit[n+1] = Vec_IntSize(vNodSup);
|
|
nNew = Dau_PrintStats( n, nInputs, nVars, vNodSup, Limit[n], Limit[n+1], nSteps, Count2, clk );
|
|
if ( nNew == 0 )
|
|
break;
|
|
}
|
|
Dau_TablesSave( nInputs, nVars, vTtMem, vNodSup, Vec_IntSize(vNodSup), clk );
|
|
Abc_PrintTime( 1, "Total time", Abc_Clock() - clk );
|
|
//Dau_DumpFuncs( vTtMem, vNodSup, nVars, nNodeMax );
|
|
//Dau_ExactNpnPrint( vTtMem, vNodSup, nVars, nInputs, n );
|
|
Abc_TtHieManStop( pMan );
|
|
Vec_MemHashFree( vTtMem );
|
|
Vec_MemFreeP( &vTtMem );
|
|
Vec_IntFree( vNodSup );
|
|
fflush(stdout);
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Function enumeration.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Mem_t * Dau_CollectNpnFunctions( word * p, int nVars, int fVerbose )
|
|
{
|
|
abctime clkStart = Abc_Clock();
|
|
Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars );
|
|
int nWords = Abc_Truth6WordNum(nVars);
|
|
word * pCopy = ABC_ALLOC( word, nWords );
|
|
Abc_TtCopy( pCopy, p, nWords, p[0] & 1 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
int nPerms = Extra_Factorial( nVars );
|
|
int nMints = 1 << nVars;
|
|
int * pPerm = Extra_PermSchedule( nVars );
|
|
int * pComp = Extra_GreyCodeSchedule( nVars );
|
|
int m, i, k, nFuncs;
|
|
for ( m = 0; m < nMints; m++ ) {
|
|
Abc_TtFlip( pCopy, nWords, pComp[m] );
|
|
if ( pCopy[0] & 1 ) {
|
|
Abc_TtNot( pCopy, nWords );
|
|
assert( (pCopy[0] & 1) == 0 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
Abc_TtNot( pCopy, nWords );
|
|
}
|
|
else
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
}
|
|
assert( Abc_TtEqual(pCopy, Vec_MemReadEntry(vTtMem, 0), nWords) );
|
|
nFuncs = Vec_MemEntryNum(vTtMem);
|
|
if ( fVerbose )
|
|
printf( "Collected %d NN functions and ", nFuncs ), fflush(stdout);
|
|
for ( i = 0; i < nFuncs; i++ ) {
|
|
Abc_TtCopy( pCopy, Vec_MemReadEntry(vTtMem, i), nWords, 0 );
|
|
for ( k = 0; k < nPerms; k++ ) {
|
|
Abc_TtSwapAdjacent( pCopy, nWords, pPerm[k] );
|
|
assert( (pCopy[0] & 1) == 0 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
}
|
|
assert( Abc_TtEqual(pCopy, Vec_MemReadEntry(vTtMem, i), nWords) );
|
|
}
|
|
ABC_FREE( pPerm );
|
|
ABC_FREE( pComp );
|
|
ABC_FREE( pCopy );
|
|
nFuncs = Vec_MemEntryNum(vTtMem);
|
|
if ( fVerbose )
|
|
printf( "%d NPN functions. ", nFuncs ),
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart ),
|
|
fflush(stdout);
|
|
return vTtMem;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Function enumeration.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Mem_t * Dau_CollectBoothFunctions( int nLog2Radix )
|
|
{
|
|
assert( nLog2Radix >=2 && nLog2Radix <= 10 );
|
|
int nVars = nLog2Radix + 1;
|
|
int nWords = Abc_Truth6WordNum( nVars );
|
|
int nFuncs = 1 << (nLog2Radix - 1);
|
|
int nMints = 1 << nVars;
|
|
Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars );
|
|
word * pFuncs = ABC_CALLOC( word, nWords * nFuncs );
|
|
int m, k, i;
|
|
for ( m = 0; m < nMints; m++ )
|
|
{
|
|
int d = (m & 1);
|
|
for ( k = 1; k < nLog2Radix; k++ )
|
|
if ( m & (1 << k) )
|
|
d += 1 << (k-1);
|
|
if ( m & (1 << nLog2Radix) )
|
|
d -= 1 << (nLog2Radix-1);
|
|
if ( d == 0 )
|
|
continue;
|
|
if ( d < 0 )
|
|
d = -d;
|
|
assert( d >= 1 && d <= nFuncs );
|
|
Abc_TtSetBit( pFuncs + (d-1)*nWords, m );
|
|
}
|
|
for ( i = 0; i < nFuncs; i++ ) {
|
|
if ( nVars < 6 )
|
|
pFuncs[i] = Abc_Tt6Stretch( pFuncs[i], nVars );
|
|
Vec_MemHashInsert( vTtMem, pFuncs + i*nWords );
|
|
}
|
|
ABC_FREE( pFuncs );
|
|
//Vec_MemDump( stdout, vTtMem );
|
|
return vTtMem;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Function enumeration.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Dau_PrintNpnFunction( Vec_Mem_t * vTtMem, int nFuncs, word * pCopy, int nVars, int uPhase, int * pPerm, int fVerbose )
|
|
{
|
|
int nWords = Abc_Truth6WordNum(nVars);
|
|
if ( fVerbose ) {
|
|
printf( "%6d : ", nFuncs );
|
|
Abc_TtPrintBits2((word *)&uPhase, nVars);
|
|
printf( " " );
|
|
for ( int v = nVars-1; v >= 0; v-- )
|
|
printf( " %d", pPerm[v] );
|
|
printf( " F = " );
|
|
Abc_TtPrintHexRev( stdout, pCopy, nVars );
|
|
}
|
|
int Pos = Vec_MemHashInsert( vTtMem, pCopy );
|
|
Abc_TtNot( pCopy, nWords );
|
|
if ( fVerbose ) {
|
|
printf( " (%05d)", Pos );
|
|
printf( " ~F = " );
|
|
Abc_TtPrintHexRev( stdout, pCopy, nVars );
|
|
}
|
|
int Neg = Vec_MemHashInsert( vTtMem, pCopy );
|
|
Abc_TtNot( pCopy, nWords );
|
|
if ( fVerbose ) {
|
|
printf( " (%05d)", Neg );
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
void Dau_PrintNpnFunctions( word * p, int nVars, int fVerbose )
|
|
{
|
|
int nWords = Abc_Truth6WordNum(nVars);
|
|
Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars );
|
|
word * pCopy = ABC_ALLOC( word, nWords );
|
|
word * pBest = ABC_ALLOC( word, nWords );
|
|
Abc_TtCopy( pCopy, p, nWords, 0 );
|
|
Abc_TtCopy( pBest, p, nWords, 0 );
|
|
int nPerms = Extra_Factorial( nVars );
|
|
int nMints = 1 << nVars;
|
|
int * pPerm = Extra_PermSchedule( nVars );
|
|
int * pComp = Extra_GreyCodeSchedule( nVars );
|
|
int m, i, k, nFuncs = 0;
|
|
int uVarPhase = 0;
|
|
int pVarPerm[32];
|
|
printf( "The number of NPN configurations is %d = %d complementations * %d permutations * 2 output polarities.\n", nMints*nPerms*2, nMints, nPerms );
|
|
for ( i = 0; i < nVars; i++ )
|
|
pVarPerm[i] = i;
|
|
for ( m = 0; m < nMints; m++ ) {
|
|
for ( k = 0; k < nPerms; k++ ) {
|
|
if ( Abc_TtCompare(pBest, pCopy, nWords) == 1 )
|
|
Abc_TtCopy( pBest, pCopy, nWords, 0 );
|
|
Dau_PrintNpnFunction( vTtMem, nFuncs++, pCopy, nVars, uVarPhase, pVarPerm, fVerbose );
|
|
Abc_TtSwapAdjacent( pCopy, nWords, pPerm[k] );
|
|
ABC_SWAP( int, pVarPerm[pPerm[k]], pVarPerm[pPerm[k]+1] );
|
|
}
|
|
if ( fVerbose ) printf( "\n" );
|
|
Abc_TtFlip( pCopy, nWords, pComp[m] );
|
|
uVarPhase ^= 1 << pComp[m];
|
|
}
|
|
assert( Abc_TtEqual(pCopy, p, nWords) );
|
|
printf( "The number of unique functions %d (out of %d). Frequency = %d. Representative: ", Vec_MemEntryNum(vTtMem), nMints*nPerms*2, nMints*nPerms*2/Vec_MemEntryNum(vTtMem) );
|
|
Abc_TtPrintHexRev( stdout, pBest, nVars );
|
|
printf( "\n" );
|
|
ABC_FREE( pPerm );
|
|
ABC_FREE( pComp );
|
|
ABC_FREE( pCopy );
|
|
ABC_FREE( pBest );
|
|
Vec_MemHashFree( vTtMem );
|
|
Vec_MemFree( vTtMem );
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Compute NPN class members.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
Vec_Mem_t * Dau_CollectNpnFunctionsArray( Vec_Wrd_t * vFuncs, int nVars, Vec_Int_t ** pvMap, int fVerbose )
|
|
{
|
|
assert( nVars <= 10 );
|
|
abctime clkStart = Abc_Clock();
|
|
Vec_Int_t * vMap = Vec_IntAlloc( 100 );
|
|
Vec_Int_t * vCnts = Vec_IntAlloc( Vec_WrdSize(vFuncs) );
|
|
Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars );
|
|
int nWords = Abc_Truth6WordNum(nVars);
|
|
int nPerms = Extra_Factorial( nVars );
|
|
int nMints = 1 << nVars;
|
|
int * pPerm = Extra_PermSchedule( nVars );
|
|
int * pComp = Extra_GreyCodeSchedule( nVars );
|
|
int m, i, k, t, Entry;
|
|
word * pCopy = ABC_ALLOC( word, nWords );
|
|
int nClasses = Vec_WrdSize(vFuncs) / nWords;
|
|
assert( nClasses * nWords == Vec_WrdSize(vFuncs) );
|
|
for ( t = 0; t < nClasses; t++ )
|
|
{
|
|
word * pTruth = Vec_WrdEntryP( vFuncs, nWords * t );
|
|
int nFuncs = Vec_MemEntryNum(vTtMem);
|
|
Abc_TtCopy( pCopy, pTruth, nWords, pTruth[0] & 1 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
for ( m = 0; m < nMints; m++ ) {
|
|
Abc_TtFlip( pCopy, nWords, pComp[m] );
|
|
if ( pCopy[0] & 1 ) {
|
|
Abc_TtNot( pCopy, nWords );
|
|
assert( (pCopy[0] & 1) == 0 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
Abc_TtNot( pCopy, nWords );
|
|
}
|
|
else
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
}
|
|
if ( pTruth[0] & 1 )
|
|
assert( Abc_TtOpposite(pCopy, pTruth, nWords) );
|
|
else
|
|
assert( Abc_TtEqual(pCopy, pTruth, nWords) );
|
|
int nFuncs2 = Vec_MemEntryNum(vTtMem);
|
|
for ( i = nFuncs; i < nFuncs2; i++ ) {
|
|
Abc_TtCopy( pCopy, Vec_MemReadEntry(vTtMem, i), nWords, 0 );
|
|
for ( k = 0; k < nPerms; k++ ) {
|
|
Abc_TtSwapAdjacent( pCopy, nWords, pPerm[k] );
|
|
assert( (pCopy[0] & 1) == 0 );
|
|
Vec_MemHashInsert( vTtMem, pCopy );
|
|
}
|
|
assert( Abc_TtEqual(pCopy, Vec_MemReadEntry(vTtMem, i), nWords) );
|
|
}
|
|
for ( i = nFuncs; i < Vec_MemEntryNum(vTtMem); i++ )
|
|
Vec_IntPush( vMap, t );
|
|
Vec_IntPush( vCnts, Vec_MemEntryNum(vTtMem) - nFuncs );
|
|
}
|
|
ABC_FREE( pCopy );
|
|
ABC_FREE( pPerm );
|
|
ABC_FREE( pComp );
|
|
if ( fVerbose ) {
|
|
int Lim = Abc_MinInt( Vec_IntSize(vCnts), 7 );
|
|
printf( "Collected %d", Vec_MemEntryNum(vTtMem) );
|
|
Vec_IntForEachEntryStop( vCnts, Entry, i, Lim )
|
|
printf( " %c %d", i ? '+' : '=', Entry );
|
|
if ( Vec_IntSize(vCnts) > Lim )
|
|
printf( " + ..." );
|
|
printf( " NPN class members. " );
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart );
|
|
fflush(stdout);
|
|
}
|
|
Vec_IntFree( vCnts );
|
|
if ( pvMap )
|
|
*pvMap = vMap;
|
|
else
|
|
Vec_IntFree( vMap );
|
|
return vTtMem;
|
|
}
|
|
|
|
/**Function*************************************************************
|
|
|
|
Synopsis [Canonicize a set of functions.]
|
|
|
|
Description []
|
|
|
|
SideEffects []
|
|
|
|
SeeAlso []
|
|
|
|
***********************************************************************/
|
|
void Dau_CanonicizeArray( Vec_Wrd_t * vFuncs, int nVars, int fVerbose )
|
|
{
|
|
abctime clkStart = Abc_Clock();
|
|
if ( fVerbose ) printf( "Functions: %d (original) ", Vec_WrdSize(vFuncs) );
|
|
unsigned uCanonPhase; char pCanonPerm[16]; word Func; int i;
|
|
Vec_WrdUniqify( vFuncs );
|
|
|
|
if ( fVerbose ) printf( "-> %d (unique) ", Vec_WrdSize(vFuncs) );
|
|
Vec_WrdForEachEntry( vFuncs, Func, i ) {
|
|
uCanonPhase = Abc_TtCanonicize( &Func, nVars, pCanonPerm );
|
|
Vec_WrdWriteEntry( vFuncs, i, Func );
|
|
}
|
|
Vec_WrdUniqify( vFuncs );
|
|
if ( fVerbose ) printf( "-> %d (approx NPN) ", Vec_WrdSize(vFuncs) );
|
|
Abc_TtHieMan_t * pMan = Abc_TtHieManStart(nVars, 5);
|
|
Vec_WrdForEachEntry( vFuncs, Func, i ) {
|
|
uCanonPhase = Abc_TtCanonicizeWrap(Abc_TtCanonicizeCA, pMan, &Func, nVars, pCanonPerm, 1);
|
|
Vec_WrdWriteEntry( vFuncs, i, Func );
|
|
}
|
|
Vec_WrdUniqify( vFuncs );
|
|
if ( fVerbose ) printf( "-> %d (exact NPN). ", Vec_WrdSize(vFuncs) );
|
|
Abc_TtHieManStop(pMan);
|
|
Abc_PrintTime( 1, "Time", Abc_Clock() - clkStart );
|
|
fflush( stdout );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
/// END OF FILE ///
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
ABC_NAMESPACE_IMPL_END
|