From 4156a88dbbfd5fb0f87a6ff92862e5c00db2d116 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 9 Aug 2024 12:39:43 -0700 Subject: [PATCH] Extending &funtrace to trace functions found in an AIG. --- src/aig/gia/giaCut.c | 122 +++++++++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 63 ++++++++++++++++++++-- src/opt/dau/dauNpn.c | 113 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+), 5 deletions(-) diff --git a/src/aig/gia/giaCut.c b/src/aig/gia/giaCut.c index 47dc5ec7b..fbd931f9e 100644 --- a/src/aig/gia/giaCut.c +++ b/src/aig/gia/giaCut.c @@ -1108,6 +1108,128 @@ Vec_Ptr_t * Gia_ManMatchCutsArray( Vec_Ptr_t * vTtMems, Gia_Man_t * pGia, int nC return vRes; } +/**Function************************************************************* + + Synopsis [Function enumeration.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Wrd_t * Gia_ManCollectCutFuncs( Gia_Man_t * p, int nCutSize, int nCutNum, int fVerbose ) +{ + Gia_Sto_t * pSto = Gia_ManMatchCutsInt( p, nCutSize, nCutNum, 0 ); + Vec_Wrd_t * vFuncs = Vec_WrdAlloc( 1000 ); Vec_Int_t * vLevel; int i, k, * pCut; + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) if ( pCut[0] == nCutSize ) { + word * pTruth = Vec_MemReadEntry( pSto->vTtMem, Abc_Lit2Var(pCut[pCut[0]+1]) ); + Vec_WrdPush( vFuncs, pTruth[0] ); + } + Gia_StoFree( pSto ); + if ( fVerbose ) + printf( "Collected %d cut functions using the AIG with %d nodes.\n", Vec_WrdSize(vFuncs), Gia_ManAndNum(p) ); + return vFuncs; +} +Vec_Int_t * Gia_ManCountNpnClasses( Vec_Mem_t * vTtMem, Vec_Int_t * vMap, int nClasses, Vec_Wrd_t * vOrig ) +{ + assert( Vec_MemEntryNum(vTtMem) == Vec_IntSize(vMap) ); + Vec_Int_t * vClassCounts = Vec_IntStart( nClasses ); int i; word Func; + Vec_WrdForEachEntry( vOrig, Func, i ) { + int * pSpot = Vec_MemHashLookup( vTtMem, &Func ); + if ( *pSpot == -1 ) + continue; + int iClass = Vec_IntEntry( vMap, *pSpot ); + if ( iClass == -1 ) + continue; + assert( iClass < Vec_IntSize(vClassCounts) ); + Vec_IntAddToEntry( vClassCounts, iClass, 1 ); + } + return vClassCounts; +} +Vec_Wrd_t * Gia_ManMatchFilterClasses( Vec_Mem_t * vTtMem, Vec_Int_t * vMap, Vec_Int_t * vClassCounts, int nNumFuncs, int fVerbose ) +{ + int * pPerm = Abc_MergeSortCost( Vec_IntArray(vClassCounts), Vec_IntSize(vClassCounts) ); + Vec_Wrd_t * vBest = Vec_WrdAlloc( nNumFuncs ); int i, k, Entry; + Vec_Int_t * vMapNew = Vec_IntStartFull( Vec_IntSize(vMap) ); + for ( i = Vec_IntSize(vClassCounts)-1; i >= 0; i-- ) { + word Best = ~(word)0; + Vec_IntForEachEntry( vMap, Entry, k ) { + if ( Entry != pPerm[i] ) + continue; + if ( Best > Vec_MemReadEntry(vTtMem, k)[0] ) + Best = Vec_MemReadEntry(vTtMem, k)[0]; + Vec_IntWriteEntry( vMapNew, k, Vec_WrdSize(vBest) ); + } + Vec_WrdPush( vBest, Best ); + assert( ~Best ); + if ( Vec_WrdSize(vBest) == nNumFuncs ) + break; + } + ABC_SWAP( Vec_Int_t, *vMap, *vMapNew ); + Vec_IntFree( vMapNew ); + ABC_FREE( pPerm ); + if ( fVerbose ) + printf( "Isolated %d (out of %d) most frequently occuring classes.\n", Vec_WrdSize(vBest), Vec_IntSize(vClassCounts) ); + return vBest; +} +void Gia_ManMatchProfileFunctions( Vec_Wrd_t * vBestReprs, Vec_Mem_t * vTtMem, Vec_Int_t * vMap, Vec_Wrd_t * vFuncs, int nCutSize ) +{ + int BarSize = 60; + extern void Dau_DsdPrintFromTruth( word * pTruth, int nVarsInit ); + Vec_Int_t * vCounts = Gia_ManCountNpnClasses( vTtMem, vMap, Vec_WrdSize(vBestReprs), vFuncs ); + word Repr; int c, i, MaxCount = Vec_IntFindMax( vCounts ); + Vec_WrdForEachEntry( vBestReprs, Repr, c ) + { + int nSymb = BarSize*Vec_IntEntry(vCounts, c)/Abc_MaxInt(MaxCount, 1); + printf( "Class%4d : ", c ); + printf( "Count =%6d ", Vec_IntEntry(vCounts, c) ); + for ( i = 0; i < nSymb; i++ ) + printf( "*" ); + for ( i = nSymb; i < BarSize+3; i++ ) + printf( " " ); + Dau_DsdPrintFromTruth( &Repr, nCutSize ); + } + Vec_IntFree( vCounts ); +} +void Gia_ManMatchCones( Gia_Man_t * pBig, Gia_Man_t * pSmall, int nCutSize, int nCutNum, int nNumFuncs, int nNumCones, int fVerbose ) +{ + abctime clkStart = Abc_Clock(); + extern void Dau_CanonicizeArray( Vec_Wrd_t * vFuncs, int nVars, int fVerbose ); + extern Vec_Mem_t * Dau_CollectNpnFunctionsArray( Vec_Wrd_t * vFuncs, int nVars, Vec_Int_t ** pvMap, int fVerbose ); + Vec_Wrd_t * vFuncs = Gia_ManCollectCutFuncs( pSmall, nCutSize, nCutNum, fVerbose ); + Vec_Wrd_t * vOrig = Vec_WrdDup( vFuncs ); + Dau_CanonicizeArray( vFuncs, nCutSize, fVerbose ); + Vec_Int_t * vMap = NULL; int n; + Vec_Mem_t * vTtMem = Dau_CollectNpnFunctionsArray( vFuncs, nCutSize, &vMap, fVerbose ); + Vec_WrdFree( vFuncs ); + Vec_Int_t * vClassCounts = Gia_ManCountNpnClasses( vTtMem, vMap, Vec_IntEntryLast(vMap)+1, vOrig ); + Vec_Wrd_t * vBestReprs = Gia_ManMatchFilterClasses( vTtMem, vMap, vClassCounts, nNumFuncs, fVerbose ); + assert( Vec_WrdSize(vBestReprs) == nNumFuncs ); + Vec_IntFree( vClassCounts ); + printf( "Frequency profile for %d most popular classes in the small AIG:\n", nNumFuncs ); + Gia_ManMatchProfileFunctions( vBestReprs, vTtMem, vMap, vOrig, nCutSize ); + Vec_WrdFree( vOrig ); + Abc_Random( 1 ); + for ( n = 0; n < nNumCones; n++ ) { + int nRand = Abc_Random( 0 ) % Gia_ManCoNum(pBig); + Gia_Man_t * pCone = Gia_ManDupCones( pBig, &nRand, 1, 1 ); + Vec_Wrd_t * vCutFuncs = Gia_ManCollectCutFuncs( pCone, nCutSize, nCutNum, 0 ); + printf( "ITER %d: Considering output cone %d with %d and-nodes. ", n+1, nRand, Gia_ManAndNum(pCone) ); + printf( "Profiling %d functions of %d-cuts:\n", Vec_WrdSize(vCutFuncs), nCutSize ); + Gia_ManMatchProfileFunctions( vBestReprs, vTtMem, vMap, vCutFuncs, nCutSize ); + Vec_WrdFree( vCutFuncs ); + Gia_ManStop( pCone ); + } + Vec_WrdFree( vBestReprs ); + Vec_IntFree( vMap ); + Vec_MemHashFree( vTtMem ); + Vec_MemFree( vTtMem ); + Abc_PrintTime( 1, "Total computation time", Abc_Clock() - clkStart ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 69c6595ff..4daaccecd 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -54209,10 +54209,10 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern Vec_Mem_t * Dau_CollectNpnFunctions( word * p, int nVars, int fVerbose ); extern void Gia_ManMatchCuts( Vec_Mem_t * vTtMem, Gia_Man_t * pGia, int nCutSize, int nCutNum, int fVerbose ); - int c, nVars, nVars2, nCutNum = 8, fVerbose = 0; word * pTruth = NULL; - char * pStr = NULL; Vec_Mem_t * vTtMem = NULL; + int c, nVars, nVars2, nCutNum = 8, nCutSize = 0, nNumFuncs = 5, nNumCones = 3, fVerbose = 0; word * pTruth = NULL; + char * pStr = NULL; Vec_Mem_t * vTtMem = NULL; Gia_Man_t * pTemp; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "Cvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "CKNMvh" ) ) != EOF ) { switch ( c ) { @@ -54227,6 +54227,39 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( nCutNum < 0 ) goto usage; break; + case 'K': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-K\" should be followed by an integer.\n" ); + goto usage; + } + nCutSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nCutSize < 0 ) + goto usage; + break; + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); + goto usage; + } + nNumFuncs = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nNumFuncs < 0 ) + goto usage; + break; + case 'M': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" ); + goto usage; + } + nNumCones = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nNumCones < 0 ) + goto usage; + break; case 'v': fVerbose ^= 1; break; @@ -54246,6 +54279,22 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Abc_CommandAbc9FunTrace(): Truth table in hex notation should be given on the command line.\n" ); return 0; } + if ( strstr(argv[globalUtilOptind], ".aig") ) + { // the entry on the command line is an AIGER file + extern void Gia_ManMatchCones( Gia_Man_t * pBig, Gia_Man_t * pSmall, int nCutSize, int nCutNum, int nNumFuncs, int nNumCones, int fVerbose ); + if ( nCutSize == 0 ) { + Abc_Print( -1, "Abc_CommandAbc9FunTrace(): The LUT size for profiling should be given on the command line.\n" ); + return 0; + } + pTemp = Gia_AigerRead( argv[globalUtilOptind], 0, 0, 0 ); + if ( pTemp == NULL ) { + Abc_Print( -1, "Abc_CommandAbc9FunTrace(): Cannot read input AIG \"%s\".\n", argv[globalUtilOptind] ); + return 0; + } + Gia_ManMatchCones( pAbc->pGia, pTemp, nCutSize, nCutNum, nNumFuncs, nNumCones, fVerbose ); + Gia_ManStop( pTemp ); + return 0; + } pStr = argv[globalUtilOptind]; if ( pStr[0] == '0' && pStr[1] == 'x' ) pStr += 2; @@ -54271,12 +54320,16 @@ int Abc_CommandAbc9FunTrace( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &funtrace [-C num] [-vh] \n" ); + Abc_Print( -2, "usage: &funtrace [-CKNM num] [-vh] { or }\n" ); Abc_Print( -2, "\t traces the presence of the function in the current AIG\n" ); Abc_Print( -2, "\t-C num : the number of cuts to compute at each node [default = %d]\n", nCutNum ); + Abc_Print( -2, "\t-K num : the LUT size to use when is given [default = %d]\n", nCutSize ); + Abc_Print( -2, "\t-N num : the number of functions to use when is given [default = %d]\n", nNumFuncs ); + Abc_Print( -2, "\t-M num : the number of logic cones to use when is given [default = %d]\n", nNumCones ); Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose ? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); - Abc_Print( -2, "\t : truth table in the hexadecimal notation\n"); + Abc_Print( -2, "\t : truth table in the hexadecimal notation used for tracing\n"); + Abc_Print( -2, "\t : AIG whose K-input functions will be used for tracing\n"); return 1; } diff --git a/src/opt/dau/dauNpn.c b/src/opt/dau/dauNpn.c index 71cc857b6..8f0f4fb73 100644 --- a/src/opt/dau/dauNpn.c +++ b/src/opt/dau/dauNpn.c @@ -859,6 +859,119 @@ Vec_Mem_t * Dau_CollectNpnFunctions( word * p, int nVars, int fVerbose ) return 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 ) +{ + 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 Truth; + assert( nWords == 1 ); + Vec_WrdForEachEntry( vFuncs, Truth, t ) + { + int nFuncs = Vec_MemEntryNum(vTtMem); + Truth = (Truth & 1) ? ~Truth : Truth; + word pCopy[1] = {Truth}; + 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 ); + } + assert( Abc_TtEqual(pCopy, &Truth, nWords) ); + 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) ); + } + for ( i = nFuncs; i < Vec_MemEntryNum(vTtMem); i++ ) + Vec_IntPush( vMap, t ); + Vec_IntPush( vCnts, Vec_MemEntryNum(vTtMem) - nFuncs ); + } + ABC_FREE( pPerm ); + ABC_FREE( pComp ); + if ( fVerbose ) { + printf( "Collected %d", Vec_MemEntryNum(vTtMem) ); + Vec_IntForEachEntryStop( vCnts, Entry, i, 7 ) + printf( " %c %d", i ? '+' : '=', Entry ); + if ( Vec_IntSize(vCnts) > 7 ) + 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(); + extern unsigned Abc_TtCanonicizeCA(Abc_TtHieMan_t * p, word * pTruth, int nVars, char * pCanonPerm, int iThres); + 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 /// ////////////////////////////////////////////////////////////////////////