From 02f3727d87a15d497a1bdf973f5fe44db8ab8565 Mon Sep 17 00:00:00 2001 From: qiuweibin <354238065@qq.com> Date: Tue, 11 Mar 2025 03:38:50 +0000 Subject: [PATCH 01/42] Fix the null reference vulnerability --- src/base/abci/abcOrchestration.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/base/abci/abcOrchestration.c b/src/base/abci/abcOrchestration.c index 5d12a529b..5b952da11 100644 --- a/src/base/abci/abcOrchestration.c +++ b/src/base/abci/abcOrchestration.c @@ -4444,6 +4444,8 @@ Rwr_ManAddTimeCuts( pManRwr, Abc_Clock() - clk ); // skip persistant nodes if ( Abc_NodeIsPersistant(pNode) ) { + if (!(pGain_res && pGain_ref && pGain_rwr)) + return 0; fprintf(fpt, "%d, %s, %d\n", pNode->Id, "None" , -99); Vec_IntPush((*pGain_res), -99); Vec_IntPush((*pGain_ref), -99); @@ -4453,6 +4455,8 @@ Rwr_ManAddTimeCuts( pManRwr, Abc_Clock() - clk ); // skip the nodes with many fanouts if ( Abc_ObjFanoutNum(pNode) > 1000 ) { + if (!(pGain_res && pGain_ref && pGain_rwr)) + return 0; fprintf(fpt, "%d, %s, %d\n", pNode->Id,"None", -99); Vec_IntPush((*pGain_res), -99); Vec_IntPush((*pGain_ref), -99); From 504f604d2af9b902c6b39f52e561e2b4d951ffe2 Mon Sep 17 00:00:00 2001 From: wjrforcyber Date: Wed, 12 Mar 2025 14:27:47 +0800 Subject: [PATCH 02/42] Refactor(cmake): Generate compilation database Signed-off-by: wjrforcyber --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05e6001f9..bbb153e64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.5.0) include(CMakeParseArguments) include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) +# Generate compilation database compile_commands.json +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Default c++ standard used unless otherwise specified in target_compile_features. set(CMAKE_CXX_STANDARD 17 CACHE STRING "the C++ standard to use for this project") From 5ef9c3c50b0324c132f1c8b3153ce85c56c8bd76 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 12 Mar 2025 20:11:33 -0700 Subject: [PATCH 03/42] Experiment with mapping. --- src/aig/gia/giaSatLut.c | 250 ++++++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 126 +++++++++++++++++++- 2 files changed, 375 insertions(+), 1 deletion(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index ba25ec90e..c4e11e674 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1567,6 +1567,256 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ + +#define KSAT_OBJS 24 +#define KSAT_MINTS 64 +#define KSAT_SPACE (4+3*KSAT_OBJS+KSAT_MINTS) + +int Gia_KSatVarInv( int * pMap, int i ) { return pMap[i*KSAT_SPACE+0]; } +int Gia_KSatVarAnd( int * pMap, int i ) { return pMap[i*KSAT_SPACE+1]; } +int Gia_KSatVarEqu( int * pMap, int i ) { return pMap[i*KSAT_SPACE+2]; } +int Gia_KSatVarRef( int * pMap, int i ) { return pMap[i*KSAT_SPACE+3]; } +int Gia_KSatVarFan( int * pMap, int i, int f, int k ) { return pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k]; } +int Gia_KSatVarMin( int * pMap, int i, int m ) { return pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m]; } + +void Gia_KSatSetInv( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+0] ); pMap[i*KSAT_SPACE+0] = iVar; } +void Gia_KSatSetAnd( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+1] ); pMap[i*KSAT_SPACE+1] = iVar; } +void Gia_KSatSetEqu( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+2] ); pMap[i*KSAT_SPACE+2] = iVar; } +void Gia_KSatSetRef( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+3] ); pMap[i*KSAT_SPACE+3] = iVar; } +void Gia_KSatSetFan( int * pMap, int i, int f, int k, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] = iVar; } +void Gia_KSatSetMin( int * pMap, int i, int m, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] = iVar; } + +int Gia_KSatValInv( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+0] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+0] ); } +int Gia_KSatValAnd( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+1] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+1] ); } +int Gia_KSatValEqu( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+2] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+2] ); } +int Gia_KSatValRef( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+3] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+3] ); } +int Gia_KSatValFan( int * pMap, int i, int f, int k, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); } +int Gia_KSatValMin( int * pMap, int i, int m, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); } + +int * Gia_KSatMapInit( int nIns, int nNodes, word Truth, int * pnVars ) +{ + assert( nIns + nNodes <= KSAT_OBJS ); + assert( (1 << nIns) <= KSAT_MINTS ); + int n, m, f, k, nVars = 2, * pMap = ABC_FALLOC( int, KSAT_OBJS*KSAT_SPACE ); + for ( n = nIns; n < nIns+nNodes; n++ ) { + Gia_KSatSetInv(pMap, n, nVars++); + Gia_KSatSetAnd(pMap, n, nVars++); + Gia_KSatSetEqu(pMap, n, nVars++); + Gia_KSatSetRef(pMap, n, nVars++); + } + for ( n = nIns; n < nIns+nNodes; n++ ) { + for ( f = 0; f < 2; f++ ) + for ( k = 0; k < n; k++ ) + Gia_KSatSetFan(pMap, n, f, k, nVars++); + for ( k = n+1; k < nIns+nNodes; k++ ) + Gia_KSatSetFan(pMap, n, 2, k, nVars++); + } + for ( m = 0; m < (1<> n) & 1 ); + Gia_KSatSetMin(pMap, nIns+nNodes-1, m, (Truth >> m) & 1 ); + for ( n = nIns; n < nIns+nNodes-1; n++ ) + Gia_KSatSetMin(pMap, n, m, nVars++); + } + if ( pnVars ) *pnVars = nVars; + return pMap; +} + +int Gia_KSatFindFan( int * pMap, int i, int f, Vec_Int_t * vRes ) +{ + assert( f < 2 ); + for ( int k = 0; k < i; k++ ) + if ( Gia_KSatValFan( pMap, i, f, k, vRes ) ) + return k; + assert( 0 ); + return -1; +} + +Gia_Man_t * Gia_ManDeriveKSatMapping( Vec_Int_t * vRes, int * pMap, int nIns, int nNodes, int fVerbose ) +{ + Gia_Man_t * pNew = Gia_ManStart( nIns + nNodes + 2 ); + pNew->pName = Abc_UtilStrsav( "test" ); + int i, pCopy[256] = {0}; + for ( i = 1; i <= nIns; i++ ) + pCopy[i] = Gia_ManAppendCi( pNew ); + for ( i = nIns; i < nIns+nNodes; i++ ) { + int iFan0 = Gia_KSatFindFan( pMap, i, 0, vRes ); + int iFan1 = Gia_KSatFindFan( pMap, i, 1, vRes ); + if ( iFan0 == iFan1 ) + pCopy[i+1] = pCopy[iFan0+1]; + else if ( Gia_KSatValAnd(pMap, i, vRes) ) + pCopy[i+1] = Gia_ManAppendAnd( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); + else + pCopy[i+1] = Gia_ManAppendOr( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); + pCopy[i+1] = Abc_LitNotCond( pCopy[i+1], Gia_KSatValInv(pMap, i, vRes) ); + if ( fVerbose ) { + printf( "%d = ", i ); + if ( iFan0 == iFan1 ) + printf( "INV( %d )\n", iFan0 ); + else if ( Gia_KSatValAnd(pMap, i, vRes) ) + printf( "%sAND( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); + else + printf( "%sOR( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); + if ( i == nIns+nNodes-1 ) + printf( "CO = %d\n", nIns+nNodes-1 ); + } + } + Gia_ManAppendCo( pNew, pCopy[nIns+nNodes] ); + return pNew; +} + +Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) +{ + Vec_Str_t * vStr = Vec_StrAlloc( 10000 ); + int i, j, m, n, f, c, a, nLits = 0, pLits[256] = {0}; + Gia_SatDumpLiteral( vStr, 1 ); + Gia_SatDumpLiteral( vStr, 2 ); + // fanins are connected once + for ( n = nIns; n < nIns+nNodes; n++ ) + for ( f = 0; f < 2; f++ ) { + nLits = 0; + for ( i = 0; i < n; i++ ) + pLits[nLits++] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 0 ); + Gia_SatDumpClause( vStr, pLits, nLits ); + for ( i = 0; i < n; i++ ) + for ( j = 0; j < i; j++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, j), 1 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + } + } + for ( n = nIns; n < nIns+nNodes; n++ ) { + // fanins are equal + for ( i = 0; i < n; i++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 0, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, i), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarEqu(pMap, n), 0 ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } + // if fanins are equal, inv is used + pLits[0] = Abc_Var2Lit( Gia_KSatVarEqu(pMap, n), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + // fanin ordering + for ( i = 0; i < n; i++ ) + for ( j = 0; j < i; j++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 0, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, j), 1 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + } + } + for ( n = nIns; n < nIns+nNodes-1; n++ ) { + // there is a fanout to the node above + for ( i = n+1; i < nIns+nNodes; i++ ) + for ( f = 0; f < 2; f++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, i, f, n), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 0 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + } + // there is at least one fanout, except the last one + nLits = 0; + for ( i = n+1; i < nIns+nNodes; i++ ) + pLits[nLits++] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 0 ); + assert( nLits > 0 ); + Gia_SatDumpClause( vStr, pLits, nLits ); + } + // there is more than one fanout, except the last one + for ( n = nIns; n < nIns+nNodes-1; n++ ) { + for ( i = n+1; i < nIns+nNodes; i++ ) + for ( j = i+1; j < nIns+nNodes; j++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, j), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarRef(pMap, n), 0 ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } + // if more than one fanout, inv is used + pLits[0] = Abc_Var2Lit( Gia_KSatVarRef(pMap, n), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + // if inv is not used, its fanins' invs are used + pLits[0] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); + for ( i = nIns; i < n; i++ ) + for ( f = 0; f < 2; f++ ) { + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarInv(pMap, i), 0 ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } + } + // the last one always uses inverter + Gia_SatDumpLiteral( vStr, Abc_Var2Lit( Gia_KSatVarInv(pMap, nIns+nNodes-1), 0 ) ); + // for each minterm, for each pair of possible fanins, the node's output is determined using and/or and inv (4*N*N*M) + for ( m = 0; m < (1 << nIns); m++ ) + for ( n = nIns; n < nIns+nNodes; n++ ) + for ( c = 0; c < 2; c++ ) + for ( a = 0; a < 2; a++ ) { + // implications: Fan(f) & Mint(m) & !And & !Inv -> Val1 + for ( f = 0; f < 2; f++ ) + for ( i = 0; i < n; i++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m), !a ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); + pLits[3] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); + pLits[4] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m), a^c ); + Gia_SatDumpClause( vStr, pLits, 5 ); + } + // large clauses: Fan(0) & Fan(1) & !Mint(m) & !Mint(m) & !And & !Inv -> Val0 + for ( i = 0; i < n; i++ ) + for ( j = i; j < n; j++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 0, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, j), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m), a ); + pLits[3] = Abc_Var2Lit( Gia_KSatVarMin(pMap, j, m), a ); + pLits[4] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); + pLits[5] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); + pLits[6] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m), a==c ); + Gia_SatDumpClause( vStr, pLits, 7 ); + } + } + // the number of nodes with duplicated fanins and without inv is maximized + Vec_StrPush( vStr, '\0' ); + return vStr; +} + +Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ) +{ + Gia_Man_t * pNew = NULL; + char * pFileNameI = (char *)"__temp__.cnf"; + char * pFileNameO = (char *)"__temp__.out"; + int nVars = 0, * pMap = Gia_KSatMapInit( nIns, nNodes, Truth, &nVars ); + Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound ); + if ( !Gia_ManDumpCnf(pFileNameI, vStr, nVars) ) { + Vec_StrFree( vStr ); + return NULL; + } + if ( fVerbose ) + printf( "Vars = %d. Nodes = %d. Cardinality bound = %d. SAT vars = %d. SAT clauses = %d. Conflict limit = %d. Timeout = %d.\n", + nIns, nNodes, nBound, nVars, Vec_StrCountEntry(vStr, '\n'), nBTLimit, nTimeout ); + //char pFileName[100]; sprintf( pFileName, "temp%02d.cnf", nBound/2 ); + //Gia_ManDumpCnf( pFileName, vStr, nVars ); + Vec_StrFree( vStr ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1 ); + unlink( pFileNameI ); + //unlink( pFileNameO ); + if ( vRes == NULL ) + return 0; + Vec_IntDrop( vRes, 0 ); + pNew = Gia_ManDeriveKSatMapping( vRes, pMap, nIns, nNodes, fVerbose ); + Vec_IntFree( vRes ); + ABC_FREE( pMap ); + return pNew; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 93fc10efb..2206a02b7 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -513,6 +513,7 @@ static int Abc_CommandAbc9Mf ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9Nf ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Of ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Simap ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Exmap ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Pack ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Edge ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SatLut ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1321,6 +1322,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&nf", Abc_CommandAbc9Nf, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&of", Abc_CommandAbc9Of, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&simap", Abc_CommandAbc9Simap, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&exmap", Abc_CommandAbc9Exmap, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&pack", Abc_CommandAbc9Pack, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&edge", Abc_CommandAbc9Edge, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&satlut", Abc_CommandAbc9SatLut, 0 ); @@ -44393,7 +44395,7 @@ int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'B': if ( globalUtilOptind >= argc ) { - Abc_Print( -1, "Command line switch \"-N\" should be followed by a positive integer.\n" ); + Abc_Print( -1, "Command line switch \"-B\" should be followed by a positive integer.\n" ); goto usage; } nBound = atoi(argv[globalUtilOptind]); @@ -44456,6 +44458,126 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ); + int c, nVars = 0, nNodes = 0, nBTLimit = 0, nBound = 0, nTimeout = 0, fVerbose = 0; Gia_Man_t * pTemp = NULL; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "NBCTvh" ) ) != EOF ) + { + switch ( c ) + { + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by a positive integer.\n" ); + goto usage; + } + nNodes = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nNodes < 0 ) + { + Abc_Print( -1, "Bound on a solution should be a positive integer.\n" ); + goto usage; + } + break; + case 'B': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-B\" should be followed by a positive integer.\n" ); + goto usage; + } + nBound = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nBound < 0 ) + { + Abc_Print( -1, "Bound on a solution should be a positive integer.\n" ); + goto usage; + } + break; + case 'C': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-C\" should be followed by a positive integer.\n" ); + goto usage; + } + nBTLimit = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nBTLimit < 0 ) + { + Abc_Print( -1, "Conflict limit should be a positive integer.\n" ); + goto usage; + } + break; + case 'T': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-T\" should be followed by a positive integer.\n" ); + goto usage; + } + nTimeout = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + default: + goto usage; + } + } + if ( argc != globalUtilOptind + 1 ) + { + Abc_Print( -1, "Truth table should be given on the command line.\n" ); + return 1; + } + char * pTruth = argv[globalUtilOptind]; + nVars = Abc_Base2Log(4*strlen(pTruth)); + if ( (1 << nVars) != 4*strlen(pTruth) ) + { + Abc_Print( -1, "The string (%s) does not look like a hex truth table.\n", pTruth ); + return 1; + } + if ( nVars > 6 ) + { + Abc_Print( -1, "Currently only works for functions of 6 of fewer inputs.\n" ); + return 1; + } + if ( nNodes == 0 ) + { + Abc_Print( -1, "The number of nodes should be given on the command line (-N ).\n" ); + return 1; + } + word Truth = 0; + int nVars2 = Abc_TtReadHex( &Truth, pTruth ); + assert( nVars2 == nVars ); + pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, nBTLimit, nTimeout, fVerbose ); + if ( pTemp ) Abc_FrameUpdateGia( pAbc, pTemp ); + return 0; + +usage: + Abc_Print( -2, "usage: &exmap [-NBCT num] [-vh] \n" ); + Abc_Print( -2, "\t performs simple mapping of the truth table\n" ); + Abc_Print( -2, "\t-N num : the number of nodes [default = %d]\n", nNodes ); + Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); + Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); + Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); + Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : prints the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] @@ -45818,6 +45940,8 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) } pTemp = Gia_ManRewire( pAbc->pGia, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); + if ( pTemp->pName == NULL ) + pTemp->pName = Abc_UtilStrsav(Extra_FileNameWithoutPath(pAbc->pGia->pName)); Abc_FrameUpdateGia( pAbc, pTemp ); return 0; From feefa0f5134a9ae7d9e4abc466970b912938888f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 12 Mar 2025 20:12:28 -0700 Subject: [PATCH 04/42] Supporting out of order signal names in AIGER reader. --- src/aig/gia/giaAiger.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index 9c6ca8992..107faaceb 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -406,24 +406,24 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi if ( *pType == 'i' ) { if ( vNamesIn == NULL ) - vNamesIn = Vec_PtrAlloc( nInputs + nLatches ); - if ( Vec_PtrSize(vNamesIn) != iTerm ) + vNamesIn = Vec_PtrStart( nInputs ); + if ( Vec_PtrSize(vNamesIn) <= iTerm ) { fError = 1; break; } - Vec_PtrPush( vNamesIn, Abc_UtilStrsav(pName) ); + Vec_PtrWriteEntry( vNamesIn, iTerm, Abc_UtilStrsav(pName) ); } else if ( *pType == 'o' ) { if ( vNamesOut == NULL ) - vNamesOut = Vec_PtrAlloc( nOutputs + nLatches ); - if ( Vec_PtrSize(vNamesOut) != iTerm ) + vNamesOut = Vec_PtrStart( nOutputs ); + if ( Vec_PtrSize(vNamesOut) <= iTerm ) { fError = 1; break; } - Vec_PtrPush( vNamesOut, Abc_UtilStrsav(pName) ); + Vec_PtrWriteEntry( vNamesOut, iTerm, Abc_UtilStrsav(pName) ); } else if ( *pType == 'l' ) { @@ -431,16 +431,16 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi assert( strlen(pName) < 995 ); sprintf( Buffer, "%s_in", pName ); if ( vNamesRegIn == NULL ) - vNamesRegIn = Vec_PtrAlloc( nLatches ); + vNamesRegIn = Vec_PtrStart( nLatches ); if ( vNamesRegOut == NULL ) - vNamesRegOut = Vec_PtrAlloc( nLatches ); - if ( Vec_PtrSize(vNamesRegIn) != iTerm ) + vNamesRegOut = Vec_PtrStart( nLatches ); + if ( Vec_PtrSize(vNamesRegIn) <= iTerm ) { fError = 1; break; } - Vec_PtrPush( vNamesRegIn, Abc_UtilStrsav(Buffer) ); - Vec_PtrPush( vNamesRegOut, Abc_UtilStrsav(pName) ); + Vec_PtrWriteEntry( vNamesRegIn, iTerm, Abc_UtilStrsav(Buffer) ); + Vec_PtrWriteEntry( vNamesRegOut, iTerm, Abc_UtilStrsav(pName) ); } else if ( *pType == 'n' ) { From 2361a02c991bf6eb5cfbafd64a5aa4ea897e2417 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 12 Mar 2025 20:53:02 -0700 Subject: [PATCH 05/42] Fixing compilation problemj in some builds. --- src/base/abci/abc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 2206a02b7..663bdac14 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -44472,7 +44472,8 @@ usage: int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ); - int c, nVars = 0, nNodes = 0, nBTLimit = 0, nBound = 0, nTimeout = 0, fVerbose = 0; Gia_Man_t * pTemp = NULL; + Gia_Man_t * pTemp = NULL; char * pTruth = NULL; word Truth = 0; + int c, nVars = 0, nNodes = 0, nVars2, nBTLimit = 0, nBound = 0, nTimeout = 0, fVerbose = 0; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "NBCTvh" ) ) != EOF ) { @@ -44542,7 +44543,7 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Truth table should be given on the command line.\n" ); return 1; } - char * pTruth = argv[globalUtilOptind]; + pTruth = argv[globalUtilOptind]; nVars = Abc_Base2Log(4*strlen(pTruth)); if ( (1 << nVars) != 4*strlen(pTruth) ) { @@ -44558,9 +44559,8 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Print( -1, "The number of nodes should be given on the command line (-N ).\n" ); return 1; - } - word Truth = 0; - int nVars2 = Abc_TtReadHex( &Truth, pTruth ); + } + nVars2 = Abc_TtReadHex( &Truth, pTruth ); assert( nVars2 == nVars ); pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, nBTLimit, nTimeout, fVerbose ); if ( pTemp ) Abc_FrameUpdateGia( pAbc, pTemp ); From 27fdbe0162b4dc05c6c26bd1cdbd617853549838 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Mar 2025 11:57:34 -0700 Subject: [PATCH 06/42] Updates to the mapping experiment. --- src/aig/gia/giaSatLut.c | 122 ++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 24 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index c4e11e674..49b5f8b99 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -20,6 +20,7 @@ #include "gia.h" #include "misc/tim/tim.h" +#include "misc/util/utilTruth.h" #include "sat/bsat/satStore.h" #include "misc/util/utilNam.h" #include "map/scl/sclCon.h" @@ -1581,28 +1582,28 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, #define KSAT_OBJS 24 #define KSAT_MINTS 64 -#define KSAT_SPACE (4+3*KSAT_OBJS+KSAT_MINTS) +#define KSAT_SPACE (4+3*KSAT_OBJS+3*KSAT_MINTS) int Gia_KSatVarInv( int * pMap, int i ) { return pMap[i*KSAT_SPACE+0]; } int Gia_KSatVarAnd( int * pMap, int i ) { return pMap[i*KSAT_SPACE+1]; } int Gia_KSatVarEqu( int * pMap, int i ) { return pMap[i*KSAT_SPACE+2]; } int Gia_KSatVarRef( int * pMap, int i ) { return pMap[i*KSAT_SPACE+3]; } -int Gia_KSatVarFan( int * pMap, int i, int f, int k ) { return pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k]; } -int Gia_KSatVarMin( int * pMap, int i, int m ) { return pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m]; } +int Gia_KSatVarFan( int * pMap, int i, int f, int k ) { return pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k]; } +int Gia_KSatVarMin( int * pMap, int i, int m, int k ) { return pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+3*m+k]; } void Gia_KSatSetInv( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+0] ); pMap[i*KSAT_SPACE+0] = iVar; } void Gia_KSatSetAnd( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+1] ); pMap[i*KSAT_SPACE+1] = iVar; } void Gia_KSatSetEqu( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+2] ); pMap[i*KSAT_SPACE+2] = iVar; } void Gia_KSatSetRef( int * pMap, int i, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+3] ); pMap[i*KSAT_SPACE+3] = iVar; } -void Gia_KSatSetFan( int * pMap, int i, int f, int k, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] = iVar; } -void Gia_KSatSetMin( int * pMap, int i, int m, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] = iVar; } +void Gia_KSatSetFan( int * pMap, int i, int f, int k, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] = iVar; } +void Gia_KSatSetMin( int * pMap, int i, int m, int k, int iVar ) { assert( -1 == pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+3*m+k] ); pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+3*m+k] = iVar; } int Gia_KSatValInv( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+0] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+0] ); } int Gia_KSatValAnd( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+1] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+1] ); } int Gia_KSatValEqu( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+2] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+2] ); } int Gia_KSatValRef( int * pMap, int i, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+3] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+3] ); } -int Gia_KSatValFan( int * pMap, int i, int f, int k, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); } -int Gia_KSatValMin( int * pMap, int i, int m, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+m] ); } +int Gia_KSatValFan( int * pMap, int i, int f, int k, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+f*KSAT_OBJS+k] ); } +int Gia_KSatValMin( int * pMap, int i, int m, int k, Vec_Int_t * vRes ) { assert( -1 != pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+3*m+k] ); return Vec_IntEntry( vRes, pMap[i*KSAT_SPACE+4+3*KSAT_OBJS+3*m+k] ); } int * Gia_KSatMapInit( int nIns, int nNodes, word Truth, int * pnVars ) { @@ -1624,10 +1625,13 @@ int * Gia_KSatMapInit( int nIns, int nNodes, word Truth, int * pnVars ) } for ( m = 0; m < (1<> n) & 1 ); - Gia_KSatSetMin(pMap, nIns+nNodes-1, m, (Truth >> m) & 1 ); - for ( n = nIns; n < nIns+nNodes-1; n++ ) - Gia_KSatSetMin(pMap, n, m, nVars++); + Gia_KSatSetMin(pMap, n, m, 0, (m >> n) & 1 ); + Gia_KSatSetMin(pMap, nIns+nNodes-1, m, 0, (Truth >> m) & 1 ); + for ( n = nIns; n < nIns+nNodes; n++ ) + for ( k = 0; k < 3; k++ ) + if ( k || n < nIns+nNodes-1 ) + Gia_KSatSetMin(pMap, n, m, k, nVars++); + } if ( pnVars ) *pnVars = nVars; return pMap; @@ -1647,7 +1651,7 @@ Gia_Man_t * Gia_ManDeriveKSatMapping( Vec_Int_t * vRes, int * pMap, int nIns, in { Gia_Man_t * pNew = Gia_ManStart( nIns + nNodes + 2 ); pNew->pName = Abc_UtilStrsav( "test" ); - int i, pCopy[256] = {0}; + int i, nSave = 0, pCopy[256] = {0}; for ( i = 1; i <= nIns; i++ ) pCopy[i] = Gia_ManAppendCi( pNew ); for ( i = nIns; i < nIns+nNodes; i++ ) { @@ -1668,8 +1672,11 @@ Gia_Man_t * Gia_ManDeriveKSatMapping( Vec_Int_t * vRes, int * pMap, int nIns, in printf( "%sAND( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); else printf( "%sOR( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); - if ( i == nIns+nNodes-1 ) + nSave += (iFan0 == iFan1) || !Gia_KSatValInv(pMap, i, vRes); + if ( i == nIns+nNodes-1 ) { printf( "CO = %d\n", nIns+nNodes-1 ); + printf( "Solution cost = %d\n", 2*(2*nNodes - nSave) ); + } } } Gia_ManAppendCo( pNew, pCopy[nIns+nNodes] ); @@ -1704,6 +1711,13 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) pLits[2] = Abc_Var2Lit( Gia_KSatVarEqu(pMap, n), 0 ); Gia_SatDumpClause( vStr, pLits, 3 ); } + for ( i = 0; i < n; i++ ) + for ( j = i+1; j < n; j++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 0, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, j), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarEqu(pMap, n), 1 ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } // if fanins are equal, inv is used pLits[0] = Abc_Var2Lit( Gia_KSatVarEqu(pMap, n), 1 ); pLits[1] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); @@ -1718,11 +1732,16 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) } for ( n = nIns; n < nIns+nNodes-1; n++ ) { // there is a fanout to the node above - for ( i = n+1; i < nIns+nNodes; i++ ) - for ( f = 0; f < 2; f++ ) { - pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, i, f, n), 1 ); - pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 0 ); - Gia_SatDumpClause( vStr, pLits, 2 ); + for ( i = n+1; i < nIns+nNodes; i++ ) { + for ( f = 0; f < 2; f++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, i, f, n), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 0 ); + Gia_SatDumpClause( vStr, pLits, 2 ); + } + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, i, 0, n), 0 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, i, 1, n), 0 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 2, i), 1 ); + Gia_SatDumpClause( vStr, pLits, 3 ); } // there is at least one fanout, except the last one nLits = 0; @@ -1755,6 +1774,7 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) } // the last one always uses inverter Gia_SatDumpLiteral( vStr, Abc_Var2Lit( Gia_KSatVarInv(pMap, nIns+nNodes-1), 0 ) ); +/* // for each minterm, for each pair of possible fanins, the node's output is determined using and/or and inv (4*N*N*M) for ( m = 0; m < (1 << nIns); m++ ) for ( n = nIns; n < nIns+nNodes; n++ ) @@ -1764,10 +1784,10 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) for ( f = 0; f < 2; f++ ) for ( i = 0; i < n; i++ ) { pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); - pLits[1] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m), !a ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m, 0), !a ); pLits[2] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); pLits[3] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); - pLits[4] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m), a^c ); + pLits[4] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 0), a^c ); Gia_SatDumpClause( vStr, pLits, 5 ); } // large clauses: Fan(0) & Fan(1) & !Mint(m) & !Mint(m) & !And & !Inv -> Val0 @@ -1775,26 +1795,79 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) for ( j = i; j < n; j++ ) { pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 0, i), 1 ); pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, j), 1 ); - pLits[2] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m), a ); - pLits[3] = Abc_Var2Lit( Gia_KSatVarMin(pMap, j, m), a ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m, 0), a ); + pLits[3] = Abc_Var2Lit( Gia_KSatVarMin(pMap, j, m, 0), a ); pLits[4] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); pLits[5] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); - pLits[6] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m), a==c ); + pLits[6] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 0), a==c ); Gia_SatDumpClause( vStr, pLits, 7 ); } } +*/ + // for each minterm, define a fanin variable and use it to get the node's output based on and/or and inv (4*N*N*M) + for ( m = 0; m < (1 << nIns); m++ ) + for ( n = nIns; n < nIns+nNodes; n++ ) { + for ( i = 0; i < n; i++ ) + for ( f = 0; f < 2; f++ ) + for ( c = 0; c < 2; c++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarMin(pMap, i, m, 0), c ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 1+f), !c ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } + for ( c = 0; c < 2; c++ ) + for ( a = 0; a < 2; a++ ) { + // implications: Mint(m,f) & !And & !Inv -> Val1 + for ( f = 0; f < 2; f++ ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 1+f), !a ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); + pLits[3] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 0), a^c ); + Gia_SatDumpClause( vStr, pLits, 4 ); + } + // large clauses: !Mint(m,0) & !Mint(m,1) & !And & !Inv -> Val0 + pLits[0] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 1), a ); + pLits[1] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 2), a ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarAnd(pMap, n), a ); + pLits[3] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), c ); + pLits[4] = Abc_Var2Lit( Gia_KSatVarMin(pMap, n, m, 0), a==c ); + Gia_SatDumpClause( vStr, pLits, 5 ); + } + } // the number of nodes with duplicated fanins and without inv is maximized + if ( nBound && 2*nNodes > nBound ) { + Vec_StrPrintF( vStr, "k %d ", 2*nNodes-nBound ); + nLits = 0; + for ( n = nIns; n < nIns+nNodes; n++ ) { + pLits[nLits++] = Abc_Var2Lit(Gia_KSatVarEqu(pMap, n), 0); + pLits[nLits++] = Abc_Var2Lit(Gia_KSatVarInv(pMap, n), 1); + } + Gia_SatDumpClause( vStr, pLits, nLits ); + } Vec_StrPush( vStr, '\0' ); return vStr; } +word Gia_ManGetTruth( Gia_Man_t * p ) +{ + Gia_Obj_t * pObj; int i, Id; + word pFuncs[256] = {0}, Const[2] = {0, ~(word)0}; + assert( Gia_ManObjNum(p) <= 256 ); + Gia_ManForEachCiId( p, Id, i ) + pFuncs[Id] = s_Truths6[i]; + Gia_ManForEachAnd( p, pObj, i ) + pFuncs[i] = (Const[Gia_ObjFaninC0(pObj)] ^ pFuncs[Gia_ObjFaninId0(pObj, i)]) & (Const[Gia_ObjFaninC1(pObj)] ^ pFuncs[Gia_ObjFaninId1(pObj, i)]); + pObj = Gia_ManCo(p, 0); + return Const[Gia_ObjFaninC0(pObj)] ^ pFuncs[Gia_ObjFaninId0p(p, pObj)]; +} + Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ) { Gia_Man_t * pNew = NULL; char * pFileNameI = (char *)"__temp__.cnf"; char * pFileNameO = (char *)"__temp__.out"; int nVars = 0, * pMap = Gia_KSatMapInit( nIns, nNodes, Truth, &nVars ); - Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound ); + Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound/2 ); if ( !Gia_ManDumpCnf(pFileNameI, vStr, nVars) ) { Vec_StrFree( vStr ); return NULL; @@ -1812,6 +1885,7 @@ Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, in return 0; Vec_IntDrop( vRes, 0 ); pNew = Gia_ManDeriveKSatMapping( vRes, pMap, nIns, nNodes, fVerbose ); + printf( "Verification %s.\n", Truth == Gia_ManGetTruth(pNew) ? "passed" : "failed" ); Vec_IntFree( vRes ); ABC_FREE( pMap ); return pNew; From d55735df2bfa0a0375f22320692319ad20dc0edb Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Mar 2025 11:57:53 -0700 Subject: [PATCH 07/42] Updates to the result reporting. --- src/proof/cec/cecProve.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/proof/cec/cecProve.c b/src/proof/cec/cecProve.c index b6325ea2c..1b5a0fa43 100644 --- a/src/proof/cec/cecProve.c +++ b/src/proof/cec/cecProve.c @@ -317,9 +317,9 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in { printf( "Problem \"%s\" is ", p->pSpec ); if ( RetValue == 0 ) - printf( "SAT (solved by %d).", RetEngine ); + printf( "SATISFIABLE (solved by %d).", RetEngine ); else if ( RetValue == 1 ) - printf( "UNSAT (solved by %d).", RetEngine ); + printf( "UNSATISFIABLE (solved by %d).", RetEngine ); else if ( RetValue == -1 ) printf( "UNDECIDED." ); else assert( 0 ); From aaba1b9a5f43a25946a2d6577ec50e63421dca70 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Mar 2025 20:59:17 -0700 Subject: [PATCH 08/42] Experiments with mapping. --- src/aig/gia/giaSatLut.c | 261 ++++++++++++++++++++++++++++++---------- src/base/abci/abc.c | 40 ++++-- src/map/mio/mio.c | 34 ++++++ 3 files changed, 260 insertions(+), 75 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index 49b5f8b99..7ca3ae4c8 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1234,7 +1234,7 @@ void Gia_ManLutSat( Gia_Man_t * pGia, int LutSize, int nNumber, int nImproves, i SeeAlso [] ***********************************************************************/ -Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimit, int TimeOut, int fVerbose ) +Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ) { extern Vec_Int_t * Exa4_ManParse( char *pFileName ); int fVerboseSolver = 0; @@ -1271,11 +1271,11 @@ Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimi if ( fVerbose ) { if ( vRes ) - printf( "The problem has a solution. " ); + printf( "The problem has a solution. " ), *pStatus = 0; else if ( vRes == NULL && TimeOut == 0 ) - printf( "The problem has no solution. " ); + printf( "The problem has no solution. " ), *pStatus = 1; else if ( vRes == NULL ) - printf( "The problem has no solution or reached a resource limit after %d sec. ", TimeOut ); + printf( "The problem has no solution or reached a resource limit after %d sec. ", TimeOut ), *pStatus = -1; Abc_PrintTime( 1, "SAT solver time", Abc_Clock() - clkTotal ); } return vRes; @@ -1536,10 +1536,41 @@ int Gia_ManDumpCnf( char * pFileName, Vec_Str_t * vStr, int nVars ) fclose( pFile ); return 1; } -int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose ) +int Gia_ManDumpCnf2( Vec_Str_t * vStr, int nVars, int argc, char ** argv, abctime Time, int Status ) { - char * pFileNameI = (char *)"__temp__.cnf"; - char * pFileNameO = (char *)"__temp__.out"; + Vec_Str_t * vFileName = Vec_StrAlloc( 100 ); int c; + Vec_StrPrintF( vFileName, "%s", argv[0] ); + for ( c = 1; c < argc; c++ ) + Vec_StrPrintF( vFileName, "_%s", argv[c] + (argv[c][0] == '-') ); + Vec_StrPrintF( vFileName, ".cnf" ); + Vec_StrPush( vFileName, '\0' ); + FILE * pFile = fopen( Vec_StrArray(vFileName), "wb" ); + if ( pFile == NULL ) { printf( "Cannot open output file \"%s\".\n", Vec_StrArray(vFileName) ); Vec_StrFree(vFileName); return 0; } + Vec_StrFree(vFileName); + fprintf( pFile, "c ABC command line: \"" ); + fprintf( pFile, "%s", argv[0] ); + for ( c = 1; c < argc; c++ ) + fprintf( pFile, " %s", argv[c] ); + fprintf( pFile, "\" " ); + if ( Status == 1 ) + fprintf( pFile, "UNSAT after " ); + if ( Status == 0 ) + fprintf( pFile, "SAT after " ); + if ( Status == -1 ) + fprintf( pFile, "UNDECIDED after " ); + fprintf( pFile, "%.2f sec by CaDiCal on ", 1.0*((double)(Time))/((double)CLOCKS_PER_SEC) ); + fprintf( pFile, "%s\n", Gia_TimeStamp() ); + fprintf( pFile, "p knf %d %d\n%s\n", nVars, Vec_StrCountEntry(vStr, '\n'), Vec_StrArray(vStr) ); + fclose( pFile ); + return 1; +} +int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) +{ + abctime clkStart = Abc_Clock(); + srand(time(NULL)); + int Status, Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFFF; + char pFileNameI[32]; sprintf( pFileNameI, "_%06x_.cnf", Rand ); + char pFileNameO[32]; sprintf( pFileNameO, "_%06x_.out", Rand ); if ( nBound == 0 ) nBound = 5 * Gia_ManAndNum(p); Vec_Str_t * vStr = Gia_ManSimpleCnf( p, nBound/2 ); @@ -1551,12 +1582,11 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, if ( fVerbose ) printf( "SAT variables = %d. SAT clauses = %d. Cardinality bound = %d. Conflict limit = %d. Timeout = %d.\n", nVars, Vec_StrCountEntry(vStr, '\n'), nBound, nBTLimit, nTimeout ); - //char pFileName[100]; sprintf( pFileName, "temp%02d.cnf", nBound/2 ); - //Gia_ManDumpCnf( pFileName, vStr, nVars ); - Vec_StrFree( vStr ); - Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1 ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1, &Status ); unlink( pFileNameI ); //unlink( pFileNameO ); + if ( fKeepFile ) Gia_ManDumpCnf2( vStr, nVars, argc, argv, Abc_Clock() - clkStart, Status ); + Vec_StrFree( vStr ); if ( vRes == NULL ) return 0; Vec_IntFreeP( &p->vCellMapping ); @@ -1565,6 +1595,7 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, if ( fVerbose ) Gia_ManSimplePrintMapping( vRes, Gia_ManCiNum(p) ); p->vCellMapping = Gia_ManDeriveSimpleMapping( p, vRes ); Vec_IntFree( vRes ); + Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); return 1; } @@ -1647,43 +1678,7 @@ int Gia_KSatFindFan( int * pMap, int i, int f, Vec_Int_t * vRes ) return -1; } -Gia_Man_t * Gia_ManDeriveKSatMapping( Vec_Int_t * vRes, int * pMap, int nIns, int nNodes, int fVerbose ) -{ - Gia_Man_t * pNew = Gia_ManStart( nIns + nNodes + 2 ); - pNew->pName = Abc_UtilStrsav( "test" ); - int i, nSave = 0, pCopy[256] = {0}; - for ( i = 1; i <= nIns; i++ ) - pCopy[i] = Gia_ManAppendCi( pNew ); - for ( i = nIns; i < nIns+nNodes; i++ ) { - int iFan0 = Gia_KSatFindFan( pMap, i, 0, vRes ); - int iFan1 = Gia_KSatFindFan( pMap, i, 1, vRes ); - if ( iFan0 == iFan1 ) - pCopy[i+1] = pCopy[iFan0+1]; - else if ( Gia_KSatValAnd(pMap, i, vRes) ) - pCopy[i+1] = Gia_ManAppendAnd( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); - else - pCopy[i+1] = Gia_ManAppendOr( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); - pCopy[i+1] = Abc_LitNotCond( pCopy[i+1], Gia_KSatValInv(pMap, i, vRes) ); - if ( fVerbose ) { - printf( "%d = ", i ); - if ( iFan0 == iFan1 ) - printf( "INV( %d )\n", iFan0 ); - else if ( Gia_KSatValAnd(pMap, i, vRes) ) - printf( "%sAND( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); - else - printf( "%sOR( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); - nSave += (iFan0 == iFan1) || !Gia_KSatValInv(pMap, i, vRes); - if ( i == nIns+nNodes-1 ) { - printf( "CO = %d\n", nIns+nNodes-1 ); - printf( "Solution cost = %d\n", 2*(2*nNodes - nSave) ); - } - } - } - Gia_ManAppendCo( pNew, pCopy[nIns+nNodes] ); - return pNew; -} - -Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) +Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound, int fMultiLevel ) { Vec_Str_t * vStr = Vec_StrAlloc( 10000 ); int i, j, m, n, f, c, a, nLits = 0, pLits[256] = {0}; @@ -1764,12 +1759,14 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) pLits[1] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); Gia_SatDumpClause( vStr, pLits, 2 ); // if inv is not used, its fanins' invs are used - pLits[0] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); - for ( i = nIns; i < n; i++ ) - for ( f = 0; f < 2; f++ ) { - pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); - pLits[2] = Abc_Var2Lit( Gia_KSatVarInv(pMap, i), 0 ); - Gia_SatDumpClause( vStr, pLits, 3 ); + if ( !fMultiLevel ) { + pLits[0] = Abc_Var2Lit( Gia_KSatVarInv(pMap, n), 0 ); + for ( i = nIns; i < n; i++ ) + for ( f = 0; f < 2; f++ ) { + pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + pLits[2] = Abc_Var2Lit( Gia_KSatVarInv(pMap, i), 0 ); + Gia_SatDumpClause( vStr, pLits, 3 ); + } } } // the last one always uses inverter @@ -1848,6 +1845,141 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound ) return vStr; } + +typedef enum { + GIA_GATE2_ZERO, // 0: + GIA_GATE2_ONE, // 1: + GIA_GATE2_BUF, // 2: + GIA_GATE2_INV, // 3: + GIA_GATE2_NAN2, // 4: + GIA_GATE2_NOR2, // 5: + GIA_GATE2_AOI21, // 6: + GIA_GATE2_NAN3, // 7: + GIA_GATE2_NOR3, // 8: + GIA_GATE2_OAI21, // 9: + GIA_GATE2_NOR4, // 10: + GIA_GATE2_AOI211, // 11: + GIA_GATE2_AOI22, // 12: + GIA_GATE2_NAN4, // 13: + GIA_GATE2_OAI211, // 14: + GIA_GATE2_OAI22, // 15: + GIA_GATE2_VOID // 16: unused value +} Gia_ManGate2_t; + +Vec_Int_t * Gia_ManDeriveKSatMappingArray( Gia_Man_t * p, Vec_Int_t * vRes ) +{ + Vec_Int_t * vMapping = Vec_IntStart( 2*Gia_ManObjNum(p) ); + int i, Id; Gia_Obj_t * pObj; + Gia_ManForEachCiId( p, Id, i ) + if ( Vec_IntEntry(vRes, Id) ) + Vec_IntWriteEntry( vMapping, Abc_Var2Lit(Id, 1), -1 ); + Gia_ManForEachAnd( p, pObj, i ) { + assert( Vec_IntEntry(vRes, i) > 0 ); + if ( (Vec_IntEntry(vRes, i) & 2) == 0 ) { + assert( (Vec_IntEntry(vRes, i) & 1) == 0 ); + continue; + } + Gia_Obj_t * pFans[2] = { Gia_ObjFanin0(pObj), Gia_ObjFanin1(pObj) }; + int fComp = ((Vec_IntEntry(vRes, i) >> 2) & 1) != 0; + int fFan0 = ((Vec_IntEntry(vRes, Gia_ObjFaninId0(pObj, i)) >> 1) & 1) == 0 && Gia_ObjIsAnd(pFans[0]); + int fFan1 = ((Vec_IntEntry(vRes, Gia_ObjFaninId1(pObj, i)) >> 1) & 1) == 0 && Gia_ObjIsAnd(pFans[1]); + if ( Vec_IntEntry(vRes, i) & 1 ) + Vec_IntWriteEntry( vMapping, Abc_Var2Lit(i, !fComp), -1 ); + Vec_IntWriteEntry( vMapping, Abc_Var2Lit(i, fComp), Vec_IntSize(vMapping) ); + if ( fFan0 && fFan1 ) { + Vec_IntPush( vMapping, 4 ); + if ( !Gia_ObjFaninC0(pObj) && Gia_ObjFaninC1(pObj) ) { + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC0(pFans[1]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC1(pFans[1]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC0(pFans[0]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC1(pFans[0]))) ); + } + else { + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC0(pFans[0]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC1(pFans[0]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC0(pFans[1]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC1(pFans[1]))) ); + } + if ( Gia_ObjFaninC0(pObj) && Gia_ObjFaninC1(pObj) ) + Vec_IntPush( vMapping, fComp ? GIA_GATE2_OAI22 : GIA_GATE2_AOI22 ); + else if ( !Gia_ObjFaninC0(pObj) && !Gia_ObjFaninC1(pObj) ) + Vec_IntPush( vMapping, fComp ? GIA_GATE2_NAN4 : GIA_GATE2_NOR4 ); + else + Vec_IntPush( vMapping, fComp ? GIA_GATE2_OAI211 : GIA_GATE2_AOI211 ); + } else if ( fFan0 ) { + Vec_IntPush( vMapping, 3 ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC0(pFans[0]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[0]), !(fComp ^ Gia_ObjFaninC0(pObj) ^ Gia_ObjFaninC1(pFans[0]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pObj), !(fComp ^ Gia_ObjFaninC1(pObj))) ); + if ( Gia_ObjFaninC0(pObj) ) + Vec_IntPush( vMapping, fComp ? GIA_GATE2_OAI21 : GIA_GATE2_AOI21 ); + else + Vec_IntPush( vMapping, fComp ? GIA_GATE2_NAN3 : GIA_GATE2_NOR3 ); + } else if ( fFan1 ) { + Vec_IntPush( vMapping, 3 ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC0(pFans[1]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pFans[1]), !(fComp ^ Gia_ObjFaninC1(pObj) ^ Gia_ObjFaninC1(pFans[1]))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pObj), !(fComp ^ Gia_ObjFaninC0(pObj))) ); + if ( Gia_ObjFaninC1(pObj) ) + Vec_IntPush( vMapping, fComp ? GIA_GATE2_OAI21 : GIA_GATE2_AOI21 ); + else + Vec_IntPush( vMapping, fComp ? GIA_GATE2_NAN3 : GIA_GATE2_NOR3 ); + } else { + Vec_IntPush( vMapping, 2 ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId0p(p, pObj), !(fComp ^ Gia_ObjFaninC0(pObj))) ); + Vec_IntPush( vMapping, Abc_Var2Lit(Gia_ObjFaninId1p(p, pObj), !(fComp ^ Gia_ObjFaninC1(pObj))) ); + Vec_IntPush( vMapping, fComp ? GIA_GATE2_NAN2 : GIA_GATE2_NOR2 ); + } + } + return vMapping; +} + +Gia_Man_t * Gia_ManDeriveKSatMapping( Vec_Int_t * vRes, int * pMap, int nIns, int nNodes, int fVerbose ) +{ + Vec_Int_t * vGuide = Vec_IntStart( 1000 ); + Gia_Man_t * pNew = Gia_ManStart( nIns + nNodes + 2 ); + pNew->pName = Abc_UtilStrsav( "test" ); + int i, nSave = 0, pCopy[256] = {0}; + for ( i = 1; i <= nIns; i++ ) + pCopy[i] = Gia_ManAppendCi( pNew ); + for ( i = nIns; i < nIns+nNodes; i++ ) { + int iFan0 = Gia_KSatFindFan( pMap, i, 0, vRes ); + int iFan1 = Gia_KSatFindFan( pMap, i, 1, vRes ); + if ( iFan0 == iFan1 ) + pCopy[i+1] = pCopy[iFan0+1]; + else if ( Gia_KSatValAnd(pMap, i, vRes) ) + pCopy[i+1] = Gia_ManAppendAnd( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); + else + pCopy[i+1] = Gia_ManAppendOr( pNew, pCopy[iFan0+1], pCopy[iFan1+1] ); + pCopy[i+1] = Abc_LitNotCond( pCopy[i+1], Gia_KSatValInv(pMap, i, vRes) ); + if ( iFan0 == iFan1 ) + *Vec_IntEntryP(vGuide, Abc_Lit2Var(pCopy[i+1])) ^= 1; + else if ( Gia_KSatValAnd(pMap, i, vRes) ) + *Vec_IntEntryP(vGuide, Abc_Lit2Var(pCopy[i+1])) ^= 4 | (2*Gia_KSatValInv(pMap, i, vRes)); + else + *Vec_IntEntryP(vGuide, Abc_Lit2Var(pCopy[i+1])) ^= 8 | (2*Gia_KSatValInv(pMap, i, vRes)); + if ( fVerbose ) { + if ( i == nIns+nNodes-1 ) + printf( " F = " ); + else + printf( "%2d = ", i ); + if ( iFan0 == iFan1 ) + printf( "INV( %d )\n", iFan0 ); + else if ( Gia_KSatValAnd(pMap, i, vRes) ) + printf( "%sAND( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); + else + printf( "%sOR( %d, %d )\n", Gia_KSatValInv(pMap, i, vRes) ? "N":"", iFan0, iFan1 ); + nSave += (iFan0 == iFan1) || !Gia_KSatValInv(pMap, i, vRes); + if ( i == nIns+nNodes-1 ) + printf( "Solution cost = %d\n", 2*(2*nNodes - nSave) ); + } + } + Gia_ManAppendCo( pNew, pCopy[nIns+nNodes] ); + //pNew->vCellMapping = Gia_ManDeriveKSatMappingArray( pNew, vGuide ); + Vec_IntFree( vGuide ); + return pNew; +} + word Gia_ManGetTruth( Gia_Man_t * p ) { Gia_Obj_t * pObj; int i, Id; @@ -1861,13 +1993,16 @@ word Gia_ManGetTruth( Gia_Man_t * p ) return Const[Gia_ObjFaninC0(pObj)] ^ pFuncs[Gia_ObjFaninId0p(p, pObj)]; } -Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ) +Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) { + abctime clkStart = Abc_Clock(); Gia_Man_t * pNew = NULL; - char * pFileNameI = (char *)"__temp__.cnf"; - char * pFileNameO = (char *)"__temp__.out"; + srand(time(NULL)); + int Status, Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFFF; + char pFileNameI[32]; sprintf( pFileNameI, "_%06x_.cnf", Rand ); + char pFileNameO[32]; sprintf( pFileNameO, "_%06x_.out", Rand ); int nVars = 0, * pMap = Gia_KSatMapInit( nIns, nNodes, Truth, &nVars ); - Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound/2 ); + Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound/2, fMultiLevel ); if ( !Gia_ManDumpCnf(pFileNameI, vStr, nVars) ) { Vec_StrFree( vStr ); return NULL; @@ -1875,17 +2010,17 @@ Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, in if ( fVerbose ) printf( "Vars = %d. Nodes = %d. Cardinality bound = %d. SAT vars = %d. SAT clauses = %d. Conflict limit = %d. Timeout = %d.\n", nIns, nNodes, nBound, nVars, Vec_StrCountEntry(vStr, '\n'), nBTLimit, nTimeout ); - //char pFileName[100]; sprintf( pFileName, "temp%02d.cnf", nBound/2 ); - //Gia_ManDumpCnf( pFileName, vStr, nVars ); - Vec_StrFree( vStr ); - Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1 ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1, &Status ); unlink( pFileNameI ); //unlink( pFileNameO ); + if ( fKeepFile ) Gia_ManDumpCnf2( vStr, nVars, argc, argv, Abc_Clock() - clkStart, Status ); + Vec_StrFree( vStr ); if ( vRes == NULL ) return 0; Vec_IntDrop( vRes, 0 ); pNew = Gia_ManDeriveKSatMapping( vRes, pMap, nIns, nNodes, fVerbose ); - printf( "Verification %s.\n", Truth == Gia_ManGetTruth(pNew) ? "passed" : "failed" ); + printf( "Verification %s. ", Truth == Gia_ManGetTruth(pNew) ? "passed" : "failed" ); + Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); Vec_IntFree( vRes ); ABC_FREE( pMap ); return pNew; diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 663bdac14..630f66aa2 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -44385,10 +44385,10 @@ usage: int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Mio_IntallSimpleLibrary(); - extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose ); - int c, nBTLimit = 0, nBound = 0, nTimeout = 0, fVerbose = 0; + extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); + int c, nBTLimit = 0, nBound = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "BCTvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "BCTfvh" ) ) != EOF ) { switch ( c ) { @@ -44429,6 +44429,9 @@ int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) nTimeout = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'f': + fKeepFile ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -44443,16 +44446,17 @@ int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } Mio_IntallSimpleLibrary(); - if ( !Gia_ManSimpleMapping( pAbc->pGia, nBound, nBTLimit, nTimeout, fVerbose ) ) + if ( !Gia_ManSimpleMapping( pAbc->pGia, nBound, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ) ) printf( "Simple mapping has failed.\n" ); return 0; usage: - Abc_Print( -2, "usage: &simap [-BCT num] [-vh]\n" ); + Abc_Print( -2, "usage: &simap [-BCT num] [-fvh]\n" ); Abc_Print( -2, "\t performs simple mapping of the AIG\n" ); Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); + Abc_Print( -2, "\t-f : toggles keeping the intermediate CNF file [default = %s]\n", fKeepFile? "yes": "no" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : prints the command usage\n"); return 1; @@ -44471,11 +44475,12 @@ usage: ***********************************************************************/ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int nBTLimit, int nTimeout, int fVerbose ); + extern void Mio_IntallSimpleLibrary2(); + extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); Gia_Man_t * pTemp = NULL; char * pTruth = NULL; word Truth = 0; - int c, nVars = 0, nNodes = 0, nVars2, nBTLimit = 0, nBound = 0, nTimeout = 0, fVerbose = 0; + int c, nVars = 0, nNodes = 0, nVars2, nBTLimit = 0, nBound = 0, fMultiLevel = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NBCTvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NBCTmfvh" ) ) != EOF ) { switch ( c ) { @@ -44530,6 +44535,12 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) nTimeout = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'm': + fMultiLevel ^= 1; + break; + case 'f': + fKeepFile ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -44559,20 +44570,25 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Print( -1, "The number of nodes should be given on the command line (-N ).\n" ); return 1; - } + } nVars2 = Abc_TtReadHex( &Truth, pTruth ); assert( nVars2 == nVars ); - pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, nBTLimit, nTimeout, fVerbose ); - if ( pTemp ) Abc_FrameUpdateGia( pAbc, pTemp ); + pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, fMultiLevel, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ); + if ( pTemp ) { + //Mio_IntallSimpleLibrary2(); + Abc_FrameUpdateGia( pAbc, pTemp ); + } return 0; usage: - Abc_Print( -2, "usage: &exmap [-NBCT num] [-vh] \n" ); + Abc_Print( -2, "usage: &exmap [-NBCT num] [-mfvh] \n" ); Abc_Print( -2, "\t performs simple mapping of the truth table\n" ); Abc_Print( -2, "\t-N num : the number of nodes [default = %d]\n", nNodes ); Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); + Abc_Print( -2, "\t-m : toggles using multi-level primitives [default = %s]\n", fMultiLevel? "yes": "no" ); + Abc_Print( -2, "\t-f : toggles keeping the intermediate CNF file [default = %s]\n", fKeepFile? "yes": "no" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : prints the command usage\n"); return 1; diff --git a/src/map/mio/mio.c b/src/map/mio/mio.c index a2c956356..8c5f38953 100644 --- a/src/map/mio/mio.c +++ b/src/map/mio/mio.c @@ -90,6 +90,27 @@ static char * pSimpleGenlib[] = { NULL }; +// internal version of genlib library +static char * pSimpleGenlib2[] = { + "GATE zero 0 O=CONST0;\n", + "GATE one 0 O=CONST1;\n", + "GATE buf 4 O=a; PIN * NONINV 1 999 1.0 0.0 1.0 0.0\n", + "GATE inv 2 O=!a; PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nand2 4 O=!(a*b); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nand3 6 O=!(a*b*c); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nand4 8 O=!(a*b*c*d); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nor2 4 O=!(a+b); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nor3 6 O=!(a+b+c); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE nor4 6 O=!(a+b+c+d); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE aoi21 6 O=!(a*b+c); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE oai21 6 O=!((a+b)*c); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE aoi22 8 O=!(a*b+c*d); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE oai22 8 O=!((a+b)*(c+d)); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE aoi211 8 O=!(a*b+c+d); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + "GATE oai211 8 O=!((a+b)*c*d); PIN * INV 1 999 1.0 0.0 1.0 0.0\n", + NULL +}; + //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -118,6 +139,19 @@ void Mio_IntallSimpleLibrary() Mio_UpdateGenlib( pLib ); Vec_StrFree( vLibStr ); } +void Mio_IntallSimpleLibrary2() +{ + extern Mio_Library_t * Mio_LibraryReadBuffer( char * pBuffer, int fExtendedFormat, st__table * tExcludeGate, int nFaninLimit, int fVerbose ); + Mio_Library_t * pLib; int i; + Vec_Str_t * vLibStr = Vec_StrAlloc( 1000 ); + for ( i = 0; pSimpleGenlib2[i]; i++ ) + Vec_StrAppend( vLibStr, pSimpleGenlib2[i] ); + Vec_StrPush( vLibStr, '\0' ); + pLib = Mio_LibraryReadBuffer( Vec_StrArray(vLibStr), 0, NULL, 0, 0 ); + Mio_LibrarySetName( pLib, Abc_UtilStrsav("simple2.genlib") ); + Mio_UpdateGenlib( pLib ); + Vec_StrFree( vLibStr ); +} /**Function************************************************************* From 839f3e18ddbc46d694b4a1832abda2999c0c1aff Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 14 Mar 2025 20:24:08 -0700 Subject: [PATCH 09/42] Experiments with mapping. --- src/aig/gia/giaSatLut.c | 23 +++++++++++++++-------- src/base/abci/abc.c | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index 7ca3ae4c8..716566cae 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1539,7 +1539,7 @@ int Gia_ManDumpCnf( char * pFileName, Vec_Str_t * vStr, int nVars ) int Gia_ManDumpCnf2( Vec_Str_t * vStr, int nVars, int argc, char ** argv, abctime Time, int Status ) { Vec_Str_t * vFileName = Vec_StrAlloc( 100 ); int c; - Vec_StrPrintF( vFileName, "%s", argv[0] ); + Vec_StrPrintF( vFileName, "%s", argv[0] + (argv[0][0] == '&') ); for ( c = 1; c < argc; c++ ) Vec_StrPrintF( vFileName, "_%s", argv[c] + (argv[c][0] == '-') ); Vec_StrPrintF( vFileName, ".cnf" ); @@ -1547,19 +1547,19 @@ int Gia_ManDumpCnf2( Vec_Str_t * vStr, int nVars, int argc, char ** argv, abctim FILE * pFile = fopen( Vec_StrArray(vFileName), "wb" ); if ( pFile == NULL ) { printf( "Cannot open output file \"%s\".\n", Vec_StrArray(vFileName) ); Vec_StrFree(vFileName); return 0; } Vec_StrFree(vFileName); - fprintf( pFile, "c ABC command line: \"" ); + fprintf( pFile, "c This file was generated by ABC command: \"" ); fprintf( pFile, "%s", argv[0] ); for ( c = 1; c < argc; c++ ) fprintf( pFile, " %s", argv[c] ); - fprintf( pFile, "\" " ); + fprintf( pFile, "\" on %s\n", Gia_TimeStamp() ); + fprintf( pFile, "c Cardinality CDCL (https://github.com/jreeves3/Cardinality-CDCL) found it to be " ); if ( Status == 1 ) - fprintf( pFile, "UNSAT after " ); + fprintf( pFile, "UNSAT" ); if ( Status == 0 ) - fprintf( pFile, "SAT after " ); + fprintf( pFile, "SAT" ); if ( Status == -1 ) - fprintf( pFile, "UNDECIDED after " ); - fprintf( pFile, "%.2f sec by CaDiCal on ", 1.0*((double)(Time))/((double)CLOCKS_PER_SEC) ); - fprintf( pFile, "%s\n", Gia_TimeStamp() ); + fprintf( pFile, "UNDECIDED" ); + fprintf( pFile, " in %.2f sec\n", 1.0*((double)(Time))/((double)CLOCKS_PER_SEC) ); fprintf( pFile, "p knf %d %d\n%s\n", nVars, Vec_StrCountEntry(vStr, '\n'), Vec_StrArray(vStr) ); fclose( pFile ); return 1; @@ -1687,16 +1687,23 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound, int fM // fanins are connected once for ( n = nIns; n < nIns+nNodes; n++ ) for ( f = 0; f < 2; f++ ) { + nLits = 0; for ( i = 0; i < n; i++ ) pLits[nLits++] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 0 ); Gia_SatDumpClause( vStr, pLits, nLits ); +/* for ( i = 0; i < n; i++ ) for ( j = 0; j < i; j++ ) { pLits[0] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); pLits[1] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, j), 1 ); Gia_SatDumpClause( vStr, pLits, 2 ); } +*/ + Vec_StrPrintF( vStr, "k %d ", n-1 ); + for ( i = 0; i < n; i++ ) + pLits[i] = Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, i), 1 ); + Gia_SatDumpClause( vStr, pLits, n ); } for ( n = nIns; n < nIns+nNodes; n++ ) { // fanins are equal diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 630f66aa2..a4078d54c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -55359,7 +55359,7 @@ usage: Abc_Print( -2, "\t generates Boolean relation for the given logic window\n" ); Abc_Print( -2, "\t-I list : comma-separated list of window inputs [default = undefined]\n" ); Abc_Print( -2, "\t-O list : comma-separated list of window outputs [default = undefined]\n" ); - Abc_Print( -2, "\t-v : toggles printing verbose information [default = %d]\n", fVerbose ? "yes": "no" ); + 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 : the output file name (PLA format extended to represented Boolean relations)\n"); return 1; From 0ebc9dbbaecc1c1c1471b43774088d0fb357d539 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 16 Mar 2025 09:39:04 -0700 Subject: [PATCH 10/42] Experiments with exact synthesis. --- src/aig/gia/giaSimBase.c | 4 +-- src/base/abci/abc.c | 10 +++++-- src/sat/bmc/bmc.h | 1 + src/sat/bmc/bmcMaj.c | 60 ++++++++++++++++++++++++++-------------- 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/aig/gia/giaSimBase.c b/src/aig/gia/giaSimBase.c index 87614c490..e5cf77dcb 100644 --- a/src/aig/gia/giaSimBase.c +++ b/src/aig/gia/giaSimBase.c @@ -3199,7 +3199,7 @@ Vec_Int_t * Gia_ManRelDeriveSimple( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t void Gia_ManRelSolve( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t * vIns, Vec_Int_t * vOuts, Vec_Int_t * vRel, Vec_Int_t * vDivs ) { - extern Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose ); + extern Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard ); int i, m, iObj, Entry, iMint = 0, nMints = Vec_IntSize(vRel) - Vec_IntCountEntry(vRel, -1); Vec_Wrd_t * vSimsIn = Vec_WrdStart( nMints ); @@ -3232,7 +3232,7 @@ void Gia_ManRelSolve( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t * vIns, Vec_In } assert( iMint == nMints ); printf( "Created %d minterms.\n", iMint ); - Exa4_ManGenTest( vSimsIn, vSimsOut, Vec_IntSize(vIns), Vec_IntSize(vDivs), Vec_IntSize(vOuts), 10, 0, 0, 0, 0, 0, 1 ); + Exa4_ManGenTest( vSimsIn, vSimsOut, Vec_IntSize(vIns), Vec_IntSize(vDivs), Vec_IntSize(vOuts), 10, 0, 0, 0, 0, 0, 1, 0 ); Vec_WrdFree( vSimsIn ); Vec_WrdFree( vSimsOut ); } diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index a4078d54c..1c2e39501 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10061,7 +10061,7 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "INTGabdconugklvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "INTGabdconugklmvh" ) ) != EOF ) { switch ( c ) { @@ -10139,6 +10139,9 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'l': fKissat2 ^= 1; break; + case 'm': + pPars->fCard ^= 1; + break; case 'v': pPars->fVerbose ^= 1; break; @@ -10179,7 +10182,7 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) } if ( fUseNands ) Exa_ManExactSynthesis7( pPars, GateSize ); - else if ( fKissat ) + else if ( fKissat || pPars->fCard ) Exa_ManExactSynthesis4( pPars ); else if ( fKissat2 ) Exa_ManExactSynthesis5( pPars ); @@ -10190,7 +10193,7 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: twoexact [-INTG ] [-abdconugklvh] \n" ); + Abc_Print( -2, "usage: twoexact [-INTG ] [-abdconugklmvh] \n" ); Abc_Print( -2, "\t exact synthesis of multi-input function using two-input gates\n" ); Abc_Print( -2, "\t-I : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-N : the number of two-input nodes [default = %d]\n", pPars->nNodes ); @@ -10206,6 +10209,7 @@ usage: Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", pPars->fGlucose ? "yes" : "no" ); Abc_Print( -2, "\t-k : toggle using Kissat by Armin Biere [default = %s]\n", fKissat ? "yes" : "no" ); Abc_Print( -2, "\t-l : toggle using Kissat by Armin Biere [default = %s]\n", fKissat2 ? "yes" : "no" ); + Abc_Print( -2, "\t-m : toggle using CaDiCaL by Armin Biere [default = %s]\n", pPars->fCard ? "yes" : "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", pPars->fVerbose ? "yes" : "no" ); Abc_Print( -2, "\t-h : print the command usage\n" ); Abc_Print( -2, "\t : truth table in hex notation\n" ); diff --git a/src/sat/bmc/bmc.h b/src/sat/bmc/bmc.h index 92fbb7422..320a85886 100644 --- a/src/sat/bmc/bmc.h +++ b/src/sat/bmc/bmc.h @@ -57,6 +57,7 @@ struct Bmc_EsPar_t_ int fDynConstr; int fDumpCnf; int fGlucose; + int fCard; int fOrderNodes; int fEnumSols; int fFewerVars; diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 68601338e..7cd138c5f 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1941,7 +1941,7 @@ static inline int Exa4_ManAddClause4( Exa4_Man_t * p, int Lit0, int Lit1, int Li int pLits[4] = { Lit0, Lit1, Lit2, Lit3 }; return Exa4_ManAddClause( p, pLits, 4 ); } -int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans ) +int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard ) { int pLits[2*MAJ_NOBJS], i, j, k, n, m, nLits; for ( i = p->nDivs; i < p->nDivs + p->nNodes; i++ ) @@ -1955,9 +1955,17 @@ int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][k][j], 0 ); assert( nLits > 0 ); Exa4_ManAddClause( p, pLits, nLits ); - for ( n = 0; n < nLits; n++ ) - for ( m = n+1; m < nLits; m++ ) - Exa4_ManAddClause4( p, Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), 0, 0 ); + if ( !fCard ) { + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + Exa4_ManAddClause4( p, Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), 0, 0 ); + } + else { + fprintf( p->pFile, "k %d ", nLits-1 ); + for ( n = 0; n < nLits; n++ ) + pLits[n] = Abc_LitNot(pLits[n]); + Exa4_ManAddClause( p, pLits, nLits ); + } if ( k == 1 ) break; for ( j = 0; j < p->nObjs; j++ ) if ( p->VarMarks[i][0][j] ) @@ -2096,17 +2104,17 @@ void Exa4_ManGenMint( Exa4_Man_t * p, int iMint, int fOnlyAnd, int fFancy ) Exa4_ManAddClause4( p, Abc_Var2Lit(p->VarMarks[i][0][j], 1), Abc_LitNotCond(VarVals[j], n), Abc_LitNotCond(VarVals[i], !n), 0); } } -void Exa4_ManGenCnf( Exa4_Man_t * p, char * pFileName, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans ) +void Exa4_ManGenCnf( Exa4_Man_t * p, char * pFileName, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard ) { int m; assert( p->pFile == NULL ); p->pFile = fopen( pFileName, "wb" ); fputs( "p cnf \n", p->pFile ); - Exa4_ManGenStart( p, fOnlyAnd, fFancy, fOrderNodes, fUniqFans ); + Exa4_ManGenStart( p, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard ); for ( m = 1; m < Vec_WrdSize(p->vSimsIn); m++ ) Exa4_ManGenMint( p, m, fOnlyAnd, fFancy ); rewind( p->pFile ); - fprintf( p->pFile, "p cnf %d %d", p->nCnfVars, p->nCnfClauses ); + fprintf( p->pFile, "p %cnf %d %d", fCard ? 'k' : 'c', p->nCnfVars, p->nCnfClauses ); fclose( p->pFile ); } @@ -2130,6 +2138,8 @@ static inline int Exa4_ManFindFanin( Exa4_Man_t * p, Vec_Int_t * vValues, int i, iVar = j; Count++; } + if ( Count != 1 ) + printf( "Fanin count is %d instead of %d.\n", Count, 1 ); assert( Count == 1 ); return iVar; } @@ -2268,21 +2278,27 @@ Mini_Aig_t * Exa4_ManMiniAig( Exa4_Man_t * p, Vec_Int_t * vValues, int fFancy ) SeeAlso [] ***********************************************************************/ -Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose ) +Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard ) { + extern Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ); Mini_Aig_t * pMini = NULL; abctime clkTotal = Abc_Clock(); Vec_Int_t * vValues = NULL; - char * pFileNameIn = "_temp_.cnf"; - char * pFileNameOut = "_temp_out.cnf"; + srand(time(NULL)); + int Status = 0, Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFF; + char pFileNameIn[32]; sprintf( pFileNameIn, "_%05x_.cnf", Rand ); + char pFileNameOut[32]; sprintf( pFileNameOut, "_%05x_.out", Rand ); Exa4_Man_t * p = Exa4_ManAlloc( vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, fVerbose ); Exa_ManIsNormalized( vSimsIn, vSimsOut ); - Exa4_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans ); + Exa4_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard ); if ( fVerbose ) printf( "Timeout = %d. OnlyAnd = %d. Fancy = %d. OrderNodes = %d. UniqueFans = %d. Verbose = %d.\n", TimeOut, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fVerbose ); if ( fVerbose ) printf( "CNF with %d variables and %d clauses was dumped into file \"%s\".\n", p->nCnfVars, p->nCnfClauses, pFileNameIn ); - vValues = Exa4_ManSolve( pFileNameIn, pFileNameOut, TimeOut, fVerbose ); + if ( fCard ) + vValues = Gia_RunKadical( pFileNameIn, pFileNameOut, 0, TimeOut, fVerbose, &Status ); + else + vValues = Exa4_ManSolve( pFileNameIn, pFileNameOut, TimeOut, fVerbose ); if ( vValues ) pMini = Exa4_ManMiniAig( p, vValues, fFancy ); //if ( vValues ) Exa4_ManPrintSolution( p, vValues, fFancy ); if ( vValues ) Exa_ManMiniPrint( pMini, p->nIns ); @@ -2310,7 +2326,7 @@ void Exa_ManExactSynthesis4_( Bmc_EsPar_t * pPars ) if ( (m >> i) & 1 ) Abc_TtSetBit( Vec_WrdEntryP(vSimsIn, m), 1+i ); } - pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, 3, 4, 2, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose ); + pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, 3, 4, 2, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, 0 ); if ( pMini ) Mini_AigStop( pMini ); Vec_WrdFree( vSimsIn ); Vec_WrdFree( vSimsOut ); @@ -2332,7 +2348,7 @@ void Exa_ManExactSynthesis4( Bmc_EsPar_t * pPars ) Abc_TtSetBit( Vec_WrdEntryP(vSimsIn, m), 1+i ); } assert( Vec_WrdSize(vSimsIn) == (1 << pPars->nVars) ); - pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, pPars->nVars, 1+pPars->nVars, 1, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose ); + pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, pPars->nVars, 1+pPars->nVars, 1, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, pPars->fCard ); if ( pMini ) Mini_AigStop( pMini ); if ( fCompl ) printf( "The resulting circuit, if computed, will be complemented.\n" ); Vec_WrdFree( vSimsIn ); @@ -2797,8 +2813,10 @@ Mini_Aig_t * Exa5_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn abctime clkTotal = Abc_Clock(); Mini_Aig_t * pMini = NULL; Vec_Int_t * vValues = NULL; - char * pFileNameIn = "_temp_.cnf"; - char * pFileNameOut = "_temp_out.cnf"; + srand(time(NULL)); + int Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFF; + char pFileNameIn[32]; sprintf( pFileNameIn, "_%05x_.cnf", Rand ); + char pFileNameOut[32]; sprintf( pFileNameOut, "_%05x_.out", Rand ); Exa5_Man_t * p = Exa5_ManAlloc( vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, fVerbose ); Exa_ManIsNormalized( vSimsIn, vSimsOut ); Exa5_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans ); @@ -3717,8 +3735,9 @@ Mini_Aig_t * Exa6_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn Mini_Aig_t * pMini = NULL; abctime clkTotal = Abc_Clock(); Vec_Int_t * vValues = NULL; - char * pFileNameIn = "_temp_.cnf"; - char * pFileNameOut = "_temp_out.cnf"; + int Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFF; + char pFileNameIn[32]; sprintf( pFileNameIn, "_%05x_.cnf", Rand ); + char pFileNameOut[32]; sprintf( pFileNameOut, "_%05x_.out", Rand ); Exa6_Man_t * p = Exa6_ManAlloc( vSimsIn, vSimsOut, nIns, 1+nIns+nDivs, nOuts, nNodes, fVerbose ); Exa_ManIsNormalized( vSimsIn, vSimsOut ); Exa6_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans ); @@ -4016,8 +4035,9 @@ void Exa_ManExactSynthesis7( Bmc_EsPar_t * pPars, int GateSize ) int nV = pPars->nVars + pPars->nNodes; word pTruth[16]; Abc_TtReadHex( pTruth, pPars->pTtStr ); Vec_Int_t * vValues = NULL; - char * pFileNameIn = "_temp_.cnf"; - char * pFileNameOut = "_temp_out.cnf"; + int Rand = ((((unsigned)rand()) << 12) ^ ((unsigned)rand())) & 0xFFFFF; + char pFileNameIn[32]; sprintf( pFileNameIn, "_%05x_.cnf", Rand ); + char pFileNameOut[32]; sprintf( pFileNameOut, "_%05x_.out", Rand ); int nClas = Exa7_ManGenCnf( pFileNameIn, pTruth, pPars->nVars, pPars->nNodes, GateSize ); if ( pPars->fVerbose ) printf( "CNF with %d variables and %d clauses was dumped into file \"%s\".\n", nMints * nV * nV, nClas, pFileNameIn ); From c3b76b1712feb16bb0c582ccdfdc025c4f06fb96 Mon Sep 17 00:00:00 2001 From: jiunhaochen Date: Mon, 10 Mar 2025 15:36:00 +0800 Subject: [PATCH 11/42] Patch rewire --- src/base/abci/abc.c | 41 ++++++++++++++++++------------------ src/opt/rar/rewire_map.c | 1 + src/opt/rar/rewire_miaig.cpp | 30 +++++++++++++++++++++----- src/opt/rar/rewire_miaig.h | 3 +++ 4 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 1c2e39501..82632e760 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -20554,17 +20554,16 @@ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) usage: Abc_Print( -2, "usage: rewire [-IEGDFSTV ]\n" ); - Abc_Print( -2, "\t performs AIG re-wiring\n" ); - Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); - Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); - Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); - Abc_Print( -2, "\t-D : the number of shared divisors to extract [default = %d]\n", nDivs ); - Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); - Abc_Print( -2, "\t-L : localization distances [default = %d]\n", nDist); - Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); - Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); - Abc_Print( -2, "\t-T : the timeout in seconds [default = unused]\n" ); - Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); + Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); + Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); + Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); + Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); + Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); + Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); + Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); + Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); + Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); Abc_Print( -2, "\t-h : prints the command usage\n" ); Abc_Print( -2, "\n\tThis command was contributed by Jiun-Hao Chen from National Taiwan University.\n" ); return 1; @@ -45968,16 +45967,16 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) usage: Abc_Print( -2, "usage: &rewire [-IEGDFSTV ]\n" ); Abc_Print( -2, "\t performs AIG re-wiring\n" ); - Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); - Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); - Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); - Abc_Print( -2, "\t-D : the number of shared divisors to extract [default = %d]\n", nDivs ); - Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); - Abc_Print( -2, "\t-L : localization distances [default = %d]\n", nDist); - Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); - Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); - Abc_Print( -2, "\t-T : the timeout in seconds [default = unused]\n" ); - Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); + Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); + Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); + Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); + Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); + Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); + Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); + Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); + Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); + Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); Abc_Print( -2, "\t-h : prints the command usage\n" ); Abc_Print( -2, "\n\tThis command was contributed by Jiun-Hao Chen from National Taiwan University.\n" ); return 1; diff --git a/src/opt/rar/rewire_map.c b/src/opt/rar/rewire_map.c index b5f164a03..58f0d9a53 100644 --- a/src/opt/rar/rewire_map.c +++ b/src/opt/rar/rewire_map.c @@ -33,6 +33,7 @@ extern Mini_Aig_t * Abc_MiniAigFromNtk ( Abc_Ntk_t *pNtk ); Abc_Ntk_t *Gia_ManRewirePut(Gia_Man_t *pGia) { Aig_Man_t *pMan = Gia_ManToAig(pGia, 0); Abc_Ntk_t *pNtk = Abc_NtkFromAigPhase(pMan); + Abc_NtkSetName(pNtk, Abc_UtilStrsav(Gia_ManName(pGia))); Aig_ManStop(pMan); return pNtk; } diff --git a/src/opt/rar/rewire_miaig.cpp b/src/opt/rar/rewire_miaig.cpp index cbab82645..5a9f8008f 100644 --- a/src/opt/rar/rewire_miaig.cpp +++ b/src/opt/rar/rewire_miaig.cpp @@ -31,6 +31,7 @@ Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, int nExpands, int nGrow Rewire::Miaig pNtkMiaig(pGia); Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + pNew.setName(Gia_ManName(pGia)); return pNew.toGia(); } @@ -38,10 +39,15 @@ Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, int nExpands, int nGrow Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { Random_Num(nSeed); + int fMapped = nMode == 1; Rewire::Miaig pNtkMiaig(pNtk); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, fMapped, nDist, fVerbose); + pNew.setName(Abc_NtkName(pNtk)); + if (nMode == 2) { + pNew.countTransistors(1); + } - return pNew.toNtk(nMode); + return pNew.toNtk(nMode >= 1); } Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { @@ -84,6 +90,15 @@ void Miaig::create(int nIns, int nOuts, int nObjsAlloc) { } } +void Miaig::setName(char *pName) { + if (_data) { + if (_data->pName) { + free(_data->pName); + } + _data->pName = strdup(pName); + } +} + void Miaig::print(void) { int i, k, iLit; printf("\nAIG printout:\n"); @@ -149,6 +164,7 @@ int Miaig::fromMiniAig(Mini_Aig_t *pMiniAig) { Gia_Man_t *Miaig::toGia(void) { int i, k, iLit, And2 = countAnd2(); Gia_Man_t *pGia = Gia_ManStart(1 + nIns() + And2 + nOuts()), *pTemp; + pGia->pName = Abc_UtilStrsav( _data->pName ); Gia_ManHashAlloc(pGia); memset(_data->pCopy, 0, sizeof(int) * nObjs()); Miaig_ForEachInput(i) @@ -197,11 +213,15 @@ Mini_Aig_t *Miaig::toMiniAig(void) { } Abc_Ntk_t *Miaig::toNtk(int fMapped) { + Abc_Ntk_t *pNtk; if (_data->pNtkMapped && fMapped) { - return Abc_ManRewireNtkFromMiniMapping(Vi_Array(_data->pNtkMapped)); + pNtk = Abc_ManRewireNtkFromMiniMapping(Vi_Array(_data->pNtkMapped)); + ABC_FREE(pNtk->pName); + Abc_NtkSetName(pNtk, Abc_UtilStrsav(_data->pName)); + return pNtk; } Gia_Man_t *pGia = toGia(); - Abc_Ntk_t *pNtk = Gia_ManRewirePut(pGia); + pNtk = Gia_ManRewirePut(pGia); Gia_ManStop(pGia); return pNtk; } @@ -1125,7 +1145,7 @@ Miaig Miaig::rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFanin float PrevBest = ((&pBest)->*Miaig_ObjectiveFunction)(1); int iterNotImproveAfterRestart = 0; if (nVerbose) printf("Initial target : %5g (AND2 = %5g Level = %3d)\n", PrevBest, this->countAnd2(1), this->countLevel()); - for (int i = 0; i < nIters; i++) { + for (int i = 0; nIters ? i < nIters : 1; i++) { if (nVerbose) printf("\rIteration %7d : %5g -> ", i + 1, ((&pRoot)->*Miaig_ObjectiveFunction)(0)); if (nTimeOut && nTimeOut < 1.0 * (Time_Clock() - clkStart) / CLOCKS_PER_SEC) break; pNew = pRoot.dupMulti(nFaninMax, nGrowth); diff --git a/src/opt/rar/rewire_miaig.h b/src/opt/rar/rewire_miaig.h index c66b19bda..425a48e34 100644 --- a/src/opt/rar/rewire_miaig.h +++ b/src/opt/rar/rewire_miaig.h @@ -141,6 +141,7 @@ static inline int Rw_Lit2LitL(int *pMapV2L, int Lit) { } struct Miaig_Data { + char *pName; // network name int refcount; // Reference counter int nIns; // primary inputs int nOuts; // primary outputs @@ -217,6 +218,7 @@ public: void refObj(int iObj); void derefObj(int iObj); void derefObj_rec(int iObj, int iLitSkip); + void setName(char *pName); private: int initializeLevels_rec(int iObj); @@ -355,6 +357,7 @@ inline void Miaig::addref(void) { inline void Miaig::release(void) { if (_refcount && RW_XADD(_refcount, -1) == 1) { if (_data) { + if (_data->pName) free(_data->pName); for (int i = 0; i < _data->nObjsAlloc; ++i) if (_data->pvFans[i].ptr) free(_data->pvFans[i].ptr); From 67d8095515644b2d2219f9d79a039ac5c73a0179 Mon Sep 17 00:00:00 2001 From: jiunhaochen Date: Tue, 11 Mar 2025 15:23:58 +0800 Subject: [PATCH 12/42] fix read_mm --- src/base/abci/abcMap.c | 6 +++--- src/base/abci/abcPart.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/base/abci/abcMap.c b/src/base/abci/abcMap.c index 2c3021b45..93bb33c22 100644 --- a/src/base/abci/abcMap.c +++ b/src/base/abci/abcMap.c @@ -930,15 +930,15 @@ Abc_Ntk_t * Abc_NtkFromMiniMapping( int *pArray ) // create pis for ( i = 0; i < nCis-nFlops; i++ ) Abc_NtkCreatePi( pNtkMapped ); + // create nodes + for ( i = 0; i < nNodes; i++ ) + Abc_NtkCreateNode( pNtkMapped ); // create pos for ( i = 0; i < nCos-nFlops; i++ ) Abc_NtkCreatePo( pNtkMapped ); // create flops for ( i = 0; i < nFlops; i++ ) Abc_NtkAddLatch( pNtkMapped, NULL, ABC_INIT_ZERO ); - // create nodes - for ( i = 0; i < nNodes; i++ ) - Abc_NtkCreateNode( pNtkMapped ); // connect nodes for ( i = 0; i < nNodes; i++ ) { diff --git a/src/base/abci/abcPart.c b/src/base/abci/abcPart.c index da4d55a65..df85a6fce 100644 --- a/src/base/abci/abcPart.c +++ b/src/base/abci/abcPart.c @@ -1313,6 +1313,7 @@ Abc_Ntk_t * Abc_NtkStochProcessOne( Abc_Ntk_t * p, char * pScript0, int Rand, in } ABC_FREE( pScript ); pNew = Abc_NtkReadFromFile( FileName ); + unlink( FileName ); if ( pNew && Abc_NtkGetMappedArea(pNew) < Abc_NtkGetMappedArea(p) ) { pNew = Abc_NtkDupDfs( pTemp = pNew ); From c63cf096602aa71c8927d03348c77d355f2fe85a Mon Sep 17 00:00:00 2001 From: jiunhaochen Date: Wed, 12 Mar 2025 00:52:46 +0800 Subject: [PATCH 13/42] rewire support level constraint --- src/base/abci/abc.c | 34 ++++++++++++++++++++----- src/opt/rar/rewire_miaig.cpp | 48 ++++++++++++++++++++---------------- src/opt/rar/rewire_miaig.h | 12 ++++----- src/opt/rar/rewire_rar.c | 12 ++++----- src/opt/rar/rewire_rar.h | 12 ++++----- 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 82632e760..0335e4376 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -20427,15 +20427,16 @@ usage: ***********************************************************************/ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); + extern Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); Abc_Ntk_t *pNtk, *pTemp; int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nDist = 0; + float nLevelGrowRatio = 0; Extra_UtilGetoptReset(); // Cmd_CommandExecute pNtk = Abc_FrameReadNtk(pAbc); - while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLVh" ) ) != EOF ) { + while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLRVh" ) ) != EOF ) { switch ( c ) { case 'I': if ( globalUtilOptind >= argc ) @@ -20518,6 +20519,15 @@ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) nDist = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'R': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-L\" should be followed by a positive number.\n" ); + goto usage; + } + nLevelGrowRatio = atof(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'V': if ( globalUtilOptind >= argc ) { @@ -20548,7 +20558,7 @@ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } - pTemp = Abc_ManRewire( pNtk, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); + pTemp = Abc_ManRewire( pNtk, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); Abc_FrameReplaceCurrentNetwork( pAbc, pTemp ); return 0; @@ -20560,6 +20570,7 @@ usage: Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-R : level constraint (0 = unlimited, 1 = preserve level) [default = %g]\n", nLevelGrowRatio); Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); @@ -45840,12 +45851,13 @@ usage: ***********************************************************************/ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); + extern Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); Gia_Man_t *pTemp; int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nDist = 0; + float nLevelGrowRatio = 0; Extra_UtilGetoptReset(); // Cmd_CommandExecute - while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLVh" ) ) != EOF ) { + while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLRVh" ) ) != EOF ) { switch ( c ) { case 'I': if ( globalUtilOptind >= argc ) @@ -45928,6 +45940,15 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) nDist = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'R': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-L\" should be followed by a positive number.\n" ); + goto usage; + } + nLevelGrowRatio = atof(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'V': if ( globalUtilOptind >= argc ) { @@ -45958,7 +45979,7 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } - pTemp = Gia_ManRewire( pAbc->pGia, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); + pTemp = Gia_ManRewire( pAbc->pGia, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); if ( pTemp->pName == NULL ) pTemp->pName = Abc_UtilStrsav(Extra_FileNameWithoutPath(pAbc->pGia->pName)); Abc_FrameUpdateGia( pAbc, pTemp ); @@ -45973,6 +45994,7 @@ usage: Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-R : level constraint (0 = unlimited, 1 = preserve level) [default = %g]\n", nLevelGrowRatio); Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); diff --git a/src/opt/rar/rewire_miaig.cpp b/src/opt/rar/rewire_miaig.cpp index 5a9f8008f..bbc2abe8f 100644 --- a/src/opt/rar/rewire_miaig.cpp +++ b/src/opt/rar/rewire_miaig.cpp @@ -26,22 +26,22 @@ ABC_NAMESPACE_IMPL_START #endif // RW_ABC #ifdef RW_ABC -Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { +Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { Random_Num(nSeed); Rewire::Miaig pNtkMiaig(pGia); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); pNew.setName(Gia_ManName(pGia)); return pNew.toGia(); } -Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { +Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { Random_Num(nSeed); int fMapped = nMode == 1; Rewire::Miaig pNtkMiaig(pNtk); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, fMapped, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, fMapped, nDist, fVerbose); pNew.setName(Abc_NtkName(pNtk)); if (nMode == 2) { pNew.countTransistors(1); @@ -50,11 +50,11 @@ Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrow return pNew.toNtk(nMode >= 1); } -Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { +Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { Random_Num(nSeed); Rewire::Miaig pNtkMiaig(pAig); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); return pNew.toMiniAig(); } @@ -912,7 +912,7 @@ int Miaig::checkConst(int iObj, word *pCare, int fVerbose) { return 0; } -int Miaig::expandOne(int iObj, int nAddedMax, int nDist, int fVerbose) { +int Miaig::expandOne(int iObj, int nAddedMax, int nDist, int nExpandableLevel, int fVerbose) { int i, k, n, iLit, nAdded = 0; word *pCare = computeCareSet(iObj); assert(nAddedMax > 0); @@ -928,6 +928,7 @@ int Miaig::expandOne(int iObj, int nAddedMax, int nDist, int fVerbose) { if (nDist) markDistanceN(iObj, nDist); Miaig_ForEachInputNode(i) { if (nDist && objDist(i) < 0 && !objIsPi(i)) continue; + // if (nExpandableLevel && objLevel(i) - objLevel(iObj) > nExpandableLevel) continue; if (objTravId(i) != nTravIds() && (objIsPi(i) || (objFaninNum(i) > 1 && objRef(i) > 0))) // this node is NOT in the TFO Vi_Push(_data->vOrderF, i); } @@ -1030,8 +1031,8 @@ int Miaig::reduceOne(int iObj, int fOnlyConst, int fOnlyBuffer, int fHeuristic, return 0; } -int Miaig::expandThenReduceOne(int iNode, int nFaninAddLimit, int nDist, int fVerbose) { - expandOne(iNode, Abc_MinInt(Vi_Space(_data->pvFans + iNode), nFaninAddLimit), nDist, fVerbose); +int Miaig::expandThenReduceOne(int iNode, int nFaninAddLimit, int nDist, int nExpandableLevel, int fVerbose) { + expandOne(iNode, Abc_MinInt(Vi_Space(_data->pvFans + iNode), nFaninAddLimit), nDist, nExpandableLevel, fVerbose); reduceOne(iNode, 0, 0, 0, fVerbose); return 0; } @@ -1045,7 +1046,7 @@ vi *Miaig::createRandomOrder(void) { return _data->vOrder; } -Miaig Miaig::expand(int nFaninAddLimitAll, int nDist, int fVerbose) { +Miaig Miaig::expand(int nFaninAddLimitAll, int nDist, int nExpandableLevel, int fVerbose) { int i, iNode, nAdded = 0; assert(nFaninAddLimitAll > 0); vi *vOrder = createRandomOrder(); @@ -1055,7 +1056,7 @@ Miaig Miaig::expand(int nFaninAddLimitAll, int nDist, int fVerbose) { initializeLevels(); if (nDist) initializeDists(); Vi_ForEachEntry(vOrder, iNode, i) { - nAdded += expandOne(iNode, Abc_MinInt(Vi_Space(_data->pvFans + iNode), nFaninAddLimitAll - nAdded), nDist, fVerbose); + nAdded += expandOne(iNode, Abc_MinInt(Vi_Space(_data->pvFans + iNode), nFaninAddLimitAll - nAdded), nDist, nExpandableLevel, fVerbose); if (nAdded >= nFaninAddLimitAll) break; } @@ -1091,7 +1092,7 @@ Miaig Miaig::reduce(int fVerbose) { return dupStrash(1, 1, 1); } -Miaig Miaig::expandThenReduce(int nFaninAddLimit, int nDist, int fVerbose) { +Miaig Miaig::expandThenReduce(int nFaninAddLimit, int nDist, int nExpandableLevel, int fVerbose) { Miaig pTemp; int i, iNode; vi *vOrder = topoCollect(); @@ -1101,15 +1102,15 @@ Miaig Miaig::expandThenReduce(int nFaninAddLimit, int nDist, int fVerbose) { initializeLevels(); if (nDist) initializeDists(); Vi_ForEachEntry(vOrder, iNode, i) { - expandThenReduceOne(iNode, nFaninAddLimit, nDist, fVerbose); + expandThenReduceOne(iNode, nFaninAddLimit, nDist, nExpandableLevel, fVerbose); } verifyRefs(); return dupDfs().dupStrash(1, 1, 1); } -Miaig Miaig::expandShareReduce(int nFaninAddLimitAll, int nDivs, int nDist, int nVerbose) { +Miaig Miaig::expandShareReduce(int nFaninAddLimitAll, int nDivs, int nDist, int nExpandableLevel, int nVerbose) { // expand - Miaig pNew = expand(nFaninAddLimitAll, nDist, nVerbose); + Miaig pNew = expand(nFaninAddLimitAll, nDist, nExpandableLevel, nVerbose); // share pNew = pNew.share(nDivs == -1 ? pNew.nObjs() : nDivs); // reduce @@ -1130,7 +1131,7 @@ Miaig randomRead(std::vector &pBests) { return pBests[Random_Num(0) % pBests.size()]; } -Miaig Miaig::rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose) { +Miaig Miaig::rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose) { const int nRootSave = 8; const int nBestSave = 4; int nRestart = 5000; @@ -1141,9 +1142,12 @@ Miaig Miaig::rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFanin Miaig pRoot = pRoots[0]; Miaig pBest = this->dup(0); float (Miaig::*Miaig_ObjectiveFunction)(int) = (nMode == 0) ? &Miaig::countAnd2 : &Miaig::countTransistors; + int maxLevel = levelGrowRatio != 0 ? this->countLevel() * levelGrowRatio : 0; + int nExpandableLevel = maxLevel ? maxLevel - this->countLevel() : 0; float PrevBest = ((&pBest)->*Miaig_ObjectiveFunction)(1); int iterNotImproveAfterRestart = 0; + if (nVerbose && maxLevel) printf("Max level : %5d\n", maxLevel); if (nVerbose) printf("Initial target : %5g (AND2 = %5g Level = %3d)\n", PrevBest, this->countAnd2(1), this->countLevel()); for (int i = 0; nIters ? i < nIters : 1; i++) { if (nVerbose) printf("\rIteration %7d : %5g -> ", i + 1, ((&pRoot)->*Miaig_ObjectiveFunction)(0)); @@ -1151,15 +1155,16 @@ Miaig Miaig::rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFanin pNew = pRoot.dupMulti(nFaninMax, nGrowth); if (i % 2 == 0) { - pNew = pNew.expandThenReduce(nGrowth, nDist, nVerbose > 1); + pNew = pNew.expandThenReduce(nGrowth, nDist, nExpandableLevel, nVerbose > 1); } - pNew = pNew.expandShareReduce(nExpands, nDivs, nDist, nVerbose > 1); + pNew = pNew.expandShareReduce(nExpands, nDivs, nDist, nExpandableLevel, nVerbose > 1); ++iterNotImproveAfterRestart; // report float rootTarget = ((&pRoot)->*Miaig_ObjectiveFunction)(0); float newTarget = ((&pNew)->*Miaig_ObjectiveFunction)(1); - if (PrevBest > newTarget) { + if (maxLevel ? pNew.countLevel() > maxLevel : 0) { + } else if (PrevBest > newTarget) { if (nVerbose) printf("%5g (AND2 = %5g Level = %3d) ", newTarget, pNew.countAnd2(), pNew.countLevel()); if (nVerbose) Time_PrintEndl("Elapsed time", Time_Clock() - clkStart); PrevBest = newTarget; @@ -1170,10 +1175,11 @@ Miaig Miaig::rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFanin randomAddBest(pBests, pNew.dup(0), nBestSave); } // compare - if (rootTarget < newTarget) { + if (maxLevel ? pNew.countLevel() > maxLevel : 0) { + } else if (rootTarget < newTarget) { if (iterNotImproveAfterRestart > nRestart) { pNew = randomRead(pBests).dupMulti(nFaninMax, nGrowth); - pNew = pNew.expand(nExpands, nDist, nVerbose > 1); + pNew = pNew.expand(nExpands, nDist, nExpandableLevel, nVerbose > 1); pNew = pNew.share(nDivs == -1 ? pNew.nObjs() : nDivs); pNew = pNew.dupStrash(1, 1, 0); pRoots = {pNew}; diff --git a/src/opt/rar/rewire_miaig.h b/src/opt/rar/rewire_miaig.h index 425a48e34..6b9aed37d 100644 --- a/src/opt/rar/rewire_miaig.h +++ b/src/opt/rar/rewire_miaig.h @@ -271,21 +271,21 @@ private: int buildNodeCascade(Miaig &pNew, vi *vFanins, int fCprop, int fStrash); private: - int expandOne(int iObj, int nAddedMax, int nDist, int fVerbose); + int expandOne(int iObj, int nAddedMax, int nDist, int nExpandableLevel, int fVerbose); int reduceOne(int iObj, int fOnlyConst, int fOnlyBuffer, int fHeuristic, int fVerbose); - int expandThenReduceOne(int iNode, int nFaninAddLimit, int nDist, int fVerbose); + int expandThenReduceOne(int iNode, int nFaninAddLimit, int nDist, int nExpandableLevel, int fVerbose); public: Miaig dup(int fRemDangle, int fMapped = 0); Miaig dupDfs(void); Miaig dupStrash(int fCprop, int fStrash, int fCascade); Miaig dupMulti(int nFaninMax_, int nGrowth); - Miaig expand(int nFaninAddLimitAll, int nDist, int nVerbose); + Miaig expand(int nFaninAddLimitAll, int nDist, int nExpandableLevel, int nVerbose); Miaig share(int nNewNodesMax); Miaig reduce(int fVerbose); - Miaig expandThenReduce(int nFaninAddLimit, int nDist, int fVerbose); - Miaig expandShareReduce(int nFaninAddLimitAll, int nDivs, int nDist, int nVerbose); - Miaig rewire(int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose); + Miaig expandThenReduce(int nFaninAddLimit, int nDist, int nExpandableLevel, int fVerbose); + Miaig expandShareReduce(int nFaninAddLimitAll, int nDivs, int nDist, int nExpandableLevel, int nVerbose); + Miaig rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose); #ifdef RW_ABC Gia_Man_t *toGia(void); Abc_Ntk_t *toNtk(int fMapped = 0); diff --git a/src/opt/rar/rewire_rar.c b/src/opt/rar/rewire_rar.c index 335fada78..3a4ed2b65 100644 --- a/src/opt/rar/rewire_rar.c +++ b/src/opt/rar/rewire_rar.c @@ -22,16 +22,16 @@ ABC_NAMESPACE_IMPL_START -Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return Gia_ManRewireInt(pGia, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { + return Gia_ManRewireInt(pGia, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); } -Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return Abc_ManRewireInt(pNtk, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { + return Abc_ManRewireInt(pNtk, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); } -Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return MiniAig_ManRewireInt(pAig, nIters, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { + return MiniAig_ManRewireInt(pAig, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); } ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/opt/rar/rewire_rar.h b/src/opt/rar/rewire_rar.h index cdfa62a7e..76a1b2e78 100644 --- a/src/opt/rar/rewire_rar.h +++ b/src/opt/rar/rewire_rar.h @@ -35,12 +35,12 @@ ABC_NAMESPACE_HEADER_START -Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); ABC_NAMESPACE_HEADER_END From e937e82cc61b0cc3617c0ae8fe54f7ec19299fd8 Mon Sep 17 00:00:00 2001 From: jiunhaochen Date: Mon, 17 Mar 2025 10:09:34 +0800 Subject: [PATCH 14/42] rewire with &nf, &simap --- src/aig/gia/giaSatLut.c | 6 +-- src/base/abci/abc.c | 71 +++++++++++++++++++----------- src/base/abci/abcPart.c | 24 +++++----- src/opt/rar/rewire_map.c | 28 +++++++++++- src/opt/rar/rewire_map.h | 4 +- src/opt/rar/rewire_miaig.cpp | 85 +++++++++++++++++++++++------------- src/opt/rar/rewire_miaig.h | 9 ++-- src/opt/rar/rewire_rar.c | 12 ++--- src/opt/rar/rewire_rar.h | 12 ++--- 9 files changed, 162 insertions(+), 89 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index 716566cae..ee63d77ad 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1243,7 +1243,7 @@ Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimi #ifdef _WIN32 char * pKadical = "kadical.exe"; #else - char * pKadical = "kadical"; + char * pKadical = "./kadical"; #endif char Command[1000], * pCommand = (char *)&Command; if ( nBTLimit ) { @@ -1582,7 +1582,7 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, if ( fVerbose ) printf( "SAT variables = %d. SAT clauses = %d. Cardinality bound = %d. Conflict limit = %d. Timeout = %d.\n", nVars, Vec_StrCountEntry(vStr, '\n'), nBound, nBTLimit, nTimeout ); - Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1, &Status ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, fVerbose, &Status ); unlink( pFileNameI ); //unlink( pFileNameO ); if ( fKeepFile ) Gia_ManDumpCnf2( vStr, nVars, argc, argv, Abc_Clock() - clkStart, Status ); @@ -1595,7 +1595,7 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, if ( fVerbose ) Gia_ManSimplePrintMapping( vRes, Gia_ManCiNum(p) ); p->vCellMapping = Gia_ManDeriveSimpleMapping( p, vRes ); Vec_IntFree( vRes ); - Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); + if ( fVerbose ) Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); return 1; } diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0335e4376..6a435a5d6 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -20427,16 +20427,15 @@ usage: ***********************************************************************/ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); + extern Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); Abc_Ntk_t *pNtk, *pTemp; - int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nDist = 0; + int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nMappedMode = 0, nDist = 0; float nLevelGrowRatio = 0; Extra_UtilGetoptReset(); - // Cmd_CommandExecute pNtk = Abc_FrameReadNtk(pAbc); - while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLRVh" ) ) != EOF ) { + while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMALRVh" ) ) != EOF ) { switch ( c ) { case 'I': if ( globalUtilOptind >= argc ) @@ -20510,6 +20509,15 @@ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) nMode = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'A': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by a positive integer.\n" ); + goto usage; + } + nMappedMode = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'L': if ( globalUtilOptind >= argc ) { @@ -20552,28 +20560,29 @@ int Abc_CommandRewire( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Empty network.\n" ); return 1; } - if ( nMode == 1 && Abc_FrameReadLibGen2() == NULL ) + if ( nMode >= 1 && Abc_FrameReadLibGen2() == NULL ) { Abc_Print( -1, "Library is not available.\n" ); return 1; } - pTemp = Abc_ManRewire( pNtk, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); + pTemp = Abc_ManRewire( pNtk, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, nSeed, nVerbose ); Abc_FrameReplaceCurrentNetwork( pAbc, pTemp ); return 0; usage: - Abc_Print( -2, "usage: rewire [-IEGDFSTV ]\n" ); + Abc_Print( -2, "usage: rewire [-IEGDFLRMASTV ]\n" ); Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); - Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); + Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1: unlimited) [default = %d]\n", nDivs ); Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); - Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); - Abc_Print( -2, "\t-R : level constraint (0 = unlimited, 1 = preserve level) [default = %g]\n", nLevelGrowRatio); - Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); - Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); - Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); + Abc_Print( -2, "\t-L : localization distances (0: unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-R : level constraint (0: unlimited, 1: preserve level) [default = %g]\n", nLevelGrowRatio); + Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "area" : "AIG node" ); + Abc_Print( -2, "\t-A : mapper (0: amap, 1: &nf, 2: &simap) (experimental) [default = %d]\n", nMappedMode ); + Abc_Print( -2, "\t-S : the random seed (0: random, >= 1: user defined) [default = %d]\n", nSeed ); + Abc_Print( -2, "\t-T : the timeout in seconds (0: unlimited) [default = %d]\n", nTimeOut ); Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); Abc_Print( -2, "\t-h : prints the command usage\n" ); Abc_Print( -2, "\n\tThis command was contributed by Jiun-Hao Chen from National Taiwan University.\n" ); @@ -45851,13 +45860,13 @@ usage: ***********************************************************************/ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); + extern Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); Gia_Man_t *pTemp; - int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nDist = 0; + int c, nIters = 100000, nExpands = 128, nGrowth = 4, nDivs = -1, nFaninMax = 8, nSeed = 1, nTimeOut = 0, nVerbose = 1, nMode = 0, nMappedMode = 0, nDist = 0; float nLevelGrowRatio = 0; Extra_UtilGetoptReset(); - // Cmd_CommandExecute - while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMLRVh" ) ) != EOF ) { + + while ( ( c = Extra_UtilGetopt( argc, argv, "IEGDFSTMALRVh" ) ) != EOF ) { switch ( c ) { case 'I': if ( globalUtilOptind >= argc ) @@ -45931,6 +45940,15 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) nMode = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'A': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by a positive integer.\n" ); + goto usage; + } + nMappedMode = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'L': if ( globalUtilOptind >= argc ) { @@ -45973,31 +45991,32 @@ int Abc_CommandAbc9Rewire( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Empty GIA network.\n" ); return 1; } - if ( nMode == 1 && Abc_FrameReadLibGen2() == NULL ) + if ( nMode >= 1 && Abc_FrameReadLibGen2() == NULL ) { Abc_Print( -1, "Library is not available.\n" ); return 1; } - pTemp = Gia_ManRewire( pAbc->pGia, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, nVerbose ); + pTemp = Gia_ManRewire( pAbc->pGia, nIters, nLevelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, nSeed, nVerbose ); if ( pTemp->pName == NULL ) pTemp->pName = Abc_UtilStrsav(Extra_FileNameWithoutPath(pAbc->pGia->pName)); Abc_FrameUpdateGia( pAbc, pTemp ); return 0; usage: - Abc_Print( -2, "usage: &rewire [-IEGDFSTV ]\n" ); + Abc_Print( -2, "usage: &rewire [-IEGDFLRMASTV ]\n" ); Abc_Print( -2, "\t performs AIG re-wiring\n" ); Abc_Print( -2, "\t-I : the number of iterations [default = %d]\n", nIters ); Abc_Print( -2, "\t-E : the number of fanins to add to all nodes [default = %d]\n", nExpands ); Abc_Print( -2, "\t-G : the number of fanins to add to one node [default = %d]\n", nGrowth ); - Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1 = unlimited) [default = %d]\n", nDivs ); + Abc_Print( -2, "\t-D : the number of shared divisors to extract (-1: unlimited) [default = %d]\n", nDivs ); Abc_Print( -2, "\t-F : the limit on the fanin count at a node [default = %d]\n", nFaninMax); - Abc_Print( -2, "\t-L : localization distances (0 = unlimited) [default = %d]\n", nDist); - Abc_Print( -2, "\t-R : level constraint (0 = unlimited, 1 = preserve level) [default = %g]\n", nLevelGrowRatio); - Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "transistor" : "node" ); - Abc_Print( -2, "\t-S : the random seed [default = %d]\n", nSeed ); - Abc_Print( -2, "\t-T : the timeout in seconds (0 = unlimited) [default = %d]\n", nTimeOut ); + Abc_Print( -2, "\t-L : localization distances (0: unlimited) [default = %d]\n", nDist); + Abc_Print( -2, "\t-R : level constraint (0: unlimited, 1: preserve level) [default = %g]\n", nLevelGrowRatio); + Abc_Print( -2, "\t-M : optimization target [default = %s]\n", nMode ? "area" : "AIG node" ); + Abc_Print( -2, "\t-A : mapper (0: amap, 1: &nf, 2: &simap) (experimental) [default = %d]\n", nMappedMode ); + Abc_Print( -2, "\t-S : the random seed (0: random, >= 1: user defined) [default = %d]\n", nSeed ); + Abc_Print( -2, "\t-T : the timeout in seconds (0: unlimited) [default = %d]\n", nTimeOut ); Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", nVerbose ); Abc_Print( -2, "\t-h : prints the command usage\n" ); Abc_Print( -2, "\n\tThis command was contributed by Jiun-Hao Chen from National Taiwan University.\n" ); diff --git a/src/base/abci/abcPart.c b/src/base/abci/abcPart.c index df85a6fce..8f943f379 100644 --- a/src/base/abci/abcPart.c +++ b/src/base/abci/abcPart.c @@ -1313,7 +1313,6 @@ Abc_Ntk_t * Abc_NtkStochProcessOne( Abc_Ntk_t * p, char * pScript0, int Rand, in } ABC_FREE( pScript ); pNew = Abc_NtkReadFromFile( FileName ); - unlink( FileName ); if ( pNew && Abc_NtkGetMappedArea(pNew) < Abc_NtkGetMappedArea(p) ) { pNew = Abc_NtkDupDfs( pTemp = pNew ); @@ -1613,6 +1612,7 @@ void Abc_NtkPermuteLevel( Abc_Ntk_t * pNtk, int Level ) Abc_ObjForEachFanout( pObj, pNext, k ) if ( Abc_ObjIsNode(pNext) ) LevelMax = Abc_MinInt( LevelMax, Abc_ObjLevel(pNext) ); + if ( LevelMin == LevelMax ) continue; assert( LevelMin < LevelMax ); // randomly set level between LevelMin and LevelMax-1 pObj->Level = LevelMin + (Abc_Random(0) % (LevelMax - LevelMin)); @@ -1802,17 +1802,19 @@ Vec_Ptr_t * Abc_NtkDupWindows( Abc_Ntk_t * pNtk, Vec_Ptr_t * vvIns, Vec_Ptr_t * } Vec_Ptr_t * Abc_NtkExtractPartitions( Abc_Ntk_t * pNtk, int Iter, int nSuppMax, Vec_Ptr_t ** pvIns, Vec_Ptr_t ** pvOuts, Vec_Ptr_t ** pvNodes ) { - if ( Abc_NtkCiNum(pNtk) <= nSuppMax ) { - Vec_Ptr_t * vWins = Vec_PtrAlloc( 1 ); - Vec_PtrPush( vWins, Abc_NtkDupDfs(pNtk) ); - *pvIns = *pvOuts = *pvNodes = NULL; - return vWins; - } - int iUseRevL = Iter % 3 == 0 ? 0 : Abc_Random(0) & 1; + // if ( Abc_NtkCiNum(pNtk) <= nSuppMax ) { + // Vec_Ptr_t * vWins = Vec_PtrAlloc( 1 ); + // Vec_PtrPush( vWins, Abc_NtkDupDfs(pNtk) ); + // *pvIns = *pvOuts = *pvNodes = NULL; + // return vWins; + // } + // int iUseRevL = Iter % 3 == 0 ? 0 : Abc_Random(0) & 1; + int iUseRevL = Abc_Random(0) & 1; int LevelMax = iUseRevL ? Abc_NtkLevelR(pNtk) : Abc_NtkLevel(pNtk); - int LevelCut = Iter % 3 == 0 ? 0 : LevelMax > 8 ? 2 + (Abc_Random(0) % (LevelMax - 4)) : 0; - //printf( "Using %s cut level %d (out of %d)\n", iUseRevL ? "reverse": "direct", LevelCut, LevelMax ); - Abc_NtkPermuteLevel( pNtk, LevelMax ); + // int LevelCut = Iter % 3 == 0 ? 0 : LevelMax > 8 ? 2 + (Abc_Random(0) % (LevelMax - 4)) : 0; + int LevelCut = LevelMax > 8 ? (Abc_Random(0) % (LevelMax - 4)) : 0; + // printf( "Using %s cut level %d (out of %d)\n", iUseRevL ? "reverse": "direct", LevelCut, LevelMax ); + // Abc_NtkPermuteLevel( pNtk, LevelMax ); Vec_Wec_t * vStore = Vec_WecStart( LevelMax+1 ); Vec_Wec_t * vSupps = Abc_NtkCollectObjectsWithSuppLimit( pNtk, LevelCut, nSuppMax ); Vec_Ptr_t * vIns = Abc_NtkDeriveWinInsAll( vSupps, nSuppMax, pNtk ); diff --git a/src/opt/rar/rewire_map.c b/src/opt/rar/rewire_map.c index 58f0d9a53..47621de71 100644 --- a/src/opt/rar/rewire_map.c +++ b/src/opt/rar/rewire_map.c @@ -29,6 +29,11 @@ extern Vec_Int_t * Abc_NtkWriteMiniMapping( Abc_Ntk_t * pNtk ); extern void Abc_NtkPrintMiniMapping( int * pArray ); extern Abc_Ntk_t * Abc_NtkFromMiniMapping( int *vMapping ); extern Mini_Aig_t * Abc_MiniAigFromNtk ( Abc_Ntk_t *pNtk ); +extern void Nf_ManSetDefaultPars( Jf_Par_t * pPars ); +extern Gia_Man_t * Nf_ManPerformMapping( Gia_Man_t * pGia, Jf_Par_t * pPars ); +extern Abc_Ntk_t * Abc_NtkFromMappedGia( Gia_Man_t * p, int fFindEnables, int fUseBuffs ); +extern Abc_Ntk_t * Abc_NtkFromCellMappedGia( Gia_Man_t * p, int fUseBuffs ); +extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); Abc_Ntk_t *Gia_ManRewirePut(Gia_Man_t *pGia) { Aig_Man_t *pMan = Gia_ManToAig(pGia, 0); @@ -38,16 +43,35 @@ Abc_Ntk_t *Gia_ManRewirePut(Gia_Man_t *pGia) { return pNtk; } -Abc_Ntk_t *Abc_ManRewireMap(Abc_Ntk_t *pNtk) { +Abc_Ntk_t *Abc_ManRewireMapAmap(Abc_Ntk_t *pNtk) { Amap_Par_t Pars, *pPars = &Pars; Amap_ManSetDefaultParams(pPars); Abc_Ntk_t *pNtkMapped = Abc_NtkDarAmap(pNtk, pPars); if (pNtkMapped == NULL) { - Abc_NtkDelete(pNtk); Abc_Print(-1, "Mapping has failed.\n"); return NULL; } + return pNtkMapped; +} +Abc_Ntk_t *Gia_ManRewireMapNf(Gia_Man_t *pGia) { + Jf_Par_t Pars, * pPars = &Pars; + Nf_ManSetDefaultPars( pPars ); + Gia_Man_t *pGiaNew = Nf_ManPerformMapping(pGia, pPars); + if (pGiaNew == NULL) { + Abc_Print(-1, "Mapping has failed.\n"); + return NULL; + } + Abc_Ntk_t *pNtkMapped = Abc_NtkFromCellMappedGia(pGiaNew, 0); + return pNtkMapped; +} + +Abc_Ntk_t *Gia_ManRewireMapSimap(Gia_Man_t *pGia, int nBound, int nBTLimit, int nTimeout) { + if (!Gia_ManSimpleMapping(pGia, nBound, nBTLimit, nTimeout, 0, 0, 0, NULL)) { + // Abc_Print(-1, "Mapping has failed.\n"); + return NULL; + } + Abc_Ntk_t *pNtkMapped = Abc_NtkFromCellMappedGia(pGia, 0); return pNtkMapped; } diff --git a/src/opt/rar/rewire_map.h b/src/opt/rar/rewire_map.h index aa4a00c61..7ed31f243 100644 --- a/src/opt/rar/rewire_map.h +++ b/src/opt/rar/rewire_map.h @@ -30,7 +30,9 @@ ABC_NAMESPACE_HEADER_START Abc_Ntk_t *Gia_ManRewirePut(Gia_Man_t *pGia); -Abc_Ntk_t *Abc_ManRewireMap(Abc_Ntk_t *pNtk); +Abc_Ntk_t *Abc_ManRewireMapAmap(Abc_Ntk_t *pNtk); +Abc_Ntk_t *Gia_ManRewireMapNf(Gia_Man_t *pGia); +Abc_Ntk_t *Gia_ManRewireMapSimap(Gia_Man_t *pGia, int nBound, int nBTLimit, int nTimeout); Vec_Int_t *Abc_ManRewireNtkWriteMiniMapping(Abc_Ntk_t *pNtk); Abc_Ntk_t *Abc_ManRewireNtkFromMiniMapping(int *vMapping); Mini_Aig_t *Abc_ManRewireMiniAigFromNtk(Abc_Ntk_t *pNtk); diff --git a/src/opt/rar/rewire_miaig.cpp b/src/opt/rar/rewire_miaig.cpp index bbc2abe8f..59070349f 100644 --- a/src/opt/rar/rewire_miaig.cpp +++ b/src/opt/rar/rewire_miaig.cpp @@ -26,35 +26,35 @@ ABC_NAMESPACE_IMPL_START #endif // RW_ABC #ifdef RW_ABC -Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - Random_Num(nSeed); +Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + Random_Num(nSeed == 0 ? Abc_Random(0) % 10 : nSeed); Rewire::Miaig pNtkMiaig(pGia); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, fVerbose); pNew.setName(Gia_ManName(pGia)); return pNew.toGia(); } -Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - Random_Num(nSeed); +Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + Random_Num(nSeed == 0 ? Abc_Random(0) % 10 : nSeed); int fMapped = nMode == 1; Rewire::Miaig pNtkMiaig(pNtk); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, fMapped, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, fMapped, nMappedMode, nDist, fVerbose); pNew.setName(Abc_NtkName(pNtk)); if (nMode == 2) { - pNew.countTransistors(1); + pNew.countTransistors(1, nMappedMode); } return pNew.toNtk(nMode >= 1); } -Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - Random_Num(nSeed); +Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + Random_Num(nSeed == 0 ? Abc_Random(0) % 10 : nSeed); Rewire::Miaig pNtkMiaig(pAig); - Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, fVerbose); + Rewire::Miaig pNew = pNtkMiaig.rewire(nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, fVerbose); return pNew.toMiniAig(); } @@ -225,26 +225,51 @@ Abc_Ntk_t *Miaig::toNtk(int fMapped) { Gia_ManStop(pGia); return pNtk; } + +vi *moveVecToVi(Vec_Int_t *v) { + vi *p = (vi *)malloc(sizeof(vi)); + p->size = Vec_IntSize(v); + p->cap = Vec_IntCap(v); + p->ptr = Vec_IntArray(v); + free(v); + return p; +} #endif // RW_ABC // technology mapping -float Miaig::countTransistors(int reset) { +float Miaig::countTransistors(int reset, int nMappedMode) { if (!reset && _data->nTransistor) return _data->nTransistor; #ifdef RW_ABC - Abc_Ntk_t *pNtk = toNtk(); - Abc_Ntk_t *pNtkMapped = Abc_ManRewireMap(pNtk); - - float area = Abc_NtkGetMappedArea(pNtkMapped); - Vec_Int_t *vMapping = Abc_ManRewireNtkWriteMiniMapping(pNtkMapped); - _data->pNtkMapped = (vi *)malloc(sizeof(vi)); - _data->pNtkMapped->size = Vec_IntSize(vMapping); - _data->pNtkMapped->cap = Vec_IntCap(vMapping); - _data->pNtkMapped->ptr = Vec_IntArray(vMapping); - free(vMapping); - Abc_NtkDelete(pNtk); - Abc_NtkDelete(pNtkMapped); -#else float area = 0; + Abc_Ntk_t *pNtkMapped = NULL, *pNtkMappedTemp = NULL; + if (nMappedMode == 0) { // amap + Abc_Ntk_t *pNtk = toNtk(); + pNtkMapped = Abc_ManRewireMapAmap(pNtk); + Abc_NtkDelete(pNtk); + } else if (nMappedMode == 1) { // &nf + Gia_Man_t *pGia = toGia(); + pNtkMapped = Gia_ManRewireMapNf(pGia); + Gia_ManStop(pGia); + } else if (nMappedMode == 2) { // &simap + Abc_Ntk_t *pNtk = toNtk(); + pNtkMapped = Abc_ManRewireMapAmap(pNtk); + area = Abc_NtkGetMappedArea(pNtkMapped); + Gia_Man_t *pGia = toGia(); + while ((pNtkMappedTemp = Gia_ManRewireMapSimap(pGia, area - 2, 0, 40))) { + area -= 2; + Abc_NtkDelete(pNtkMapped); + pNtkMapped = pNtkMappedTemp; + } + Gia_ManStop(pGia); + } + if (pNtkMapped) { + area = Abc_NtkGetMappedArea(pNtkMapped); + Vec_Int_t *vMapping = Abc_ManRewireNtkWriteMiniMapping(pNtkMapped); + _data->pNtkMapped = moveVecToVi(vMapping); + Abc_NtkDelete(pNtkMapped); + } +#else + float area = countAnd2(reset, 0); #endif // RW_ABC return _data->nTransistor = area; @@ -1131,7 +1156,7 @@ Miaig randomRead(std::vector &pBests) { return pBests[Random_Num(0) % pBests.size()]; } -Miaig Miaig::rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose) { +Miaig Miaig::rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nVerbose) { const int nRootSave = 8; const int nBestSave = 4; int nRestart = 5000; @@ -1141,16 +1166,16 @@ Miaig Miaig::rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, Miaig pNew; Miaig pRoot = pRoots[0]; Miaig pBest = this->dup(0); - float (Miaig::*Miaig_ObjectiveFunction)(int) = (nMode == 0) ? &Miaig::countAnd2 : &Miaig::countTransistors; + float (Miaig::*Miaig_ObjectiveFunction)(int, int) = (nMode == 0) ? &Miaig::countAnd2 : &Miaig::countTransistors; int maxLevel = levelGrowRatio != 0 ? this->countLevel() * levelGrowRatio : 0; int nExpandableLevel = maxLevel ? maxLevel - this->countLevel() : 0; - float PrevBest = ((&pBest)->*Miaig_ObjectiveFunction)(1); + float PrevBest = ((&pBest)->*Miaig_ObjectiveFunction)(1, nMappedMode); int iterNotImproveAfterRestart = 0; if (nVerbose && maxLevel) printf("Max level : %5d\n", maxLevel); if (nVerbose) printf("Initial target : %5g (AND2 = %5g Level = %3d)\n", PrevBest, this->countAnd2(1), this->countLevel()); for (int i = 0; nIters ? i < nIters : 1; i++) { - if (nVerbose) printf("\rIteration %7d : %5g -> ", i + 1, ((&pRoot)->*Miaig_ObjectiveFunction)(0)); + if (nVerbose) printf("\rIteration %7d : %5g -> ", i + 1, ((&pRoot)->*Miaig_ObjectiveFunction)(0, nMappedMode)); if (nTimeOut && nTimeOut < 1.0 * (Time_Clock() - clkStart) / CLOCKS_PER_SEC) break; pNew = pRoot.dupMulti(nFaninMax, nGrowth); @@ -1161,8 +1186,8 @@ Miaig Miaig::rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, ++iterNotImproveAfterRestart; // report - float rootTarget = ((&pRoot)->*Miaig_ObjectiveFunction)(0); - float newTarget = ((&pNew)->*Miaig_ObjectiveFunction)(1); + float rootTarget = ((&pRoot)->*Miaig_ObjectiveFunction)(0, nMappedMode); + float newTarget = ((&pNew)->*Miaig_ObjectiveFunction)(1, nMappedMode); if (maxLevel ? pNew.countLevel() > maxLevel : 0) { } else if (PrevBest > newTarget) { if (nVerbose) printf("%5g (AND2 = %5g Level = %3d) ", newTarget, pNew.countAnd2(), pNew.countLevel()); diff --git a/src/opt/rar/rewire_miaig.h b/src/opt/rar/rewire_miaig.h index 6b9aed37d..7cec02054 100644 --- a/src/opt/rar/rewire_miaig.h +++ b/src/opt/rar/rewire_miaig.h @@ -257,8 +257,9 @@ private: int *hashLookup(int *pTable, int l0, int l1, int TableSize); public: - float countAnd2(int reset = 0); - float countTransistors(int reset = 0); + float countAnd2(int reset = 0, int fDummy = 0); + // 0: amap 1: &nf 2: &simap + float countTransistors(int reset = 0, int nMode = 0); int countLevel(void); private: @@ -285,7 +286,7 @@ public: Miaig reduce(int fVerbose); Miaig expandThenReduce(int nFaninAddLimit, int nDist, int nExpandableLevel, int fVerbose); Miaig expandShareReduce(int nFaninAddLimitAll, int nDivs, int nDist, int nExpandableLevel, int nVerbose); - Miaig rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nVerbose); + Miaig rewire(int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nVerbose); #ifdef RW_ABC Gia_Man_t *toGia(void); Abc_Ntk_t *toNtk(int fMapped = 0); @@ -462,7 +463,7 @@ inline int Miaig::nWords(void) { return _data->nWords; } -inline float Miaig::countAnd2(int reset) { +inline float Miaig::countAnd2(int reset, int fDummy) { int i, Counter = 0; Miaig_ForEachNode(i) { Counter += objFaninNum(i) - 1; diff --git a/src/opt/rar/rewire_rar.c b/src/opt/rar/rewire_rar.c index 3a4ed2b65..c9c23f6d3 100644 --- a/src/opt/rar/rewire_rar.c +++ b/src/opt/rar/rewire_rar.c @@ -22,16 +22,16 @@ ABC_NAMESPACE_IMPL_START -Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return Gia_ManRewireInt(pGia, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + return Gia_ManRewireInt(pGia, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, nSeed, fVerbose); } -Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return Abc_ManRewireInt(pNtk, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + return Abc_ManRewireInt(pNtk, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, nSeed, fVerbose); } -Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose) { - return MiniAig_ManRewireInt(pAig, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nDist, nSeed, fVerbose); +Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose) { + return MiniAig_ManRewireInt(pAig, nIters, levelGrowRatio, nExpands, nGrowth, nDivs, nFaninMax, nTimeOut, nMode, nMappedMode, nDist, nSeed, fVerbose); } ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/opt/rar/rewire_rar.h b/src/opt/rar/rewire_rar.h index 76a1b2e78..dfe47712f 100644 --- a/src/opt/rar/rewire_rar.h +++ b/src/opt/rar/rewire_rar.h @@ -35,12 +35,12 @@ ABC_NAMESPACE_HEADER_START -Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); -Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nDist, int nSeed, int fVerbose); +Gia_Man_t *Gia_ManRewire(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); +Gia_Man_t *Gia_ManRewireInt(Gia_Man_t *pGia, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); +Abc_Ntk_t *Abc_ManRewire(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); +Abc_Ntk_t *Abc_ManRewireInt(Abc_Ntk_t *pNtk, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); +Mini_Aig_t *MiniAig_ManRewire(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); +Mini_Aig_t *MiniAig_ManRewireInt(Mini_Aig_t *pAig, int nIters, float levelGrowRatio, int nExpands, int nGrowth, int nDivs, int nFaninMax, int nTimeOut, int nMode, int nMappedMode, int nDist, int nSeed, int fVerbose); ABC_NAMESPACE_HEADER_END From e20cbd61203d61ca2cc2be6841a3f72104c9abae Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 17 Mar 2025 16:10:22 -0700 Subject: [PATCH 15/42] Updating command "cone" to extract a comma-separated list of outputs. --- src/base/abc/abcNtk.c | 56 +++++++++++++++++++++++++++-- src/base/abci/abc.c | 82 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 120 insertions(+), 18 deletions(-) diff --git a/src/base/abc/abcNtk.c b/src/base/abc/abcNtk.c index c9eeb79c6..5ea38cc12 100644 --- a/src/base/abc/abcNtk.c +++ b/src/base/abc/abcNtk.c @@ -1727,6 +1727,58 @@ void Abc_NtkMakeSeq( Abc_Ntk_t * pNtk, int nLatchesToAdd ) } +/**Function************************************************************* + + Synopsis [Keeps POs in the array.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Abc_Ntk_t * Abc_NtkSelectPos( Abc_Ntk_t * pNtkInit, Vec_Int_t * vPoIds ) +{ + Abc_Ntk_t * pNtk; + Vec_Ptr_t * vPosLeft; + Vec_Ptr_t * vCosLeft; + Abc_Obj_t * pNodePo; + int i, Index; + assert( !Abc_NtkIsNetlist(pNtkInit) ); + assert( Abc_NtkHasOnlyLatchBoxes(pNtkInit) ); + pNtk = Abc_NtkDup( pNtkInit ); + if ( Abc_NtkPoNum(pNtk) == 1 ) + return pNtk; + vPosLeft = Vec_PtrAlloc( Vec_IntSize(vPoIds) ); + Vec_IntForEachEntry( vPoIds, Index, i ) { + Vec_PtrPush( vPosLeft, Abc_NtkPo(pNtk, Index) ); + Vec_PtrWriteEntry( pNtk->vPos, Index, NULL ); + } + // filter COs + vCosLeft = Vec_PtrDup( vPosLeft ); + for ( i = Abc_NtkPoNum(pNtk); i < Abc_NtkCoNum(pNtk); i++ ) + Vec_PtrPush( vCosLeft, Abc_NtkCo(pNtk, i) ); + // remove remaiing POs + Abc_NtkForEachPo( pNtk, pNodePo, i ) + if ( pNodePo ) + Abc_NtkDeleteObjPo( pNodePo ); + // update arrays + Vec_PtrFree( pNtk->vPos ); pNtk->vPos = vPosLeft; + Vec_PtrFree( pNtk->vCos ); pNtk->vCos = vCosLeft; + // clean the network + if ( Abc_NtkIsStrash(pNtk) ) { + Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc ); + if ( Abc_NtkLatchNum(pNtk) ) printf( "Run sequential cleanup (\"scl\") to get rid of dangling logic.\n" ); + } + else { + if ( Abc_NtkLatchNum(pNtk) ) printf( "Run sequential cleanup (\"st; scl\") to get rid of dangling logic.\n" ); + } + if ( !Abc_NtkCheck( pNtk ) ) + fprintf( stdout, "Abc_NtkMakeComb(): Network check has failed.\n" ); + return pNtk; +} + /**Function************************************************************* Synopsis [Removes all POs, except one.] @@ -1779,11 +1831,11 @@ Abc_Ntk_t * Abc_NtkMakeOnePo( Abc_Ntk_t * pNtkInit, int Output, int nRange ) if ( Abc_NtkIsStrash(pNtk) ) { Abc_AigCleanup( (Abc_Aig_t *)pNtk->pManFunc ); - printf( "Run sequential cleanup (\"scl\") to get rid of dangling logic.\n" ); + if ( Abc_NtkLatchNum(pNtk) ) printf( "Run sequential cleanup (\"scl\") to get rid of dangling logic.\n" ); } else { - printf( "Run sequential cleanup (\"st; scl\") to get rid of dangling logic.\n" ); + if ( Abc_NtkLatchNum(pNtk) ) printf( "Run sequential cleanup (\"st; scl\") to get rid of dangling logic.\n" ); } if ( !Abc_NtkCheck( pNtk ) ) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6a435a5d6..0da06dba9 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -13080,6 +13080,16 @@ usage: return 1; } +Vec_Int_t * Vec_IntReadList( char * pStr, char Separ ) +{ + Vec_Int_t * vRes = Vec_IntAlloc( 10 ); + Vec_IntPush( vRes, atoi(pStr) ); + for ( int c = 0; c < strlen(pStr); c++ ) + if ( pStr[c] == Separ ) + Vec_IntPush( vRes, atoi(pStr+c+1) ); + return vRes; +} + /**Function************************************************************* Synopsis [] @@ -13095,24 +13105,23 @@ int Abc_CommandCone( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Ntk_t * pNtk, * pNtkRes; Abc_Obj_t * pNode, * pNodeCo; + Vec_Int_t * vPoIds = NULL; int c; int fUseAllCis; int fUseMffc; - int fSeq; int Output; int nRange; - extern Abc_Ntk_t * Abc_NtkMakeOnePo( Abc_Ntk_t * pNtk, int Output, int nRange ); + extern Abc_Ntk_t * Abc_NtkSelectPos( Abc_Ntk_t * pNtkInit, Vec_Int_t * vPoIds ); pNtk = Abc_FrameReadNtk(pAbc); // set defaults fUseAllCis = 0; fUseMffc = 0; - fSeq = 0; Output = -1; nRange = -1; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "ORmash" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "ORNmah" ) ) != EOF ) { switch ( c ) { @@ -13138,15 +13147,23 @@ int Abc_CommandCone( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( nRange < 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; + } + vPoIds = Vec_IntReadList( argv[globalUtilOptind], ',' ); + globalUtilOptind++; + if ( vPoIds == NULL ) + goto usage; + break; case 'm': fUseMffc ^= 1; break; case 'a': fUseAllCis ^= 1; break; - case 's': - fSeq ^= 1; - break; case 'h': goto usage; default: @@ -13186,27 +13203,60 @@ int Abc_CommandCone( Abc_Frame_t * pAbc, int argc, char ** argv ) else pNtkRes = Abc_NtkCreateCone( pNtk, pNode, argv[globalUtilOptind], fUseAllCis ); } + else if ( vPoIds ) + { + pNtkRes = Abc_NtkSelectPos( pNtk, vPoIds ); + Vec_IntFree( vPoIds ); + } + else if ( nRange > 0 ) + { + if ( Output == -1 ) + { + Abc_Print( -1, "The starting PO ID is not specified.\n" ); + return 1; + } + if ( Output >= Abc_NtkPoNum(pNtk) ) + { + Abc_Print( -1, "The 0-based output number (%d) is larger than the number of primary outputs (%d).\n", Output, Abc_NtkPoNum(pNtk) ); + return 1; + } assert( vPoIds == NULL ); + vPoIds = Vec_IntAlloc( nRange ); + for ( c = Output; c < Output + nRange; c++ ) + Vec_IntPush( vPoIds, c ); + pNtkRes = Abc_NtkSelectPos( pNtk, vPoIds ); + Vec_IntFree( vPoIds ); + } + else if ( Output >= 0 ) + { + if ( Output >= Abc_NtkPoNum(pNtk) ) + { + Abc_Print( -1, "The 0-based output number (%d) is larger than the number of primary outputs (%d).\n", Output, Abc_NtkPoNum(pNtk) ); + return 1; + } assert( vPoIds == NULL ); + vPoIds = Vec_IntAlloc( 1 ); + Vec_IntPush( vPoIds, Output ); + pNtkRes = Abc_NtkSelectPos( pNtk, vPoIds ); + Vec_IntFree( vPoIds ); + } else { if ( Output == -1 ) { - Abc_Print( -1, "The node is not specified.\n" ); + Abc_Print( -1, "The starting PO ID is not specified.\n" ); return 1; } if ( Output >= Abc_NtkCoNum(pNtk) ) { - Abc_Print( -1, "The 0-based output number (%d) is larger than the number of outputs (%d).\n", Output, Abc_NtkCoNum(pNtk) ); + Abc_Print( -1, "The 0-based output number (%d) is larger than the number of combinational outputs (%d).\n", Output, Abc_NtkCoNum(pNtk) ); return 1; } pNodeCo = Abc_NtkCo( pNtk, Output ); - if ( fSeq ) - pNtkRes = Abc_NtkMakeOnePo( pNtk, Output, nRange ); - else if ( fUseMffc ) + if ( fUseMffc ) pNtkRes = Abc_NtkCreateMffc( pNtk, Abc_ObjFanin0(pNodeCo), Abc_ObjName(pNodeCo) ); else pNtkRes = Abc_NtkCreateCone( pNtk, Abc_ObjFanin0(pNodeCo), Abc_ObjName(pNodeCo), fUseAllCis ); } - if ( pNodeCo && Abc_ObjFaninC0(pNodeCo) && !fSeq ) + if ( pNodeCo && Abc_ObjFaninC0(pNodeCo) ) { Abc_NtkPo(pNtkRes, 0)->fCompl0 ^= 1; // Abc_Print( -1, "The extracted cone represents the complement function of the CO.\n" ); @@ -13221,14 +13271,14 @@ int Abc_CommandCone( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: cone [-OR num] [-amsh] \n" ); - Abc_Print( -2, "\t replaces the current network by one logic cone\n" ); + Abc_Print( -2, "usage: cone [-ORN num] [-amh] \n" ); + Abc_Print( -2, "\t replaces the current network by one or more logic cones\n" ); Abc_Print( -2, "\t-a : toggle keeping all CIs or structral support only [default = %s]\n", fUseAllCis? "all": "structural" ); Abc_Print( -2, "\t-m : toggle keeping only MFFC or complete TFI cone [default = %s]\n", fUseMffc? "MFFC": "TFI cone" ); - Abc_Print( -2, "\t-s : toggle comb or sequential cone (works with \"-O num\") [default = %s]\n", fSeq? "seq": "comb" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\t-O num : (optional) the 0-based number of the CO to extract\n"); Abc_Print( -2, "\t-R num : (optional) the number of outputs to extract\n"); + Abc_Print( -2, "\t-N : (optional) a comma-separated list of zero-based primary output indexes\n"); Abc_Print( -2, "\tname : (optional) the name of the node to extract\n"); return 1; } From 59a7cc5c9ce800e1d3e7e261d84a1242bfdead98 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 17 Mar 2025 17:12:01 -0700 Subject: [PATCH 16/42] Removing intermediate files in exact synthesis. --- src/sat/bmc/bmcMaj.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 7cd138c5f..998215ae9 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -2305,6 +2305,7 @@ Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn if ( vValues ) Exa_ManMiniVerify( pMini, vSimsIn, vSimsOut ); Vec_IntFreeP( &vValues ); Exa4_ManFree( p ); + unlink( pFileNameIn ); Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); return pMini; } @@ -2831,6 +2832,7 @@ Mini_Aig_t * Exa5_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn if ( vValues ) Exa_ManMiniVerify( pMini, vSimsIn, vSimsOut ); Vec_IntFreeP( &vValues ); Exa5_ManFree( p ); + unlink( pFileNameIn ); Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); return pMini; } @@ -3752,6 +3754,7 @@ Mini_Aig_t * Exa6_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn if ( vValues && nIns <= 6 ) Exa_ManMiniVerify( pMini, vSimsIn, vSimsOut ); Vec_IntFreeP( &vValues ); Exa6_ManFree( p ); + unlink( pFileNameIn ); Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); return pMini; } @@ -4056,6 +4059,7 @@ void Exa_ManExactSynthesis7( Bmc_EsPar_t * pPars, int GateSize ) if ( vValues ) Exa_ManDumpVerilog( vValues, pPars->nVars, pPars->nNodes, GateSize, pTruth ); Vec_IntFreeP( &vValues ); + unlink( pFileNameIn ); Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); } From 30c952ed22d28854bd0bd33ee4ca505803b7c012 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 17 Mar 2025 17:17:48 -0700 Subject: [PATCH 17/42] Remove structural choices after mapping. --- src/aig/gia/giaNf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/aig/gia/giaNf.c b/src/aig/gia/giaNf.c index f70a63135..8bcf76b33 100644 --- a/src/aig/gia/giaNf.c +++ b/src/aig/gia/giaNf.c @@ -2674,6 +2674,9 @@ Gia_Man_t * Nf_ManPerformMapping( Gia_Man_t * p, Jf_Par_t * pPars ) pNew = Nf_ManPerformMappingInt( p, pPars ); Gia_ManTransferTiming( pNew, p ); //Gia_ManCellMappingVerify( pNew ); + // remove choices after mapping + ABC_FREE( pNew->pReprs ); + ABC_FREE( pNew->pNexts ); } //pNew->MappedDelay = (int)((If_Par_t *)pp)->FinalDelay; //pNew->MappedArea = (int)((If_Par_t *)pp)->FinalArea; From 2078b3945b8b7743ebda76494c5daffa46cacf46 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Mar 2025 07:55:28 -0700 Subject: [PATCH 18/42] Adding support for the random seed to the recent experiments. --- src/aig/gia/giaSatLut.c | 23 ++++++++++++++--------- src/base/abci/abc.c | 40 ++++++++++++++++++++++++++++++---------- src/opt/rar/rewire_map.c | 4 ++-- src/sat/bmc/bmcMaj.c | 4 ++-- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index ee63d77ad..df92030b9 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1234,7 +1234,7 @@ void Gia_ManLutSat( Gia_Man_t * pGia, int LutSize, int nNumber, int nImproves, i SeeAlso [] ***********************************************************************/ -Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ) +Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int Seed, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ) { extern Vec_Int_t * Exa4_ManParse( char *pFileName ); int fVerboseSolver = 0; @@ -1244,19 +1244,24 @@ Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimi char * pKadical = "kadical.exe"; #else char * pKadical = "./kadical"; + FILE * pFile = fopen( pKadical, "rb" ); + if ( pFile == NULL ) + pKadical += 2; + else + fclose( pFile ); #endif char Command[1000], * pCommand = (char *)&Command; if ( nBTLimit ) { if ( TimeOut ) - sprintf( pCommand, "%s -c %d -t %d %s %s > %s", pKadical, nBTLimit, TimeOut, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); + sprintf( pCommand, "%s --seed=%d -c %d -t %d %s %s > %s", pKadical, Seed, nBTLimit, TimeOut, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); else - sprintf( pCommand, "%s -c %d %s %s > %s", pKadical, nBTLimit, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); + sprintf( pCommand, "%s --seed=%d -c %d %s %s > %s", pKadical, Seed, nBTLimit, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); } else { if ( TimeOut ) - sprintf( pCommand, "%s -t %d %s %s > %s", pKadical, TimeOut, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); + sprintf( pCommand, "%s --seed=%d -t %d %s %s > %s", pKadical, Seed, TimeOut, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); else - sprintf( pCommand, "%s %s %s > %s", pKadical, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); + sprintf( pCommand, "%s --seed=%d %s %s > %s", pKadical, Seed, fVerboseSolver ? "": "-q", pFileNameIn, pFileNameOut ); } #ifdef __wasm if ( 1 ) @@ -1564,7 +1569,7 @@ int Gia_ManDumpCnf2( Vec_Str_t * vStr, int nVars, int argc, char ** argv, abctim fclose( pFile ); return 1; } -int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) +int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int Seed, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) { abctime clkStart = Abc_Clock(); srand(time(NULL)); @@ -1582,7 +1587,7 @@ int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, if ( fVerbose ) printf( "SAT variables = %d. SAT clauses = %d. Cardinality bound = %d. Conflict limit = %d. Timeout = %d.\n", nVars, Vec_StrCountEntry(vStr, '\n'), nBound, nBTLimit, nTimeout ); - Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, fVerbose, &Status ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, Seed, nBTLimit, nTimeout, fVerbose, &Status ); unlink( pFileNameI ); //unlink( pFileNameO ); if ( fKeepFile ) Gia_ManDumpCnf2( vStr, nVars, argc, argv, Abc_Clock() - clkStart, Status ); @@ -2000,7 +2005,7 @@ word Gia_ManGetTruth( Gia_Man_t * p ) return Const[Gia_ObjFaninC0(pObj)] ^ pFuncs[Gia_ObjFaninId0p(p, pObj)]; } -Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) +Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) { abctime clkStart = Abc_Clock(); Gia_Man_t * pNew = NULL; @@ -2017,7 +2022,7 @@ Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, in if ( fVerbose ) printf( "Vars = %d. Nodes = %d. Cardinality bound = %d. SAT vars = %d. SAT clauses = %d. Conflict limit = %d. Timeout = %d.\n", nIns, nNodes, nBound, nVars, Vec_StrCountEntry(vStr, '\n'), nBTLimit, nTimeout ); - Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, nBTLimit, nTimeout, 1, &Status ); + Vec_Int_t * vRes = Gia_RunKadical( pFileNameI, pFileNameO, Seed, nBTLimit, nTimeout, 1, &Status ); unlink( pFileNameI ); //unlink( pFileNameO ); if ( fKeepFile ) Gia_ManDumpCnf2( vStr, nVars, argc, argv, Abc_Clock() - clkStart, Status ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0da06dba9..0e898d63c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -44458,10 +44458,10 @@ usage: int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Mio_IntallSimpleLibrary(); - extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); - int c, nBTLimit = 0, nBound = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; + extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int Seed, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); + int c, Seed = 0, nBTLimit = 0, nBound = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "BCTfvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "BRCTfvh" ) ) != EOF ) { switch ( c ) { @@ -44479,6 +44479,15 @@ int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } break; + case 'R': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" ); + goto usage; + } + Seed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'C': if ( globalUtilOptind >= argc ) { @@ -44519,14 +44528,15 @@ int Abc_CommandAbc9Simap( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } Mio_IntallSimpleLibrary(); - if ( !Gia_ManSimpleMapping( pAbc->pGia, nBound, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ) ) + if ( !Gia_ManSimpleMapping( pAbc->pGia, nBound, Seed, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ) ) printf( "Simple mapping has failed.\n" ); return 0; usage: - Abc_Print( -2, "usage: &simap [-BCT num] [-fvh]\n" ); + Abc_Print( -2, "usage: &simap [-BRCT num] [-fvh]\n" ); Abc_Print( -2, "\t performs simple mapping of the AIG\n" ); Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); + Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", Seed ); Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); Abc_Print( -2, "\t-f : toggles keeping the intermediate CNF file [default = %s]\n", fKeepFile? "yes": "no" ); @@ -44549,11 +44559,11 @@ usage: int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Mio_IntallSimpleLibrary2(); - extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); + extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); Gia_Man_t * pTemp = NULL; char * pTruth = NULL; word Truth = 0; - int c, nVars = 0, nNodes = 0, nVars2, nBTLimit = 0, nBound = 0, fMultiLevel = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; + int c, nVars = 0, nNodes = 0, nVars2, Seed = 0, nBTLimit = 0, nBound = 0, fMultiLevel = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NBCTmfvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NBRCTmfvh" ) ) != EOF ) { switch ( c ) { @@ -44585,6 +44595,15 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } break; + case 'R': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" ); + goto usage; + } + Seed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'C': if ( globalUtilOptind >= argc ) { @@ -44646,7 +44665,7 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) } nVars2 = Abc_TtReadHex( &Truth, pTruth ); assert( nVars2 == nVars ); - pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, fMultiLevel, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ); + pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, Seed, fMultiLevel, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ); if ( pTemp ) { //Mio_IntallSimpleLibrary2(); Abc_FrameUpdateGia( pAbc, pTemp ); @@ -44654,10 +44673,11 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &exmap [-NBCT num] [-mfvh] \n" ); + Abc_Print( -2, "usage: &exmap [-NBRCT num] [-mfvh] \n" ); Abc_Print( -2, "\t performs simple mapping of the truth table\n" ); Abc_Print( -2, "\t-N num : the number of nodes [default = %d]\n", nNodes ); Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); + Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", Seed ); Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); Abc_Print( -2, "\t-m : toggles using multi-level primitives [default = %s]\n", fMultiLevel? "yes": "no" ); diff --git a/src/opt/rar/rewire_map.c b/src/opt/rar/rewire_map.c index 47621de71..b63da077b 100644 --- a/src/opt/rar/rewire_map.c +++ b/src/opt/rar/rewire_map.c @@ -33,7 +33,7 @@ extern void Nf_ManSetDefaultPars( Jf_Par_t * pPars ); extern Gia_Man_t * Nf_ManPerformMapping( Gia_Man_t * pGia, Jf_Par_t * pPars ); extern Abc_Ntk_t * Abc_NtkFromMappedGia( Gia_Man_t * p, int fFindEnables, int fUseBuffs ); extern Abc_Ntk_t * Abc_NtkFromCellMappedGia( Gia_Man_t * p, int fUseBuffs ); -extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); +extern int Gia_ManSimpleMapping( Gia_Man_t * p, int nBound, int Seed, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); Abc_Ntk_t *Gia_ManRewirePut(Gia_Man_t *pGia) { Aig_Man_t *pMan = Gia_ManToAig(pGia, 0); @@ -67,7 +67,7 @@ Abc_Ntk_t *Gia_ManRewireMapNf(Gia_Man_t *pGia) { } Abc_Ntk_t *Gia_ManRewireMapSimap(Gia_Man_t *pGia, int nBound, int nBTLimit, int nTimeout) { - if (!Gia_ManSimpleMapping(pGia, nBound, nBTLimit, nTimeout, 0, 0, 0, NULL)) { + if (!Gia_ManSimpleMapping(pGia, nBound, 0, nBTLimit, nTimeout, 0, 0, 0, NULL)) { // Abc_Print(-1, "Mapping has failed.\n"); return NULL; } diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 998215ae9..ca11102bf 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -2280,7 +2280,7 @@ Mini_Aig_t * Exa4_ManMiniAig( Exa4_Man_t * p, Vec_Int_t * vValues, int fFancy ) ***********************************************************************/ Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard ) { - extern Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ); + extern Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int Seed, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ); Mini_Aig_t * pMini = NULL; abctime clkTotal = Abc_Clock(); Vec_Int_t * vValues = NULL; @@ -2296,7 +2296,7 @@ Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn if ( fVerbose ) printf( "CNF with %d variables and %d clauses was dumped into file \"%s\".\n", p->nCnfVars, p->nCnfClauses, pFileNameIn ); if ( fCard ) - vValues = Gia_RunKadical( pFileNameIn, pFileNameOut, 0, TimeOut, fVerbose, &Status ); + vValues = Gia_RunKadical( pFileNameIn, pFileNameOut, 0, 0, TimeOut, fVerbose, &Status ); else vValues = Exa4_ManSolve( pFileNameIn, pFileNameOut, TimeOut, fVerbose ); if ( vValues ) pMini = Exa4_ManMiniAig( p, vValues, fFancy ); From e7dd9151b1020a8c0612d769abe7096b362ee689 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Mar 2025 17:51:40 -0700 Subject: [PATCH 19/42] Adding structural guidance. --- src/aig/gia/giaSatLut.c | 53 ++++++++++++++++++++++++++++++++++++---- src/aig/gia/giaSimBase.c | 4 +-- src/base/abci/abc.c | 34 ++++++++++++++++++++------ src/sat/bmc/bmc.h | 1 + src/sat/bmc/bmcMaj.c | 33 +++++++++++++++++++------ 5 files changed, 103 insertions(+), 22 deletions(-) diff --git a/src/aig/gia/giaSatLut.c b/src/aig/gia/giaSatLut.c index df92030b9..cc6068a96 100644 --- a/src/aig/gia/giaSatLut.c +++ b/src/aig/gia/giaSatLut.c @@ -1683,12 +1683,54 @@ int Gia_KSatFindFan( int * pMap, int i, int f, Vec_Int_t * vRes ) return -1; } -Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound, int fMultiLevel ) +Vec_Int_t * Gia_ManKSatGenLevels( char * pGuide, int nIns, int nNodes ) +{ + Vec_Int_t * vRes; + int i, k, Count = 0; + for ( i = 0; pGuide[i]; i++ ) + Count += pGuide[i] - '0'; + if ( Count != nNodes ) { + printf( "Guidance %s has %d nodes while the problem has %d nodes.\n", pGuide, Count, nNodes ); + return NULL; + } + int FirstPrev = 0; + int FirstThis = nIns; + int FirstNext = FirstThis; + vRes = Vec_IntStartFull( 2*nIns ); + for ( i = 0; pGuide[i]; i++ ) { + FirstNext += pGuide[i] - '0'; + for ( k = FirstThis; k < FirstNext; k++ ) + Vec_IntPushTwo( vRes, FirstPrev, FirstThis ); + FirstPrev = FirstThis; + FirstThis = FirstNext; + } + assert( Vec_IntSize(vRes) == 2*(nIns + nNodes) ); + Count = 0; + //int Start, Stop; + //Vec_IntForEachEntryDouble(vRes, Start, Stop, i) + // printf( "%2d : Start %2d Stop %2d\n", Count++, Start, Stop ); + return vRes; +} + +Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound, int fMultiLevel, char * pGuide ) { Vec_Str_t * vStr = Vec_StrAlloc( 10000 ); - int i, j, m, n, f, c, a, nLits = 0, pLits[256] = {0}; + Vec_Int_t * vRes = pGuide ? Gia_ManKSatGenLevels( pGuide, nIns, nNodes ) : NULL; + int i, j, m, n, f, c, a, Start, Stop, nLits = 0, pLits[256] = {0}; Gia_SatDumpLiteral( vStr, 1 ); - Gia_SatDumpLiteral( vStr, 2 ); + Gia_SatDumpLiteral( vStr, 2 ); + if ( vRes ) { + n = nIns; + Vec_IntForEachEntryDoubleStart( vRes, Start, Stop, i, 2*nIns ) { + for ( j = 0; j < Start; j++ ) + Gia_SatDumpLiteral( vStr, Abc_Var2Lit( Gia_KSatVarFan(pMap, n, 1, j), 1 ) ); + for ( f = 0; f < 2; f++ ) + for ( j = Stop; j < n; j++ ) + Gia_SatDumpLiteral( vStr, Abc_Var2Lit( Gia_KSatVarFan(pMap, n, f, j), 1 ) ); + n++; + } + assert( n == nIns + nNodes ); + } // fanins are connected once for ( n = nIns; n < nIns+nNodes; n++ ) for ( f = 0; f < 2; f++ ) { @@ -1854,6 +1896,7 @@ Vec_Str_t * Gia_ManKSatCnf( int * pMap, int nIns, int nNodes, int nBound, int fM Gia_SatDumpClause( vStr, pLits, nLits ); } Vec_StrPush( vStr, '\0' ); + Vec_IntFreeP( &vRes ); return vStr; } @@ -2005,7 +2048,7 @@ word Gia_ManGetTruth( Gia_Man_t * p ) return Const[Gia_ObjFaninC0(pObj)] ^ pFuncs[Gia_ObjFaninId0p(p, pObj)]; } -Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ) +Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv, char * pGuide ) { abctime clkStart = Abc_Clock(); Gia_Man_t * pNew = NULL; @@ -2014,7 +2057,7 @@ Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, in char pFileNameI[32]; sprintf( pFileNameI, "_%06x_.cnf", Rand ); char pFileNameO[32]; sprintf( pFileNameO, "_%06x_.out", Rand ); int nVars = 0, * pMap = Gia_KSatMapInit( nIns, nNodes, Truth, &nVars ); - Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound/2, fMultiLevel ); + Vec_Str_t * vStr = Gia_ManKSatCnf( pMap, nIns, nNodes, nBound/2, fMultiLevel, pGuide ); if ( !Gia_ManDumpCnf(pFileNameI, vStr, nVars) ) { Vec_StrFree( vStr ); return NULL; diff --git a/src/aig/gia/giaSimBase.c b/src/aig/gia/giaSimBase.c index e5cf77dcb..b5c3c0802 100644 --- a/src/aig/gia/giaSimBase.c +++ b/src/aig/gia/giaSimBase.c @@ -3199,7 +3199,7 @@ Vec_Int_t * Gia_ManRelDeriveSimple( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t void Gia_ManRelSolve( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t * vIns, Vec_Int_t * vOuts, Vec_Int_t * vRel, Vec_Int_t * vDivs ) { - extern Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard ); + extern Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard, char * pGuide ); int i, m, iObj, Entry, iMint = 0, nMints = Vec_IntSize(vRel) - Vec_IntCountEntry(vRel, -1); Vec_Wrd_t * vSimsIn = Vec_WrdStart( nMints ); @@ -3232,7 +3232,7 @@ void Gia_ManRelSolve( Gia_Man_t * p, Vec_Wrd_t * vSims, Vec_Int_t * vIns, Vec_In } assert( iMint == nMints ); printf( "Created %d minterms.\n", iMint ); - Exa4_ManGenTest( vSimsIn, vSimsOut, Vec_IntSize(vIns), Vec_IntSize(vDivs), Vec_IntSize(vOuts), 10, 0, 0, 0, 0, 0, 1, 0 ); + Exa4_ManGenTest( vSimsIn, vSimsOut, Vec_IntSize(vIns), Vec_IntSize(vDivs), Vec_IntSize(vOuts), 10, 0, 0, 0, 0, 0, 1, 0, NULL ); Vec_WrdFree( vSimsIn ); Vec_WrdFree( vSimsOut ); } diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0e898d63c..faaa6f639 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10061,7 +10061,7 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "INTGabdconugklmvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "INTGSabdconugklmvh" ) ) != EOF ) { switch ( c ) { @@ -10109,6 +10109,15 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( GateSize < 0 ) goto usage; break; + case 'S': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-S\" should be followed by a file name.\n" ); + goto usage; + } + pPars->pGuide = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'a': pPars->fOnlyAnd ^= 1; break; @@ -10193,12 +10202,13 @@ int Abc_CommandTwoExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: twoexact [-INTG ] [-abdconugklmvh] \n" ); + Abc_Print( -2, "usage: twoexact [-INTG ] [-S str] [-abdconugklmvh] \n" ); Abc_Print( -2, "\t exact synthesis of multi-input function using two-input gates\n" ); Abc_Print( -2, "\t-I : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-N : the number of two-input nodes [default = %d]\n", pPars->nNodes ); Abc_Print( -2, "\t-T : the runtime limit in seconds [default = %d]\n", pPars->RuntimeLim ); Abc_Print( -2, "\t-G : the largest allowed gate size (NANDs only) [default = %d]\n", GateSize ); + Abc_Print( -2, "\t-S : structural guidance from the user [default = %s]\n", pPars->pGuide ? pPars->pGuide : "unknown" ); Abc_Print( -2, "\t-a : toggle using only AND-gates (without XOR-gates) [default = %s]\n", pPars->fOnlyAnd ? "yes" : "no" ); Abc_Print( -2, "\t-b : toggle using only NAND-gates [default = %s]\n", fUseNands ? "yes" : "no" ); Abc_Print( -2, "\t-d : toggle using dynamic constraint addition [default = %s]\n", pPars->fDynConstr ? "yes" : "no" ); @@ -44559,11 +44569,11 @@ usage: int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Mio_IntallSimpleLibrary2(); - extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv ); - Gia_Man_t * pTemp = NULL; char * pTruth = NULL; word Truth = 0; + extern Gia_Man_t * Gia_ManKSatMapping( word Truth, int nIns, int nNodes, int nBound, int Seed, int fMultiLevel, int nBTLimit, int nTimeout, int fVerbose, int fKeepFile, int argc, char ** argv, char * pGuide ); + Gia_Man_t * pTemp = NULL; char * pTruth = NULL, * pGuide = NULL; word Truth = 0; int c, nVars = 0, nNodes = 0, nVars2, Seed = 0, nBTLimit = 0, nBound = 0, fMultiLevel = 0, nTimeout = 0, fKeepFile = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NBRCTmfvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NBRCTSmfvh" ) ) != EOF ) { switch ( c ) { @@ -44627,6 +44637,15 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) nTimeout = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'S': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-S\" should be followed by a file name.\n" ); + goto usage; + } + pGuide = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'm': fMultiLevel ^= 1; break; @@ -44665,7 +44684,7 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) } nVars2 = Abc_TtReadHex( &Truth, pTruth ); assert( nVars2 == nVars ); - pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, Seed, fMultiLevel, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv ); + pTemp = Gia_ManKSatMapping( Truth, nVars, nNodes, nBound, Seed, fMultiLevel, nBTLimit, nTimeout, fVerbose, fKeepFile, argc, argv, pGuide ); if ( pTemp ) { //Mio_IntallSimpleLibrary2(); Abc_FrameUpdateGia( pAbc, pTemp ); @@ -44673,13 +44692,14 @@ int Abc_CommandAbc9Exmap( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &exmap [-NBRCT num] [-mfvh] \n" ); + Abc_Print( -2, "usage: &exmap [-NBRCT num] [-S str] [-mfvh] \n" ); Abc_Print( -2, "\t performs simple mapping of the truth table\n" ); Abc_Print( -2, "\t-N num : the number of nodes [default = %d]\n", nNodes ); Abc_Print( -2, "\t-B num : the bound on the solution size [default = %d]\n", nBound ); Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", Seed ); Abc_Print( -2, "\t-C num : the conflict limit [default = %d]\n", nBTLimit ); Abc_Print( -2, "\t-T num : runtime limit in seconds [default = %d]\n", nTimeout ); + Abc_Print( -2, "\t-S str : structural guidance from the user [default = %s]\n", pGuide ? pGuide : "unknown" ); Abc_Print( -2, "\t-m : toggles using multi-level primitives [default = %s]\n", fMultiLevel? "yes": "no" ); Abc_Print( -2, "\t-f : toggles keeping the intermediate CNF file [default = %s]\n", fKeepFile? "yes": "no" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); diff --git a/src/sat/bmc/bmc.h b/src/sat/bmc/bmc.h index 320a85886..233930178 100644 --- a/src/sat/bmc/bmc.h +++ b/src/sat/bmc/bmc.h @@ -70,6 +70,7 @@ struct Bmc_EsPar_t_ int fVerbose; char * pTtStr; char * pSymStr; + char * pGuide; }; static inline void Bmc_EsParSetDefault( Bmc_EsPar_t * pPars ) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index ca11102bf..3440ac514 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1941,9 +1941,25 @@ static inline int Exa4_ManAddClause4( Exa4_Man_t * p, int Lit0, int Lit1, int Li int pLits[4] = { Lit0, Lit1, Lit2, Lit3 }; return Exa4_ManAddClause( p, pLits, 4 ); } -int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard ) +int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard, char * pGuide ) { - int pLits[2*MAJ_NOBJS], i, j, k, n, m, nLits; + extern Vec_Int_t * Gia_ManKSatGenLevels( char * pGuide, int nIns, int nNodes ); + Vec_Int_t * vRes = pGuide ? Gia_ManKSatGenLevels( pGuide, p->nDivs, p->nNodes ) : NULL; + int pLits[2*MAJ_NOBJS], i, j, k, n, m, nLits, Start, Stop; + if ( vRes ) { + n = p->nDivs; + Vec_IntForEachEntryDoubleStart( vRes, Start, Stop, i, 2*p->nDivs ) { + for ( j = 0; j < Start; j++ ) + if ( p->VarMarks[n][0][j] ) + Exa4_ManAddClause4( p, Abc_Var2Lit( p->VarMarks[n][0][j], 1 ), 0, 0, 0 ); + for ( k = 0; k < 2; k++ ) + for ( j = Stop; j < n; j++ ) + if ( p->VarMarks[n][k][j] ) + Exa4_ManAddClause4( p, Abc_Var2Lit( p->VarMarks[n][k][j], 1 ), 0, 0, 0 ); + n++; + } + assert( n == p->nDivs + p->nNodes ); + } for ( i = p->nDivs; i < p->nDivs + p->nNodes; i++ ) { int iVarStart = 1 + 5*(i - p->nDivs);// @@ -2023,6 +2039,7 @@ int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, for ( m = n+1; m < nLits; m++ ) Exa4_ManAddClause4( p, Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), 0, 0 ); } + Vec_IntFreeP( &vRes ); return 1; } void Exa4_ManGenMint( Exa4_Man_t * p, int iMint, int fOnlyAnd, int fFancy ) @@ -2104,13 +2121,13 @@ void Exa4_ManGenMint( Exa4_Man_t * p, int iMint, int fOnlyAnd, int fFancy ) Exa4_ManAddClause4( p, Abc_Var2Lit(p->VarMarks[i][0][j], 1), Abc_LitNotCond(VarVals[j], n), Abc_LitNotCond(VarVals[i], !n), 0); } } -void Exa4_ManGenCnf( Exa4_Man_t * p, char * pFileName, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard ) +void Exa4_ManGenCnf( Exa4_Man_t * p, char * pFileName, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fCard, char * pGuide ) { int m; assert( p->pFile == NULL ); p->pFile = fopen( pFileName, "wb" ); fputs( "p cnf \n", p->pFile ); - Exa4_ManGenStart( p, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard ); + Exa4_ManGenStart( p, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard, pGuide ); for ( m = 1; m < Vec_WrdSize(p->vSimsIn); m++ ) Exa4_ManGenMint( p, m, fOnlyAnd, fFancy ); rewind( p->pFile ); @@ -2278,7 +2295,7 @@ Mini_Aig_t * Exa4_ManMiniAig( Exa4_Man_t * p, Vec_Int_t * vValues, int fFancy ) SeeAlso [] ***********************************************************************/ -Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard ) +Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, int TimeOut, int fOnlyAnd, int fFancy, int fOrderNodes, int fUniqFans, int fVerbose, int fCard, char * pGuide ) { extern Vec_Int_t * Gia_RunKadical( char * pFileNameIn, char * pFileNameOut, int Seed, int nBTLimit, int TimeOut, int fVerbose, int * pStatus ); Mini_Aig_t * pMini = NULL; @@ -2290,7 +2307,7 @@ Mini_Aig_t * Exa4_ManGenTest( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIn char pFileNameOut[32]; sprintf( pFileNameOut, "_%05x_.out", Rand ); Exa4_Man_t * p = Exa4_ManAlloc( vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, fVerbose ); Exa_ManIsNormalized( vSimsIn, vSimsOut ); - Exa4_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard ); + Exa4_ManGenCnf( p, pFileNameIn, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fCard, pGuide ); if ( fVerbose ) printf( "Timeout = %d. OnlyAnd = %d. Fancy = %d. OrderNodes = %d. UniqueFans = %d. Verbose = %d.\n", TimeOut, fOnlyAnd, fFancy, fOrderNodes, fUniqFans, fVerbose ); if ( fVerbose ) @@ -2327,7 +2344,7 @@ void Exa_ManExactSynthesis4_( Bmc_EsPar_t * pPars ) if ( (m >> i) & 1 ) Abc_TtSetBit( Vec_WrdEntryP(vSimsIn, m), 1+i ); } - pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, 3, 4, 2, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, 0 ); + pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, 3, 4, 2, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, 0, pPars->pGuide ); if ( pMini ) Mini_AigStop( pMini ); Vec_WrdFree( vSimsIn ); Vec_WrdFree( vSimsOut ); @@ -2349,7 +2366,7 @@ void Exa_ManExactSynthesis4( Bmc_EsPar_t * pPars ) Abc_TtSetBit( Vec_WrdEntryP(vSimsIn, m), 1+i ); } assert( Vec_WrdSize(vSimsIn) == (1 << pPars->nVars) ); - pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, pPars->nVars, 1+pPars->nVars, 1, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, pPars->fCard ); + pMini = Exa4_ManGenTest( vSimsIn, vSimsOut, pPars->nVars, 1+pPars->nVars, 1, pPars->nNodes, pPars->RuntimeLim, pPars->fOnlyAnd, pPars->fFewerVars, pPars->fOrderNodes, pPars->fUniqFans, pPars->fVerbose, pPars->fCard, pPars->pGuide ); if ( pMini ) Mini_AigStop( pMini ); if ( fCompl ) printf( "The resulting circuit, if computed, will be complemented.\n" ); Vec_WrdFree( vSimsIn ); From 8ffca32372178de8726c2d5d21ef631061fcc15f Mon Sep 17 00:00:00 2001 From: Franz Reichl Date: Wed, 19 Mar 2025 11:29:14 +0100 Subject: [PATCH 20/42] Add command &eslim --- Makefile | 2 +- abclib.dsp | 40 ++ src/base/abci/abc.c | 160 +++++++ src/opt/eslim/eSLIM.cpp | 182 ++++++++ src/opt/eslim/eSLIM.h | 59 +++ src/opt/eslim/eSLIMMan.hpp | 98 +++++ src/opt/eslim/eSLIMMan.tpp | 514 ++++++++++++++++++++++ src/opt/eslim/module.make | 2 + src/opt/eslim/relationGeneration.cpp | 172 ++++++++ src/opt/eslim/relationGeneration.hpp | 107 +++++ src/opt/eslim/satInterfaces.hpp | 196 +++++++++ src/opt/eslim/selectionStrategy.hpp | 154 +++++++ src/opt/eslim/selectionStrategy.tpp | 231 ++++++++++ src/opt/eslim/synthesisEngine.hpp | 240 +++++++++++ src/opt/eslim/synthesisEngine.tpp | 621 +++++++++++++++++++++++++++ src/opt/eslim/utils.hpp | 103 +++++ 16 files changed, 2880 insertions(+), 1 deletion(-) create mode 100644 src/opt/eslim/eSLIM.cpp create mode 100644 src/opt/eslim/eSLIM.h create mode 100644 src/opt/eslim/eSLIMMan.hpp create mode 100644 src/opt/eslim/eSLIMMan.tpp create mode 100644 src/opt/eslim/module.make create mode 100644 src/opt/eslim/relationGeneration.cpp create mode 100644 src/opt/eslim/relationGeneration.hpp create mode 100644 src/opt/eslim/satInterfaces.hpp create mode 100644 src/opt/eslim/selectionStrategy.hpp create mode 100644 src/opt/eslim/selectionStrategy.tpp create mode 100644 src/opt/eslim/synthesisEngine.hpp create mode 100644 src/opt/eslim/synthesisEngine.tpp create mode 100644 src/opt/eslim/utils.hpp diff --git a/Makefile b/Makefile index a546f65fd..50cff2d17 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ MODULES := \ src/misc/mem src/misc/bar src/misc/bbl src/misc/parse \ src/opt/cut src/opt/fxu src/opt/fxch src/opt/rwr src/opt/mfs src/opt/sim \ src/opt/ret src/opt/fret src/opt/res src/opt/lpk src/opt/nwk src/opt/rwt src/opt/rar \ - src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd \ + src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd src/opt/eslim \ src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 src/sat/kissat src/sat/cadical \ src/bool/bdc src/bool/deco src/bool/dec src/bool/kit src/bool/lucky \ src/bool/rsb src/bool/rpo \ diff --git a/abclib.dsp b/abclib.dsp index 921030b34..2bcb6e1b8 100644 --- a/abclib.dsp +++ b/abclib.dsp @@ -4114,6 +4114,46 @@ SOURCE=.\src\opt\sbd\sbdSat.c SOURCE=.\src\opt\sbd\sbdWin.c # End Source File # End Group +# Begin Group "eslim" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\opt\eslim\eSLIM.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\eSLIM.h +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\eSLIMMan.hpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\relationGeneration.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\relationGeneration.hpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\satInterfaces.hpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\selectionStrategy.hpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\utils.hpp +# End Source File +# Begin Source File + +SOURCE=.\src\opt\eslim\synthesisEngine.hpp +# End Source File +# End Group # End Group # Begin Group "map" diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index faaa6f639..8ceb65167 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -65,6 +65,7 @@ #include "opt/nwk/nwkMerge.h" #include "base/acb/acbPar.h" #include "misc/extra/extra.h" +#include "opt/eslim/eSLIM.h" #ifndef _WIN32 @@ -637,6 +638,8 @@ static int Abc_CommandAbc9MulFind ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9Test ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9eSLIM ( Abc_Frame_t * pAbc, int argc, char ** argv ); + extern int Abc_CommandAbcLivenessToSafety ( Abc_Frame_t * pAbc, int argc, char ** argv ); extern int Abc_CommandAbcLivenessToSafetySim ( Abc_Frame_t * pAbc, int argc, char ** argv ); extern int Abc_CommandAbcLivenessToSafetyWithLTL( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1451,6 +1454,8 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&mulfind", Abc_CommandAbc9MulFind, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 ); + + Cmd_CommandAdd( pAbc, "ABC9", "&eslim", Abc_CommandAbc9eSLIM, 0 ); { // extern Mf_ManTruthCount(); // Mf_ManTruthCount(); @@ -56445,6 +56450,161 @@ usage: return 1; } +int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { + extern void seteSLIMParams(eSLIM_ParamStruct* params); + extern Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params); + extern Gia_Man_t* applyeSLIMIncremental(Gia_Man_t * pGia, const eSLIM_ParamStruct* params, unsigned int restarts, unsigned int deepsynTimeout); + + int nruns = 0; + int deepsynTimeout = 180; + int runOneShotMode = 0; + eSLIM_ParamStruct params; + int c; + Gia_Man_t * pTemp; + seteSLIMParams(¶ms); + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "DIPRSTVZfhnos" ) ) != EOF ) { + switch ( c ) { + case 'D': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-D\" should be followed by an integer.\n" ); + goto usage; + } + deepsynTimeout = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( deepsynTimeout < 1 ) + goto usage; + break; + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by an integer.\n" ); + goto usage; + } + params.iterations = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.iterations < 0 ) + goto usage; + break; + case 'P': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-P\" should be followed by a float.\n" ); + goto usage; + } + params.expansion_probability = atof(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.expansion_probability < 0 ) + goto usage; + break; + case 'R': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" ); + goto usage; + } + nruns = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nruns < 0 ) + goto usage; + break; + case 'S': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-S\" should be followed by an integer.\n" ); + goto usage; + } + params.subcircuit_size_bound = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.subcircuit_size_bound < 2 ) + goto usage; + break; + case 'T': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-T\" should be followed by an integer.\n" ); + goto usage; + } + params.timeout = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.timeout < 1 ) + goto usage; + break; + case 'V': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-V\" should be followed by an integer.\n" ); + goto usage; + } + params.verbose = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.verbose < 0 || params.verbose > 2 ) + goto usage; + break; + case 'Z': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-Z\" should be followed by an integer.\n" ); + goto usage; + } + params.fix_seed = 1; + params.seed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'f' : + params.forbidden_pairs ^= 1; + break; + case 'h': + goto usage; + case 'n' : + params.extended_normality_processing ^= 1; + break; + case 'o' : + runOneShotMode ^= 1; + break; + case 's' : + params.fill_subcircuits ^= 1; + break; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) { + Abc_Print( -1, "Abc_CommandAbc9Test(): There is no AIG.\n" ); + return 1; + } + + if (runOneShotMode) { + pTemp = applyeSLIM(pAbc->pGia, ¶ms); + } else { + pTemp = applyeSLIMIncremental(pAbc->pGia, ¶ms, nruns, deepsynTimeout); + } + + Abc_FrameUpdateGia( pAbc, pTemp ); + return 0; + + usage: + Abc_Print( -2, "usage: &eslim [-RTIDSPAV ] [-ch]\n" ); + Abc_Print( -2, "\t circuit minimization using exact synthesis and the SAT-based local improvement method (SLIM)\n" ); + Abc_Print( -2, "\t-D : the timeout in seconds for the individual deepsyn runs [default = %d]\n", deepsynTimeout ); + Abc_Print( -2, "\t-I : the maximal number of iterations (0 = no limit) for the individual eSLIM runs [default = %d]\n", params.iterations ); + Abc_Print( -2, "\t-P : the probability of expanding a node [default = %.2f]\n", params.expansion_probability ); + Abc_Print( -2, "\t-R : the number of runs of eSLIM + Inprocessing [default = %d]\n", nruns ); + Abc_Print( -2, "\t-S : the maximal size of considered subcircuits [default = %d]\n", params.subcircuit_size_bound ); + Abc_Print( -2, "\t-T : the timeout in seconds for the individual eSLIM runs [default = %d]\n", params.timeout ); + Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", params.verbose); + Abc_Print( -2, "\t-Z : use a fixed seed\n", params.seed); + Abc_Print( -2, "\t-f : toggle using subcircuits with forbidden pairs\n"); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t-n : extended normality processing\n"); + Abc_Print( -2, "\t-o : single run of eSLIM without inprocessing\n"); + Abc_Print( -2, "\t-s : fill subcircuits\n"); + Abc_Print( -2, "\t\n" ); + Abc_Print( -2, "\t This command was contributed by Franz-Xaver Reichl from University of Freiburg.\n" ); + return 1; +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/opt/eslim/eSLIM.cpp b/src/opt/eslim/eSLIM.cpp new file mode 100644 index 000000000..142531090 --- /dev/null +++ b/src/opt/eslim/eSLIM.cpp @@ -0,0 +1,182 @@ +/**CFile**************************************************************** + + FileName [eSLIM.cpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Interface to the eSLIM package.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: eSLIM.cpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#include "utils.hpp" +#include "eSLIMMan.hpp" +#include "relationGeneration.hpp" +#include "selectionStrategy.hpp" + +#include "misc/util/abc_namespaces.h" + +#include "eSLIM.h" + +ABC_NAMESPACE_HEADER_START + Gia_Man_t * Gia_ManDeepSyn( Gia_Man_t * pGia, int nIters, int nNoImpr, int TimeOut, int nAnds, int Seed, int fUseTwo, int fVerbose ); +ABC_NAMESPACE_HEADER_END + +ABC_NAMESPACE_IMPL_START + +eSLIM::eSLIMConfig getCfg(const eSLIM_ParamStruct* params) { + eSLIM::eSLIMConfig config; + config.extended_normality_processing = params->extended_normality_processing; + config.apply_strash = params->apply_strash; + config.fill_subcircuits = params->fill_subcircuits; + config.fix_seed = params->fix_seed; + config.trial_limit_active = params->trial_limit_active; + config.timeout = params->timeout; + config.iterations = params->iterations; + config.subcircuit_size_bound = params->subcircuit_size_bound; + config.strash_intervall = params->strash_intervall; + config.nselection_trials = params->nselection_trials; + config.seed = params->seed; + config.verbose = params->verbose; + config.expansion_probability = params->expansion_probability; + return config; +} + +void seteSLIMParams(eSLIM_ParamStruct* params) { + params->forbidden_pairs = 1; + params->extended_normality_processing = 0; + params->fill_subcircuits = 0; + params->apply_strash = 1; + params->fix_seed = 0; + params->trial_limit_active = 1; + params->timeout = 1620; + params->iterations = 0; + params->subcircuit_size_bound = 6; + params->strash_intervall = 100; + params->nselection_trials = 100; + params->mode = 0; + params->seed = 0; + params->verbose = 0; + params->expansion_probability = 0.4; +} + +Gia_Man_t* selectApproach(Gia_Man_t* pGia, eSLIM::eSLIMConfig params, eSLIM::eSLIMLog& log, int approach, bool allow_forbidden_pairs) { + switch (approach) { + case 0 : + if (allow_forbidden_pairs) { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + } else { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + }; + case 1: + if (allow_forbidden_pairs) { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + } else { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + }; + default: + std::cerr << "eSLIM -- Invalid mode given\n"; + assert (false && "Invalid approach selected"); + return nullptr; + } +} + +Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params) { + eSLIM::eSLIMConfig config = getCfg(params); + int initial_size = Gia_ManAndNum(pGia); + Gia_Man_t * temp = Gia_ManDup(pGia); + eSLIM::eSLIMLog log(params->subcircuit_size_bound); + Gia_Man_t* result = selectApproach(temp, config, log, params->mode, params->forbidden_pairs); + if (params->verbose > 0) { + std::cout << "#Iterations with forbidden pairs: " << log.subcircuits_with_forbidden_pairs << "\n"; + int new_size = initial_size - Gia_ManAndNum(result); + std::cout << "#reduced gates: " << new_size << "\n"; + } + return result; + +} + +Gia_Man_t* applyeSLIMIncremental(Gia_Man_t* pGia, const eSLIM_ParamStruct* params, unsigned int restarts, unsigned int deepsynTimeout) { + eSLIM::eSLIMConfig config = getCfg(params); + config.verbose = params->verbose > 1; + + int eSLIM_reductions = 0; + int deepsyn_reductions = 0; + + Gia_Man_t * pThis = Gia_ManDup(pGia); + Gia_Man_t * tmp; + eSLIM::eSLIMLog log(params->subcircuit_size_bound); + int initial_size = Gia_ManAndNum(pThis); + if (params->verbose > 0) { + std::cout << "Initial size: " << initial_size << "\n"; + } + + for (unsigned int i = 0; i <= restarts; i++) { + if (config.fix_seed) { + config.seed = params->seed + i; + } + + int size_iteration_start = Gia_ManAndNum(pThis); + pThis = selectApproach(pThis, config, log, params->mode, params->forbidden_pairs); + int size_eslim = Gia_ManAndNum(pThis); + eSLIM_reductions += size_iteration_start - size_eslim; + if (params->verbose > 0) { + std::cout << "Size eSLIM it-" << i << " : " << size_eslim << "\n"; + } + + tmp = Gia_ManDeepSyn( pThis, 1, ABC_INFINITY, deepsynTimeout, 0, params->seed + i, 0, 0); + int size_deepsyn = Gia_ManAndNum(tmp); + + if ( Gia_ManAndNum(pThis) > Gia_ManAndNum(tmp) ) { + Gia_ManStop( pThis ); + pThis = tmp; + deepsyn_reductions += size_eslim - size_deepsyn; + } else { + Gia_ManStop( tmp ); + } + } + + if (params->verbose > 0) { + std::cout << "#Gates reduced by eSLIM: " << eSLIM_reductions << "\n"; + std::cout << "#Gates reduced by deepsyn: " << deepsyn_reductions << "\n"; + std::cout << "Total #iterations: " << log.iteration_count << "\n"; + std::cout << "Total relation generation time (s): " << log.relation_generation_time << "\n"; + std::cout << "Total synthesis time (s): " << log.synthesis_time << "\n"; + std::cout << "#Iterations with forbidden pairs: " << log.subcircuits_with_forbidden_pairs << "\n"; + + for (int i = 2; i < log.nof_analyzed_circuits_per_size.size(); i++) { + int replaced = log.nof_replaced_circuits_per_size.size() > i ? log.nof_replaced_circuits_per_size[i] : 0; + int reduced = log.nof_reduced_circuits_per_size.size() > i ? log.nof_reduced_circuits_per_size[i] : 0; + std::cout << "#gates: " << i << " - #analysed: " << log.nof_analyzed_circuits_per_size[i] << " - #replaced: " << replaced << " - #reduced: " << reduced << "\n"; + } + } + + if (params->verbose > 1) { + for (int i = 0; i < log.nof_sat_calls_per_size.size(); i++) { + if (log.nof_sat_calls_per_size[i] == 0) { + std::cout << "#gates: " << i << " - avg. sat time: -\n"; + } else { + std::cout << "#gates: " << i << " - avg. sat time: " << static_cast(log.cummulative_sat_runtimes_per_size[i]) / (1000 * log.nof_sat_calls_per_size[i]) << " sec\n"; + } + } + for (int i = 0; i < log.nof_unsat_calls_per_size.size(); i++) { + if (log.nof_unsat_calls_per_size[i] == 0) { + std::cout << "#gates: " << i << " - avg. unsat time: -\n"; + } else { + std::cout << "#gates: " << i << " - avg. unsat time: " << static_cast(log.cummulative_unsat_runtimes_per_size[i]) / (1000* log.nof_unsat_calls_per_size[i]) << " sec\n"; + } + } + } + return pThis; +} + +ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/opt/eslim/eSLIM.h b/src/opt/eslim/eSLIM.h new file mode 100644 index 000000000..1d4bc2175 --- /dev/null +++ b/src/opt/eslim/eSLIM.h @@ -0,0 +1,59 @@ +/**CFile**************************************************************** + + FileName [eSLIM.h] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Interface to the eSLIM package.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: eSLIM.h,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__ESLIM_h +#define ABC__OPT__ESLIM__ESLIM_h + +#include "misc/util/abc_namespaces.h" +#include "aig/gia/gia.h" + +ABC_NAMESPACE_HEADER_START + + typedef struct eSLIM_ParamStruct_ eSLIM_ParamStruct; + struct eSLIM_ParamStruct_ { + int forbidden_pairs; // Allow forbidden pairs in the selected subcircuits + int extended_normality_processing; // Additional checks for non normal subcircuits + double expansion_probability; // the probability that a node is added to the subcircuit + int fill_subcircuits; // If a subcircuit has fewer than subcircuit_size_bound gates, try to fill it with rejected gates. + int apply_strash; + int fix_seed; + int trial_limit_active; + + unsigned int timeout; // available time in seconds (soft limit) + unsigned int iterations; // maximal number of iterations. No limit if 0 + unsigned int subcircuit_size_bound; // upper bound for the subcircuit sizes + unsigned int strash_intervall; + unsigned int nselection_trials; + + int mode; // 0: Cadical Incremental, 1: Kissat Oneshot + int seed; + int verbose; + + }; + + void seteSLIMParams(eSLIM_ParamStruct* params); + + Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params); + Gia_Man_t* applyeSLIMIncremental(Gia_Man_t * pGia, const eSLIM_ParamStruct* params, unsigned int restarts, unsigned int deepsynTimeout); + + +ABC_NAMESPACE_HEADER_END + +#endif \ No newline at end of file diff --git a/src/opt/eslim/eSLIMMan.hpp b/src/opt/eslim/eSLIMMan.hpp new file mode 100644 index 000000000..5a6718099 --- /dev/null +++ b/src/opt/eslim/eSLIMMan.hpp @@ -0,0 +1,98 @@ +/**CFile**************************************************************** + + FileName [eSLIMMan.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [eSLIM manager.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: eSLIMMan.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__ESLIMMAN_h +#define ABC__OPT__ESLIM__ESLIMMAN_h + +#include +#include +#include + +#include "misc/util/abc_namespaces.h" +#include "misc/vec/vec.h" +#include "aig/gia/gia.h" +#include "misc/util/utilTruth.h" // ioResub.h depends on utilTruth.h +#include "base/io/ioResub.h" +#include "aig/miniaig/miniaig.h" + +#include "utils.hpp" +#include "selectionStrategy.hpp" + + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + class eSLIM_Man { + + public: + static Gia_Man_t* applyeSLIM(Gia_Man_t * p, const eSLIMConfig& cfg, eSLIMLog& log); + private: + + eSLIM_Man(Gia_Man_t * gia_man, const eSLIMConfig& cfg, eSLIMLog& log); + Gia_Man_t* getCircuit(); + + void minimize(); + void findReplacement(); + Mini_Aig_t* findMinimumAig(const Subcircuit& subcir); + + Abc_RData_t* generateRelation(const Subcircuit& subcir); + Vec_Int_t* generateRelationPatterns(const Subcircuit& subcir); + Abc_RData_t* constructABCRelationRepresentation(int nof_inputs, int nof_outputs, Vec_Int_t * patterns); + + Vec_Wrd_t* getSimsIn(Abc_RData_t* relation); + Vec_Wrd_t* getSimsOut(Abc_RData_t* relation); + word getAllFalseBehaviour(const Subcircuit& subcir); + bool getAllFalseBehaviourRec(Gia_Obj_t * pObj); + + std::pair reduce( Vec_Wrd_t* vSimsDiv, Vec_Wrd_t* vSimsOut, const std::unordered_map>& forbidden_pairs, + int nVars, int nDivs, int nOuts, int initial_size); + Mini_Aig_t* computeReplacement( SynthesisEngine& syn_man, int size); + double getDynamicTimeout(int size); + + void insertReplacement(Mini_Aig_t* replacement, const Subcircuit& subcir); + std::vector processReplacement(Gia_Man_t* gia_man, Gia_Man_t* pNew, const Subcircuit& subcir, Mini_Aig_t* replacement, std::vector&& to_process, std::vector& replacement_values); + Vec_Int_t * processEncompassing(Gia_Man_t* gia_man, Gia_Man_t* pNew, Vec_Int_t* to_process); + int getInsertionLiteral(Gia_Man_t* gia_man, const Subcircuit& subcir, Mini_Aig_t* replacement, const std::vector& replacement_values, int fanin_lit); + + Gia_Man_t* gia_man = nullptr; + const eSLIMConfig& cfg; + eSLIMLog& log; + SelectionEngine subcircuit_selection; + + double relation_generation_time ; + double synthesis_time ; + + bool stopeSLIM=false; + + }; + + template + inline Gia_Man_t* eSLIM_Man::getCircuit() { + return gia_man; + } +} + +ABC_NAMESPACE_CXX_HEADER_END + +#include "eSLIMMan.tpp" + +#endif \ No newline at end of file diff --git a/src/opt/eslim/eSLIMMan.tpp b/src/opt/eslim/eSLIMMan.tpp new file mode 100644 index 000000000..ae12e2bb7 --- /dev/null +++ b/src/opt/eslim/eSLIMMan.tpp @@ -0,0 +1,514 @@ +/**CFile**************************************************************** + + FileName [eSLIMMan.tpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [eSLIM manager.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: eSLIMMan.tpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "eSLIMMan.hpp" +#include "synthesisEngine.hpp" +#include "relationGeneration.hpp" + + +ABC_NAMESPACE_HEADER_START + Vec_Int_t* Gia_ManGenIoCombs( Gia_Man_t * pGia, Vec_Int_t * vInsOuts, int nIns, int fVerbose ); + Mini_Aig_t * Mini_AigDupCompl( Mini_Aig_t * p, int ComplIns, int ComplOuts ); + int Exa6_ManFindPolar( word First, int nOuts ); + Vec_Wrd_t * Exa6_ManTransformInputs( Vec_Wrd_t * vIns ); + Vec_Wrd_t * Exa6_ManTransformOutputs( Vec_Wrd_t * vOuts, int nOuts ); +ABC_NAMESPACE_HEADER_END + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + Gia_Man_t* eSLIM_Man::applyeSLIM(Gia_Man_t * p, const eSLIMConfig& cfg, eSLIMLog& log) { + eSLIM_Man eslim(p, cfg, log); + eslim.minimize(); + if (cfg.verbose > 0) { + std::cout << "Relation generation time: " << log.relation_generation_time - eslim.relation_generation_time << "\n"; + std::cout << "Synthesis time: " << log.synthesis_time - eslim.synthesis_time << "\n"; + } + return eslim.getCircuit(); + } + + template + eSLIM_Man::eSLIM_Man(Gia_Man_t * pGia, const eSLIMConfig& cfg, eSLIMLog& log) + : gia_man(pGia), cfg(cfg), log(log), + subcircuit_selection(gia_man, cfg, log) { + if (cfg.fix_seed) { + subcircuit_selection.setSeed(cfg.seed); + } + relation_generation_time = log.relation_generation_time; + synthesis_time = log.synthesis_time; + } + + template + void eSLIM_Man::minimize() { + abctime clkStart = Abc_Clock(); + abctime nTimeToStop = clkStart + cfg.timeout * CLOCKS_PER_SEC; + unsigned int iteration = 0; + unsigned int iterMax = cfg.iterations ? cfg.iterations - 1 : UINT_MAX; + while (Abc_Clock() <= nTimeToStop && iteration <= iterMax && !stopeSLIM) { + iteration++; + findReplacement(); + if (Gia_ManHasDangling(gia_man)) { + Gia_Man_t* pTemp = gia_man; + gia_man = Gia_ManCleanup( pTemp ); + Gia_ManStop( pTemp ); + } + if (cfg.apply_strash && iteration % cfg.strash_intervall == 0) { + Gia_Man_t* pTemp = gia_man; + gia_man = Gia_ManRehash( pTemp, 0 ); + Gia_ManStop( pTemp ); + } + } + log.iteration_count += iteration; + + if (cfg.verbose) { + printf( "Time %8.2f sec\n", (float)1.0*(Abc_Clock() - clkStart)/CLOCKS_PER_SEC ); + std::cout << "#Iterations: " << iteration << "\n"; + } + } + + template + Abc_RData_t* eSLIM_Man::generateRelation(const Subcircuit& subcir) { + int nof_outputs = Vec_IntSize(subcir.io) - subcir.nof_inputs; + assert(Vec_IntSize(subcir.io) <= 32); + abctime relation_generation_start = Abc_Clock(); + Vec_Int_t* relation_patterns_masks = generateRelationPatterns(subcir); + log.relation_generation_time += (double)1.0*(Abc_Clock() - relation_generation_start)/CLOCKS_PER_SEC; + Abc_RData_t* relation = constructABCRelationRepresentation(subcir.nof_inputs, nof_outputs, relation_patterns_masks); + Vec_IntFree(relation_patterns_masks); + return relation; + } + + template + Vec_Int_t* eSLIM_Man::generateRelationPatterns(const Subcircuit& subcir) { + Vec_Int_t * vRes = RelationGenerator::computeRelation(gia_man, subcir); + if ( vRes == NULL ) { + return nullptr; + } + return vRes; + } + + template + Abc_RData_t* eSLIM_Man::constructABCRelationRepresentation(int nof_inputs, int nof_outputs, Vec_Int_t * patterns) { + int i, mask; + int nof_vars = nof_inputs + nof_outputs; + Abc_RData_t* p = Abc_RDataStart( nof_inputs, nof_outputs, Vec_IntSize(patterns) ); + Vec_IntForEachEntry( patterns, mask, i ) { + for ( int k = 0; k < nof_vars; k++ ) { + if ( (mask >> (nof_vars-1-k)) & 1 ) { + if ( k < nof_inputs ) { + Abc_RDataSetIn( p, k, i ); + } else { + Abc_RDataSetOut( p, 2*(k-nof_inputs)+1, i ); + } + } else { + if ( k >= nof_inputs ) { + Abc_RDataSetOut( p, 2*(k-nof_inputs), i ); + } + } + } + } + Abc_RData_t* p2 = Abc_RData2Rel(p); + Abc_RDataStop(p); + return p2; + } + + template + Vec_Wrd_t* eSLIM_Man::getSimsIn(Abc_RData_t* relation) { + Vec_Wrd_t* vSimsDiv = Vec_WrdStart( relation->nPats ); + for (int k = 0; k < relation->nIns; k++) { + for (int i = 0; i < relation->nPats; i++) { + if (Abc_RDataGetIn(relation, k, i)) { + // The first bit corresponds to the constant divisor thus we have +1 + Abc_InfoSetBit((unsigned *)Vec_WrdEntryP(vSimsDiv, i), 1+k); + } + } + } + return vSimsDiv; + } + + template + Vec_Wrd_t* eSLIM_Man::getSimsOut(Abc_RData_t* relation) { + Vec_Wrd_t* vSimsOut = Vec_WrdStart(relation->nPats); + for (int k = 0; k < (1 << relation->nOuts); k++) { + for (int i = 0; i < relation->nPats; i++) { + if (Abc_RDataGetOut(relation, k, i)) { + Abc_InfoSetBit((unsigned *)Vec_WrdEntryP(vSimsOut, i), k); + } + } + } + return vSimsOut; + } + + template + void eSLIM_Man::findReplacement() { + Subcircuit subcir = subcircuit_selection.getSubcircuit(); + if (!subcircuit_selection.getStatus()) { + if (cfg.trial_limit_active) { + stopeSLIM = true; + } + return; + } + Mini_Aig_t* replacement = findMinimumAig(subcir); + if (replacement != nullptr) { + insertReplacement(replacement, subcir); + Mini_AigStop(replacement); + } + subcir.free(); + } + + // Based on Exa_ManExactSynthesis6Int and Exa_ManExactSynthesis6 + template + Mini_Aig_t* eSLIM_Man::findMinimumAig(const Subcircuit& subcir) { + + if (subcir.forbidden_pairs.size() > 0) { + log.subcircuits_with_forbidden_pairs++; + } + + Abc_RData_t* relation = generateRelation(subcir); + int nDivs = 0; + int nOuts = relation->nOuts; + int nVars = relation->nIns; + if ( nVars == 0 ) { + return nullptr; + } + assert (nVars <= 8); //Assertion from original ABC code + Vec_Wrd_t* vSimsDiv = getSimsIn(relation); + Vec_Wrd_t* vSimsOut = getSimsOut(relation); + + word original_all_false_behaviour = vSimsOut->pArray[0]; + // If the original circuit computed a non-normal circuit, but the relations allows to set the outputs to false in the all inputs false case + // ABC does not "negate" the relation but forces the circuit to yield (0,...,0) for (0,...,0). + // As a consequence it is not necessarily possible to find a same sized circuit. + // In order to prevent this behaviour, we first modify the relation such that for the (0,...,0) input pattern only the original output patterns is allowed. + vSimsOut->pArray[0] = getAllFalseBehaviour(subcir); + + int DivCompl = (int)Vec_WrdEntry(vSimsDiv, 0) >> 1; + int OutCompl = Exa6_ManFindPolar( Vec_WrdEntry(vSimsOut, 0), nOuts ); + Vec_Wrd_t* vSimsDiv2 = Exa6_ManTransformInputs( vSimsDiv ); + Vec_Wrd_t* vSimsOut2 = Exa6_ManTransformOutputs( vSimsOut, nOuts ); + Mini_Aig_t* pMini = nullptr; + int original_size = Vec_IntSize(subcir.nodes); + int size = original_size; + + if (log.nof_analyzed_circuits_per_size.size() < original_size + 1) { + log.nof_analyzed_circuits_per_size.resize(original_size + 1, 0); + log.nof_replaced_circuits_per_size.resize(original_size + 1, 0); + log.nof_reduced_circuits_per_size.resize(original_size + 1, 0); + } + log.nof_analyzed_circuits_per_size[original_size]++; + + abctime synthesis_start = Abc_Clock(); + std::tie(size, pMini) = reduce(vSimsDiv2, vSimsOut2, subcir.forbidden_pairs, nVars, nDivs, nOuts, size); + log.synthesis_time += (double)1.0*(Abc_Clock() - synthesis_start)/CLOCKS_PER_SEC; + + if (size > original_size) { + // Could not find a replacement. This can be caused by a timeout. + Abc_RDataStop(relation); + Vec_WrdFreeP( &vSimsDiv ); + Vec_WrdFreeP( &vSimsOut ); + Vec_WrdFreeP( &vSimsDiv2 ); + Vec_WrdFreeP( &vSimsOut2 ); + return nullptr; + } + + // It is possible that a better replacement is obtained with a non normal behaviour. + bool check_original_all_false_behaviour = cfg.extended_normality_processing && vSimsOut->pArray[0] != original_all_false_behaviour; + if (check_original_all_false_behaviour) { + vSimsOut->pArray[0] = original_all_false_behaviour; + int OutCompl_alt = Exa6_ManFindPolar( Vec_WrdEntry(vSimsOut, 0), nOuts ); + Vec_Wrd_t* vSimsOut2_alt = Exa6_ManTransformOutputs( vSimsOut, nOuts ); + abctime synthesis_start = Abc_Clock(); + // auto [sz, mini] = reduce(vSimsDiv2, vSimsOut2_alt, subcir.forbidden_pairs, nVars, nDivs, nOuts, size - 1, true); + auto result = reduce(vSimsDiv2, vSimsOut2_alt, subcir.forbidden_pairs, nVars, nDivs, nOuts, size - 1); + int sz = result.first; + Mini_Aig_t* mini = result.second; + log.synthesis_time += (double)1.0*(Abc_Clock() - synthesis_start)/CLOCKS_PER_SEC; + if (mini != nullptr) { + size = sz; + if (pMini) { + Mini_AigStop(pMini); + } + pMini = mini; + OutCompl = OutCompl_alt; + } + } + Abc_RDataStop(relation); + + if (pMini != nullptr) { + Mini_Aig_t* pTemp = pMini; + pMini = Mini_AigDupCompl(pTemp, DivCompl, OutCompl); + Mini_AigStop(pTemp); + + log.nof_replaced_circuits_per_size[original_size]++; + if (size < original_size) { + log.nof_reduced_circuits_per_size[original_size]++; + } + } + Vec_WrdFreeP( &vSimsDiv ); + Vec_WrdFreeP( &vSimsOut ); + Vec_WrdFreeP( &vSimsDiv2 ); + Vec_WrdFreeP( &vSimsOut2 ); + return pMini; + } + + template + word eSLIM_Man::getAllFalseBehaviour(const Subcircuit& subcir) { + Gia_ManIncrementTravId(gia_man); + Gia_Obj_t * pObj; + int i; + Gia_ManForEachObjVec( subcir.nodes, gia_man, pObj, i ) { + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + long assm_idx = 0; + Gia_ManForEachObjVecStart(subcir.io, gia_man, pObj, i, subcir.nof_inputs) { + int bit_idx = i - subcir.nof_inputs; + if (getAllFalseBehaviourRec(pObj)) { + assm_idx |= (1 << bit_idx); + } + } + return 1L << assm_idx; + } + + template + bool eSLIM_Man::getAllFalseBehaviourRec(Gia_Obj_t * pObj) { + bool valuefanin0, valuefanin1; + if (Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin0(pObj))) { + valuefanin0 = getAllFalseBehaviourRec(Gia_ObjFanin0(pObj)); + } else { + valuefanin0 = false; + } + valuefanin0 = valuefanin0 != pObj->fCompl0; + if (Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin1(pObj))) { + valuefanin1 = getAllFalseBehaviourRec(Gia_ObjFanin1(pObj)); + } else { + valuefanin1 = false; + } + valuefanin1 = valuefanin1 != pObj->fCompl1; + return valuefanin0 && valuefanin1; + } + + template + int eSLIM_Man::getInsertionLiteral(Gia_Man_t* gia_man, const Subcircuit& subcir, Mini_Aig_t* replacement, const std::vector& replacement_values, int fanin_lit) { + int fanin_idx = Abc_Lit2Var(fanin_lit); + bool fanin_negated = Abc_LitIsCompl(fanin_lit); + int fanin_value; + if (fanin_idx == 0) { // constant fanin + fanin_value = 0; + } else if (fanin_idx <= subcir.nof_inputs) { + Gia_Obj_t* pObj = Gia_ManObj(gia_man, Vec_IntEntry(subcir.io, fanin_idx - 1)); + if (Gia_ObjIsTravIdCurrent(gia_man, pObj)) { //the node has already been added + fanin_value = Gia_ManObj(gia_man, Vec_IntEntry(subcir.io, fanin_idx - 1))->Value; + } else { + return -1; + } + } else { + if (replacement_values[fanin_idx - subcir.nof_inputs - 1] == -1) { + return -1; + } + fanin_value = replacement_values[fanin_idx - subcir.nof_inputs - 1]; + } + return Abc_LitNotCond( fanin_value, fanin_negated ); + } + + template + std::vector eSLIM_Man::processReplacement(Gia_Man_t* gia_man, Gia_Man_t* pNew, const Subcircuit& subcir, Mini_Aig_t* replacement, std::vector&& to_process, std::vector& replacement_values) { + std::vector to_process_next_it; + for (int id : to_process) { + int fanin0 = getInsertionLiteral(gia_man, subcir, replacement, replacement_values, Mini_AigNodeFanin0( replacement, id)); + int fanin1 = getInsertionLiteral(gia_man, subcir, replacement, replacement_values, Mini_AigNodeFanin1( replacement, id)); + if (fanin0 == -1 || fanin1 == -1) { + to_process_next_it.push_back(id); + } else { + int idx = id - subcir.nof_inputs - 1; + replacement_values[idx] = Gia_ManAppendAnd2(pNew, fanin0, fanin1); + } + } + int i, j = 0; + Mini_AigForEachPo(replacement, i) { + int old_id = Vec_IntEntry(subcir.io, j + subcir.nof_inputs); + j++; + Gia_Obj_t* obj = Gia_ManObj(gia_man, old_id); + int fanin0_lit = Mini_AigNodeFanin0( replacement, i); + int fanin0_idx = Abc_Lit2Var(fanin0_lit); + if (fanin0_idx == 0) { // constant fanin + obj->Value = Gia_ManConst0(gia_man)->Value; + } else if (fanin0_idx <= subcir.nof_inputs) { + Gia_Obj_t* fanin_obj = Gia_ManObj(gia_man, Vec_IntEntry(subcir.io, fanin0_idx - 1)); + if (Gia_ObjIsTravIdCurrent(gia_man, fanin_obj)) { + obj->Value = fanin_obj->Value; + } else { + continue; + } + } else { + if (replacement_values[fanin0_idx - subcir.nof_inputs - 1] == -1 ) { + continue; + } else { + obj->Value = replacement_values[fanin0_idx - subcir.nof_inputs - 1]; + } + } + Gia_ObjSetTravIdCurrent(gia_man, obj); + bool fanin0_negated = Abc_LitIsCompl(fanin0_lit); + if (fanin0_negated) { + obj->fMark0 = 1; + } + } + return to_process_next_it; + } + + template + Vec_Int_t * eSLIM_Man::processEncompassing(Gia_Man_t* gia_man, Gia_Man_t* pNew, Vec_Int_t * to_process) { + int i; + Gia_Obj_t * pObj; + Vec_Int_t * to_process_remaining = Vec_IntAlloc( Vec_IntSize(to_process) ); + Gia_ManForEachObjVec( to_process, gia_man, pObj, i ) { + if (Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin0(pObj)) && Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin1(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, pObj); + bool fanin0_negated = Gia_ObjFaninC0(pObj) ^ Gia_ObjFanin0(pObj)->fMark0; + bool fanin1_negated = Gia_ObjFaninC1(pObj) ^ Gia_ObjFanin1(pObj)->fMark0; + int fanin0 = Abc_LitNotCond(Gia_ObjFanin0(pObj)->Value, fanin0_negated); + int fanin1 = Abc_LitNotCond(Gia_ObjFanin1(pObj)->Value, fanin1_negated); + pObj->Value = Gia_ManAppendAnd2( pNew, fanin0, fanin1); + } else { + Vec_IntPush(to_process_remaining, Gia_ObjId(gia_man, pObj)); + } + } + Vec_IntFree(to_process); + return to_process_remaining; + } + + template + void eSLIM_Man::insertReplacement(Mini_Aig_t* replacement, const Subcircuit& subcir) { + // A miniaig contains a constant node, nodes for each PI/PO and for each and. + int repalcement_size = Mini_AigNodeNum(replacement) - Vec_IntSize(subcir.io) - 1; + int size_diff = Vec_IntSize(subcir.nodes) - repalcement_size; + Gia_Man_t * pNew = Gia_ManStart( Gia_ManObjNum(gia_man) - size_diff ); + pNew->pName = Abc_UtilStrsav( gia_man->pName ); + pNew->pSpec = Abc_UtilStrsav( gia_man->pSpec ); + Gia_Obj_t * pObj; + int i; + Gia_ManConst0(gia_man)->Value = 0; + Gia_ManForEachPi( gia_man, pObj, i ) { + pObj->Value = Gia_ManAppendCi(pNew); + } + Gia_ManIncrementTravId(gia_man); + Gia_ManForEachObjVec( subcir.nodes, gia_man, pObj, i ) { + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + Gia_ManIncrementTravId(gia_man); + Gia_ManForEachPi( gia_man, pObj, i ) { + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + Vec_Int_t * to_process_encompassing = Vec_IntAlloc( gia_man->nObjs ); + Gia_ManForEachAnd( gia_man, pObj, i ) { + // nodes from the subcircuit shall not be added + if (Gia_ObjIsTravIdPrevious(gia_man, pObj)) { + continue; + } else if (Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin0(pObj)) && Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin1(pObj))) { + pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } else { + Vec_IntPush(to_process_encompassing, Gia_ObjId(gia_man, pObj)); + } + } + std::vector to_process_replacement; + Mini_AigForEachAnd(replacement, i) { + to_process_replacement.push_back(i); + } + std::vector replacement_values(to_process_replacement.size(), -1); + + while (Vec_IntSize(to_process_encompassing) > 0 || to_process_replacement.size() > 0) { + to_process_replacement = processReplacement(gia_man, pNew, subcir, replacement, std::move(to_process_replacement), replacement_values); + to_process_encompassing = processEncompassing(gia_man, pNew, to_process_encompassing); + } + Vec_IntFree(to_process_encompassing); + int po_idx = 0; + Mini_AigForEachPo(replacement, i) { + Gia_Obj_t* pObj = Gia_ManObj(gia_man, Vec_IntEntry(subcir.io, subcir.nof_inputs + po_idx)); + if (!Gia_ObjIsTravIdCurrent(gia_man, pObj)) { + int fanin_lit = Mini_AigNodeFanin0( replacement, i); + int fanin_idx = Abc_Lit2Var(fanin_lit); + assert (fanin_idx <= subcir.nof_inputs); + Gia_Obj_t* fanin_obj = Gia_ManObj(gia_man, Vec_IntEntry(subcir.io, fanin_idx - 1)); + pObj->Value = fanin_obj->Value; + if (Abc_LitIsCompl(fanin_lit)) { + pObj->fMark0 = 1; + } + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + po_idx++; + } + + Gia_ManForEachPo( gia_man, pObj, i ) { + assert(Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin0(pObj))); + bool fanin_negated = Gia_ObjFaninC0(pObj) ^ Gia_ObjFanin0(pObj)->fMark0; + int fanin0 = Abc_LitNotCond(Gia_ObjFanin0(pObj)->Value, fanin_negated); + pObj->Value = Gia_ManAppendCo( pNew, fanin0 ); + } + Gia_ManStop(gia_man); + gia_man = pNew; + } + + template + std::pair eSLIM_Man::reduce(Vec_Wrd_t* vSimsDiv, Vec_Wrd_t* vSimsOut, const std::unordered_map>& forbidden_pairs, + int nVars, int nDivs, int nOuts, int size) { + Y synth_man(vSimsDiv,vSimsOut,nVars,1+nVars+nDivs,nOuts,size, forbidden_pairs, log, cfg); + Mini_Aig_t* result = nullptr; + while (size >= 0) { + Mini_Aig_t* pTemp = computeReplacement(synth_man, size); + if (pTemp) { + if (result) { + Mini_AigStop(result); + } + result = pTemp; + size--; + } else { + break; + } + } + return std::make_pair(size + 1, result); + } + + template + double eSLIM_Man::getDynamicTimeout(int size) { + if (this->log.nof_sat_calls_per_size[size] > cfg.minimum_dynamic_timeout_sample_size) { + return std::max(static_cast(cfg.minimum_sat_timeout), static_cast(log.cummulative_sat_runtimes_per_size[size]) / (1000*log.nof_sat_calls_per_size[size])); //logged timings are given in ms + } else { + return cfg.base_sat_timeout; + } + } + + template + Mini_Aig_t* eSLIM_Man::computeReplacement(Y& syn_man, int size) { + return syn_man.getCircuit(size, getDynamicTimeout(size)); + } + +} + +ABC_NAMESPACE_CXX_HEADER_END \ No newline at end of file diff --git a/src/opt/eslim/module.make b/src/opt/eslim/module.make new file mode 100644 index 000000000..f300a4231 --- /dev/null +++ b/src/opt/eslim/module.make @@ -0,0 +1,2 @@ +SRC += src/opt/eslim/relationGeneration.cpp \ + src/opt/eslim/eSLIM.cpp \ No newline at end of file diff --git a/src/opt/eslim/relationGeneration.cpp b/src/opt/eslim/relationGeneration.cpp new file mode 100644 index 000000000..66dc11eff --- /dev/null +++ b/src/opt/eslim/relationGeneration.cpp @@ -0,0 +1,172 @@ +/**CFile**************************************************************** + + FileName [relationGeneration.cpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for computing Boolean relations.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: relationGeneration.cpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#include + +#include "misc/vec/vec.h" +#include "sat/cnf/cnf.h" +#include "sat/bsat/satSolver.h" + +#include "relationGeneration.hpp" + +ABC_NAMESPACE_HEADER_START + void * Mf_ManGenerateCnf( Gia_Man_t * pGia, int nLutSize, int fCnfObjIds, int fAddOrCla, int fMapping, int fVerbose ); + void * Cnf_DataWriteIntoSolver( Cnf_Dat_t * p, int nFrames, int fInit ); + Vec_Int_t * Gia_ManCollectNodeTfos( Gia_Man_t * p, int * pNodes, int nNodes ); + Vec_Int_t * Gia_ManCollectNodeTfis( Gia_Man_t * p, Vec_Int_t * vNodes ); +ABC_NAMESPACE_HEADER_END + +ABC_NAMESPACE_IMPL_START + + +namespace eSLIM { + + RelationGeneratorABC::RelationGeneratorABC(Gia_Man_t* pGia, const Subcircuit& subcir) + : RelationGenerator(pGia, subcir) { + + // for (const auto& [out, inputs] : subcir.forbidden_pairs) { + for (const auto& it: subcir.forbidden_pairs) { + const auto& inputs = it.second; + inputs_in_forbidden_pairs.insert(inputs.begin(), inputs.end()); + } +} + + Vec_Int_t* RelationGeneratorABC::getRelationImpl() { + abctime clkStart = Abc_Clock(); + int nTimeOut = 600, nConfLimit = 1000000; + int i, iNode, iSatVar, Iter, Mask, nSolutions = 0, RetValue = 0; + // --------------- Modification --------------- + Gia_Man_t* pMiter = generateMiter(); + // --------------- Modification --------------- + Cnf_Dat_t * pCnf = (Cnf_Dat_t*)Mf_ManGenerateCnf( pMiter, 8, 0, 0, 0, 0 ); + sat_solver * pSat = (sat_solver*)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); + int iLit = Abc_Var2Lit( 1, 0 ); // enumerating the care set (the miter output is 1) + int status = sat_solver_addclause( pSat, &iLit, &iLit + 1 ); assert( status ); + Vec_Int_t * vSatVars = Vec_IntAlloc( Vec_IntSize(subcir.io) ); + Vec_IntForEachEntry( subcir.io, iNode, i ) + Vec_IntPush( vSatVars, i < subcir.nof_inputs ? 2+i : pCnf->nVars-Vec_IntSize(subcir.io)+i ); + Vec_Int_t * vLits = Vec_IntAlloc( 100 ); + Vec_Int_t * vRes = Vec_IntAlloc( 1000 ); + for ( Iter = 0; Iter < 1000000; Iter++ ) + { + int status = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfLimit, 0, 0, 0 ); + if ( status == l_False ) { RetValue = 1; break; } + if ( status == l_Undef ) { RetValue = 0; break; } + nSolutions++; + // extract SAT assignment + Mask = 0; + Vec_IntClear( vLits ); + Vec_IntForEachEntry( vSatVars, iSatVar, i ) { + Vec_IntPush( vLits, Abc_Var2Lit(iSatVar, sat_solver_var_value(pSat, iSatVar)) ); + if ( sat_solver_var_value(pSat, iSatVar) ) + Mask |= 1 << (Vec_IntSize(subcir.io)-1-i); + } + Vec_IntPush( vRes, Mask ); + if ( !sat_solver_addclause( pSat, Vec_IntArray(vLits), Vec_IntArray(vLits) + Vec_IntSize(vLits) ) ) + { RetValue = 1; break; } + if ( nTimeOut && (Abc_Clock() - clkStart)/CLOCKS_PER_SEC >= nTimeOut ) { RetValue = 0; break; } + } + // complement the set of input/output minterms + Vec_Int_t * vBits = Vec_IntStart( 1 << Vec_IntSize(subcir.io) ); + Vec_IntForEachEntry( vRes, Mask, i ) + Vec_IntWriteEntry( vBits, Mask, 1 ); + Vec_IntClear( vRes ); + Vec_IntForEachEntry( vBits, Mask, i ) + if ( !Mask ) + Vec_IntPush( vRes, i ); + Vec_IntFree( vBits ); + // cleanup + Vec_IntFree( vLits ); + Vec_IntFree( vSatVars ); + sat_solver_delete( pSat ); + Gia_ManStop( pMiter ); + Cnf_DataFree( pCnf ); + if ( RetValue == 0 ) + Vec_IntFreeP( &vRes ); + return vRes; + } + + Gia_Man_t * RelationGeneratorABC::generateMiter() { + Vec_Int_t * vInsOuts = subcir.io; + int nIns = subcir.nof_inputs; + + Vec_Int_t * vTfo = Gia_ManCollectNodeTfos( pGia, Vec_IntEntryP(vInsOuts, nIns), Vec_IntSize(vInsOuts)-nIns ); + Vec_Int_t * vTfi = Gia_ManCollectNodeTfis( pGia, vTfo ); + Vec_Int_t * vInLits = Vec_IntAlloc( nIns ); + Vec_Int_t * vOutLits = Vec_IntAlloc( Vec_IntSize(vInsOuts) - nIns ); + Gia_Man_t * pNew, * pTemp; Gia_Obj_t * pObj; int i, iLit = 0; + Gia_ManFillValue( pGia ); + pNew = Gia_ManStart( 1000 ); + pNew->pName = Abc_UtilStrsav( pGia->pName ); + Gia_ManHashAlloc( pNew ); + Gia_ManForEachObjVec( vTfi, pGia, pObj, i ) + if ( Gia_ObjIsCi(pObj) ) + pObj->Value = Gia_ManAppendCi(pNew); + for ( i = 0; i < Vec_IntSize(vInsOuts)-nIns; i++ ) + Vec_IntPush( vInLits, Gia_ManAppendCi(pNew) ); + Gia_ManForEachObjVec( vTfi, pGia, pObj, i ) + if ( Gia_ObjIsAnd(pObj) ) + pObj->Value = Gia_ManHashAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ManForEachObjVec( vTfo, pGia, pObj, i ) + if ( Gia_ObjIsCo(pObj) ) + pObj->Value = Gia_ObjFanin0Copy(pObj); + Gia_ManForEachObjVec( vInsOuts, pGia, pObj, i ) + if ( i < nIns ) + Vec_IntPush( vOutLits, pObj->Value ); + else + pObj->Value = Vec_IntEntry( vInLits, i-nIns ); + + Gia_ManIncrementTravId(pGia); + Gia_ManForEachObjVec( subcir.nodes, pGia, pObj, i ) { + Gia_ObjSetTravIdCurrent(pGia, pObj); + } + + Gia_ManForEachObjVec( vTfo, pGia, pObj, i ) + // in case there are forbidden pairs we have to ensure that nodes from the sucircuit are not added + if ( Gia_ObjIsAnd(pObj) && !Gia_ObjIsTravIdCurrent(pGia, pObj) ) + pObj->Value = Gia_ManHashAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + Gia_ManForEachObjVec( vTfo, pGia, pObj, i ) + if ( Gia_ObjIsCo(pObj) ) + iLit = Gia_ManHashOr( pNew, iLit, Gia_ManHashXor(pNew, Gia_ObjFanin0Copy(pObj), pObj->Value) ); + // --------------- Modification --------------- + // In case there are forbidden pairs, the outputs of the subcircuit influence the inputs of the subcircuit. + // Therefore, we need the values of the inputs in the version of the circuit that is affected by the new outputs. + for (int inp : inputs_in_forbidden_pairs) { + int node_id = Vec_IntEntry(vInsOuts, inp); + pObj = Gia_ManObj(pGia, node_id); + Vec_IntWriteEntry(vOutLits, inp, pObj->Value); + } + // --------------- Modification --------------- + Gia_ManAppendCo( pNew, iLit ); + Vec_IntForEachEntry( vOutLits, iLit, i ) + Gia_ManAppendCo( pNew, iLit ); + Vec_IntFree( vTfo ); + Vec_IntFree( vTfi ); + Vec_IntFree( vInLits ); + Vec_IntFree( vOutLits ); + pNew = Gia_ManCleanup( pTemp = pNew ); + Gia_ManStop( pTemp ); + Gia_ManSetRegNum( pNew, Gia_ManRegNum(pGia) ); + return pNew; + } + +} + +ABC_NAMESPACE_IMPL_END \ No newline at end of file diff --git a/src/opt/eslim/relationGeneration.hpp b/src/opt/eslim/relationGeneration.hpp new file mode 100644 index 000000000..2d29fe8ef --- /dev/null +++ b/src/opt/eslim/relationGeneration.hpp @@ -0,0 +1,107 @@ +/**CFile**************************************************************** + + FileName [relationGeneration.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for computing Boolean relations.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: relationGeneration.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__RELATIONGENERATION_h +#define ABC__OPT__ESLIM__RELATIONGENERATION_h + +#include +#include +#include + +#include "misc/util/abc_namespaces.h" +#include +#include "aig/gia/gia.h" + +#include "utils.hpp" +// #include "satInterfaces.hpp" + + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + class RelationGenerator { + + public: + static Vec_Int_t* computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir); + + private: + Gia_Man_t* pGia; + const Subcircuit& subcir; + + RelationGenerator(Gia_Man_t* pGia, const Subcircuit& subcir); + void setup(); + Vec_Int_t* getRelation(); + + friend Derived; + }; + + // The class almost entirely duplicates the functionality provided by Gia_ManGenIoCombs in giaQBF.c + // But the implementation in this class allows to take forbidden pairs into account. + class RelationGeneratorABC : public RelationGenerator { + + private: + RelationGeneratorABC(Gia_Man_t* pGia, const Subcircuit& subcir); + void setupImpl() {}; + Vec_Int_t* getRelationImpl(); + Gia_Man_t * generateMiter(); + + std::unordered_set inputs_in_forbidden_pairs; + + friend RelationGenerator; + }; + + + // Add other engine for the generation of relations + // class MyRelationGenerator : public RelationGenerator { + // private: + // void setupImpl() + // Vec_Int_t* getRelationImpl(); + // friend RelationGenerator; + // }; + + + template + inline RelationGenerator::RelationGenerator(Gia_Man_t* pGia, const Subcircuit& subcir) + : pGia(pGia), subcir(subcir) { + } + + template + inline Vec_Int_t* RelationGenerator::computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir) { + T generator(gia_man, subcir); + generator.setup(); + return generator.getRelation(); + } + + template + inline void RelationGenerator::setup() { + static_cast(this)->setupImpl(); + } + + template + inline Vec_Int_t* RelationGenerator::getRelation() { + return static_cast(this)->getRelationImpl(); + } +} + +ABC_NAMESPACE_CXX_HEADER_END + +#endif diff --git a/src/opt/eslim/satInterfaces.hpp b/src/opt/eslim/satInterfaces.hpp new file mode 100644 index 000000000..3300d9e59 --- /dev/null +++ b/src/opt/eslim/satInterfaces.hpp @@ -0,0 +1,196 @@ +/**CFile**************************************************************** + + FileName [satInterfaces.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Interface to SAT solvers.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: satInterfaces.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__SATINTERFACE_h +#define ABC__OPT__ESLIM__SATINTERFACE_h + +#include +#include +#include + +#include "misc/util/abc_namespaces.h" +#include "misc/vec/vec.h" +#include "sat/kissat/kissat.h" +#include "sat/cadical/cadical.hpp" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + class CadicalSolver { + public: + void addClause(int * pLits, int nLits ); + void assume(const std::vector& assumptions); + int solve(double timeout); + int solve(); + Vec_Int_t* getModelVec(); + double getRunTime() const; + + private: + int val(int variable); + double last_runtime; + CaDiCaL::Solver solver; + + public: + class TimeoutTerminator : public CaDiCaL::Terminator { + public: + TimeoutTerminator(double max_runtime); + bool terminate(); + + private: + double max_runtime; //in seconds + std::chrono::time_point start = std::chrono::steady_clock::now(); + }; + }; + + class KissatSolver { + public: + KissatSolver(); + ~KissatSolver(); + void init(int max_var); + void addClause(int * pLits, int nLits ); + int solve(); + // int solve(int timeout); + Vec_Int_t* getModelVec(); + + private: + + int max_var = 0; + int val(int variable); + kissat * solver = nullptr; + }; + + inline CadicalSolver::TimeoutTerminator::TimeoutTerminator(double max_runtime) : max_runtime(max_runtime) {} + + inline bool CadicalSolver::TimeoutTerminator::terminate() { + auto current_time = std::chrono::steady_clock::now(); + std::chrono::duration elapsed_seconds = current_time - start; + return elapsed_seconds.count() > max_runtime; + } + + inline double CadicalSolver::getRunTime() const { + return last_runtime; + } + + inline void CadicalSolver::addClause(int * pLits, int nLits ) { + for ( int i = 0; i < nLits; i++ ) { + if (pLits[i] == 0) { + continue;; + } + solver.add(Abc_LitIsCompl(pLits[i]) ? -Abc_Lit2Var(pLits[i]) : Abc_Lit2Var(pLits[i])); + } + solver.add(0); + } + + inline void CadicalSolver::assume(const std::vector& assumptions) { + for (auto& l: assumptions) { + solver.assume(l); + } + } + + inline int CadicalSolver::solve() { + std::chrono::time_point start = std::chrono::steady_clock::now(); + int status = solver.solve(); + last_runtime = std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count(); + return status; + } + + inline int CadicalSolver::solve(double timeout) { + std::chrono::time_point start = std::chrono::steady_clock::now(); + TimeoutTerminator terminator(timeout); + solver.connect_terminator(&terminator); + int status = solver.solve(); + last_runtime = std::chrono::duration_cast(std::chrono::steady_clock::now() - start).count(); + if (solver.state() == CaDiCaL::INVALID) { + std::cerr<<"Solver is in invalid state"< 0 ); + } + return assignment; + } + + inline int CadicalSolver::val(int variable) { + auto l = solver.val(variable); + auto v = abs(l); + if (v == variable) { + return l; + } else { + return variable; + } + } + + inline KissatSolver::KissatSolver() { + solver = kissat_init(); + } + + inline KissatSolver::~KissatSolver() { + kissat_release(solver); + } + + inline void KissatSolver::init(int max_var) { + this->max_var = max_var; + kissat_reserve(solver, max_var); + } + + inline void KissatSolver::addClause(int * pLits, int nLits ) { + for ( int i = 0; i < nLits; i++ ) { + if (pLits[i] == 0) { + continue; + } + kissat_add (solver, Abc_LitIsCompl(pLits[i]) ? -Abc_Lit2Var(pLits[i]) : Abc_Lit2Var(pLits[i])); + } + kissat_add (solver, 0); + } + + inline int KissatSolver::solve() { + int status = kissat_solve(solver); + return status; + } + + inline int KissatSolver::val(int variable) { + int l = kissat_value (solver, variable); + auto v = abs(l); + if (v == variable) { + return l; + } else { + return variable; + } + } + + inline Vec_Int_t* KissatSolver::getModelVec() { + Vec_Int_t* assignment = Vec_IntAlloc( max_var ); + for (int v = 1; v <= max_var; v++) { + Vec_IntSetEntryFull( assignment, Abc_AbsInt(val(v)), val(v) > 0 ); + } + return assignment; + } +} + +ABC_NAMESPACE_CXX_HEADER_END + +#endif \ No newline at end of file diff --git a/src/opt/eslim/selectionStrategy.hpp b/src/opt/eslim/selectionStrategy.hpp new file mode 100644 index 000000000..b4f0ccf80 --- /dev/null +++ b/src/opt/eslim/selectionStrategy.hpp @@ -0,0 +1,154 @@ +/**CFile**************************************************************** + + FileName [selectionStrategy.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for selecting subcircuits.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: selectionStrategy.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__SELECTIONSTRATEGY_h +#define ABC__OPT__ESLIM__SELECTIONSTRATEGY_h + +#include +#include + +#include "misc/util/abc_namespaces.h" +#include "misc/vec/vec.h" +#include "aig/gia/gia.h" + +#include "utils.hpp" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + class SelectionStrategy { + public: + Subcircuit getSubcircuit(); + bool getStatus() {return status;}; + void setSeed(int seed); + + protected: + SelectionStrategy(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log); + unsigned int getUniformRandomNumber(unsigned int lower, unsigned int upper); // requires lower < upper + bool getRandomBool(); + int getSubcircuitIO(Vec_Int_t* subcircuit, Vec_Int_t* io); + // The resulting map assigns inputs of the subcircuit to outputs of the subcircuit s.t. each associated input is reachable from the output + std::unordered_map> computeForbiddenPairs(const Subcircuit& subcir); + + Gia_Man_t*& gia_man; + const eSLIMConfig& cfg; + eSLIMLog& log; + + private: + + bool filterSubcircuit(const Subcircuit& subcir); + void forbiddenPairsRec(Gia_Obj_t * pObj, int input, int min_level, std::unordered_map>& pairs, const std::unordered_map& out_ids ); + + bool status = true; //set to false if selection fails too often + static constexpr unsigned int min_size = 2; + + std::mt19937 rng; + std::bernoulli_distribution bdist; + std::uniform_int_distribution udistr; + + }; + + template + class randomizedBFS : public SelectionStrategy { + private: + randomizedBFS(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log); + Subcircuit findSubcircuit(); + int selectRoot(); + void checkCandidate(Subcircuit& subcircuit, std::queue& candidate, std::queue& rejected, bool add); + const int nPis; + const int nPos; + friend SelectionStrategy; + friend T; + }; + + class randomizedBFSFP : public randomizedBFS { + public : + randomizedBFSFP(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log); + private: + Subcircuit getSubcircuitImpl(); + bool filterSubcircuitImpl(const Subcircuit& subcir); + + friend SelectionStrategy; + }; + + class randomizedBFSnoFP : public randomizedBFS { + public: + randomizedBFSnoFP(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log); + private: + Subcircuit getSubcircuitImpl() {return findSubcircuit();}; + bool filterSubcircuitImpl(const Subcircuit& subcir); + bool filterSubcircuitRec(Gia_Obj_t * pObj, unsigned int min_level); + + friend SelectionStrategy; + }; + + + template + SelectionStrategy::SelectionStrategy(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log) + : gia_man(gia_man), cfg(cfg), log(log), rng(std::random_device()()) { + } + + template + void SelectionStrategy::setSeed(int seed) { + rng.seed(seed); + } + + template + unsigned int SelectionStrategy::getUniformRandomNumber(unsigned int lower, unsigned int upper) { + udistr.param(std::uniform_int_distribution::param_type(lower, upper)); + return udistr(rng); + } + + template + bool SelectionStrategy::getRandomBool() { + return bdist(rng); + } + + template + randomizedBFS::randomizedBFS(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log) + : SelectionStrategy(gia_man, cfg, log), nPis(Gia_ManPiNum(gia_man)), nPos(Gia_ManPoNum(gia_man)) { + } + + inline randomizedBFSFP::randomizedBFSFP(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log) + : randomizedBFS(gia_man, cfg, log){ + } + + inline Subcircuit randomizedBFSFP::getSubcircuitImpl() { + Subcircuit subcir = findSubcircuit(); + subcir.forbidden_pairs = computeForbiddenPairs(subcir); + return subcir; + } + + inline randomizedBFSnoFP::randomizedBFSnoFP(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log) + : randomizedBFS(gia_man, cfg, log) { + } + + inline bool randomizedBFSFP::filterSubcircuitImpl(const Subcircuit& subcir) { + return true; + } +} + +ABC_NAMESPACE_CXX_HEADER_END + +#include "selectionStrategy.tpp" + +#endif \ No newline at end of file diff --git a/src/opt/eslim/selectionStrategy.tpp b/src/opt/eslim/selectionStrategy.tpp new file mode 100644 index 000000000..ba150d624 --- /dev/null +++ b/src/opt/eslim/selectionStrategy.tpp @@ -0,0 +1,231 @@ +/**CFile**************************************************************** + + FileName [selectionStrategy.tpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for selecting subcircuits.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: selectionStrategy.tpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#include + +#include "misc/util/abc_namespaces.h" + +#include "selectionStrategy.hpp" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + Subcircuit SelectionStrategy::getSubcircuit() { + for (int i = 0; i < cfg.nselection_trials; i++) { + Subcircuit subcir = static_cast(this)->getSubcircuitImpl(); + if (filterSubcircuit(subcir)) { + return subcir; + } else { + subcir.free(); + } + } + status = false; + Subcircuit empty_subcir; + return empty_subcir; + } + + template + bool SelectionStrategy::filterSubcircuit(const Subcircuit& subcir) { + if (subcir.nof_inputs > 8) { + return false; + } + if (Vec_IntSize(subcir.io)-subcir.nof_inputs > 6) { + return false; + } + if (Vec_IntSize(subcir.nodes) < min_size) { + return false; + } + return static_cast(this)->filterSubcircuitImpl(subcir); + } + + template + int SelectionStrategy::getSubcircuitIO(Vec_Int_t* subcircuit, Vec_Int_t* io) { + assert(Vec_IntSize(io) == 0); + Gia_ManIncrementTravId(gia_man); + Gia_Obj_t * pObj; + int i; + Gia_ManForEachObjVec( subcircuit, gia_man, pObj, i ) { + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + Gia_ManIncrementTravId(gia_man); + + // inputs + Gia_ManForEachObjVec( subcircuit, gia_man, pObj, i ) { + // fanin0 is not in the subcircuit and was not considered yet + if (!Gia_ObjIsTravIdPrevious(gia_man, Gia_ObjFanin0(pObj)) && !Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin0(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, Gia_ObjFanin0(pObj)); + Vec_IntPush(io, Gia_ObjId(gia_man, Gia_ObjFanin0(pObj))); + } + // fanin1 is not in the subcircuit and was not considered yet + if (!Gia_ObjIsTravIdPrevious(gia_man, Gia_ObjFanin1(pObj)) && !Gia_ObjIsTravIdCurrent(gia_man, Gia_ObjFanin1(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, Gia_ObjFanin1(pObj)); + Vec_IntPush(io, Gia_ObjId(gia_man, Gia_ObjFanin1(pObj))); + } + } + int nof_inputs = Vec_IntSize(io); + + // outputs + Gia_ManForEachAnd( gia_man, pObj, i ) { + // If there is an object that is not contained in the subcircuit that has a fanin in the subcircuit then this fanin is an output + if (!Gia_ObjIsTravIdPrevious(gia_man, pObj)) { + if (Gia_ObjIsTravIdPrevious(gia_man, Gia_ObjFanin0(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, Gia_ObjFanin0(pObj)); + Vec_IntPush(io, Gia_ObjId(gia_man, Gia_ObjFanin0(pObj))); + } + if (Gia_ObjIsTravIdPrevious(gia_man, Gia_ObjFanin1(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, Gia_ObjFanin1(pObj)); + Vec_IntPush(io, Gia_ObjId(gia_man, Gia_ObjFanin1(pObj))); + } + } + } + + Gia_ManForEachPo( gia_man, pObj, i ) { + if (Gia_ObjIsTravIdPrevious(gia_man, Gia_ObjFanin0(pObj))) { + Gia_ObjSetTravIdCurrent(gia_man, Gia_ObjFanin0(pObj)); + Vec_IntPush(io, Gia_ObjId(gia_man, Gia_ObjFanin0(pObj))); + } + } + return nof_inputs; + } + + template + std::unordered_map> SelectionStrategy::computeForbiddenPairs(const Subcircuit& subcir) { + Gia_Obj_t * pObj; + int i; + unsigned int min_output_level = Gia_ManLevelNum(gia_man); + Gia_ManIncrementTravId(gia_man); + std::unordered_map out_id; + Gia_ManForEachObjVecStart(subcir.io, gia_man, pObj, i, subcir.nof_inputs) { + min_output_level = Gia_ObjLevel(gia_man, pObj) < min_output_level ? Gia_ObjLevel(gia_man, pObj) : min_output_level; + Gia_ObjSetTravIdCurrent(gia_man, pObj); + auto id = Gia_ObjId(gia_man, pObj); + out_id[id] = i - subcir.nof_inputs; + } + std::unordered_map> forbidden_pairs; + Gia_ManForEachObjVecStop(subcir.io, gia_man, pObj, i, subcir.nof_inputs) { + forbiddenPairsRec(pObj, i, min_output_level, forbidden_pairs, out_id); + } + return forbidden_pairs; + } + + template + void SelectionStrategy::forbiddenPairsRec(Gia_Obj_t * pObj, int input, int min_level, std::unordered_map>& pairs, const std::unordered_map& out_id) { + if (Gia_ObjIsTravIdCurrent(gia_man, pObj)) { + auto id = Gia_ObjId(gia_man, pObj); + pairs[out_id.at(id)].insert(input); + return; + } + if (Gia_ObjLevel(gia_man, pObj) < min_level) { + return; + } + forbiddenPairsRec(Gia_ObjFanin0(pObj), input, min_level, pairs, out_id); + forbiddenPairsRec(Gia_ObjFanin1(pObj), input, min_level, pairs, out_id); + } + + template + int randomizedBFS::selectRoot() { + int nof_objs = Gia_ManObjNum(this->gia_man); + int root_id = this->getUniformRandomNumber(this->nPis + 1, nof_objs - this->nPos - 1); + return root_id; + } + + template + void randomizedBFS::checkCandidate(Subcircuit& subcircuit, std::queue& candidates, std::queue& rejected, bool add) { + int obj_id = candidates.front(); + candidates.pop(); + Gia_Obj_t * gia_obj = Gia_ManObj(this->gia_man, obj_id); + if (Gia_ObjIsAnd(gia_obj) && !Gia_ObjIsTravIdCurrent(this->gia_man, gia_obj)) { + if (add) { + Gia_ObjSetTravIdCurrent(this->gia_man, gia_obj); + Vec_IntPush(subcircuit.nodes, obj_id); + candidates.push(Gia_ObjFaninId0(gia_obj, obj_id)); + candidates.push(Gia_ObjFaninId1(gia_obj, obj_id)); + } else { + rejected.push(obj_id); + } + } + } + + template + Subcircuit randomizedBFS::findSubcircuit() { + Subcircuit result; + assert (Gia_ManIsNormalized(this->gia_man)); + int root_id = selectRoot(); + Gia_Obj_t * gia_obj = Gia_ManObj(this->gia_man, root_id); + assert (Gia_ObjIsAnd(gia_obj)); + result.nodes = Vec_IntAlloc(this->cfg.subcircuit_size_bound); + result.io = Vec_IntAlloc(this->cfg.subcircuit_size_bound); + + Vec_IntPush(result.nodes, root_id); + + std::queue candidates; + candidates.push(Gia_ObjFaninId0(gia_obj, root_id)); + candidates.push(Gia_ObjFaninId1(gia_obj, root_id)); + std::queue rejected_nodes; + + Gia_ManIncrementTravId(this->gia_man); + + while (!candidates.empty() && Vec_IntSize(result.nodes) < this->cfg.subcircuit_size_bound) { + checkCandidate(result, candidates, rejected_nodes, this->getRandomBool()); + } + + if (this->cfg.fill_subcircuits) { + while (!rejected_nodes.empty() && Vec_IntSize(result.nodes) < this->cfg.subcircuit_size_bound) { + checkCandidate(result, rejected_nodes, rejected_nodes, true); + } + } + result.nof_inputs = this->getSubcircuitIO(result.nodes, result.io); + return result; + } + + inline bool randomizedBFSnoFP::filterSubcircuitImpl(const Subcircuit& subcir) { + Gia_Obj_t * pObj; + int i; + unsigned int min_output_level = Gia_ManLevelNum(gia_man); + Gia_ManIncrementTravId(gia_man); + Gia_ManForEachObjVecStart(subcir.io, gia_man, pObj, i, subcir.nof_inputs) { + min_output_level = Gia_ObjLevel(gia_man, pObj) < min_output_level ? Gia_ObjLevel(gia_man, pObj) : min_output_level; + Gia_ObjSetTravIdCurrent(gia_man, pObj); + } + Gia_ManIncrementTravId(gia_man); + Gia_ManForEachObjVecStop(subcir.io, gia_man, pObj, i, subcir.nof_inputs) { + if (!filterSubcircuitRec(pObj, min_output_level)) { + return false; + } + } + return true; + } + + inline bool randomizedBFSnoFP::filterSubcircuitRec(Gia_Obj_t * pObj, unsigned int min_level) { + if (Gia_ObjIsTravIdPrevious(gia_man, pObj)) { + return false; + } else if (Gia_ObjIsTravIdCurrent(gia_man, pObj)) { + return true; + } else if (Gia_ObjLevel(gia_man, pObj) < min_level) { + return true; + } + Gia_ObjSetTravIdCurrent(gia_man, pObj); + return filterSubcircuitRec(Gia_ObjFanin0(pObj), min_level) && filterSubcircuitRec(Gia_ObjFanin1(pObj), min_level); + } +} + +ABC_NAMESPACE_CXX_HEADER_END \ No newline at end of file diff --git a/src/opt/eslim/synthesisEngine.hpp b/src/opt/eslim/synthesisEngine.hpp new file mode 100644 index 000000000..d061e761b --- /dev/null +++ b/src/opt/eslim/synthesisEngine.hpp @@ -0,0 +1,240 @@ +/**CFile**************************************************************** + + FileName [synthesisEngine.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for synthesising Boolean relations.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: synthesisEngine.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__SYNTHESISENGINE_h +#define ABC__OPT__ESLIM__SYNTHESISENGINE_h + +#include +#include +#include +#include + +#include "misc/util/abc_namespaces.h" +#include "aig/miniaig/miniaig.h" +#include "misc/vec/vec.h" + +#include "satInterfaces.hpp" + +ABC_NAMESPACE_CXX_HEADER_START + +#define MAJ_NOBJS 64 // Const0 + Const1 + nVars + nNodes + +namespace eSLIM { + + // Based on Exa6_ManGenStart + template + class exactSynthesisEngine { + + private: + Vec_Wrd_t * vSimsIn; // input signatures (nWords = 1, nIns <= 64) + Vec_Wrd_t * vSimsOut; // output signatures (nWords = 1, nOuts <= 6) + int nIns; + int nDivs; // divisors (const + inputs + tfi + sidedivs) + int nNodes; + int nOuts; + int nObjs; + int VarMarks[MAJ_NOBJS][2][MAJ_NOBJS] = {}; // default init the array + int nCnfVars; + int nCnfVars2; + int nCnfClauses; + + // Assign outputs to their connectivity variables + std::unordered_map> connection_variables; + const std::unordered_map>& forbidden_pairs; + eSLIMLog& log; + const eSLIMConfig& cfg; + + exactSynthesisEngine( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + int addClause(int lit1, int lit2, int lit3, int lit4); + static bool isNormalized( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut ); + int markup(); + int findFanin( Vec_Int_t * vValues, int i, int k, int nof_objs); + Mini_Aig_t * getAig(Vec_Int_t * assignment, int size); + Mini_Aig_t * getAig(Vec_Int_t * assignment); + void generateCNF(int fOrderNodes, int fUniqFans); + int startEncoding(int fOrderNodes, int fUniqFans ); + void generateMinterm( int iMint); + + int getGateEnablingLiteral(int index, bool negated); + int getAuxilaryVariableCount(); + + void introduceConnectionVariables(); + void setupConnectionVariables(); + void addConnectivityConstraints(); + void addCombinedCycleConstraints(); + std::unordered_map> computeNotInPair(const std::unordered_map>& pairs); + + int prepareLits(int * pLits, int& nLits); + + friend Derived; + }; + + // applies Cadical incrementally + class CadicalEngine : public exactSynthesisEngine { + + public: + CadicalEngine(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + Mini_Aig_t* getCircuit(int size, double timeout); + + private: + using exactSynthesisEngine::addClause; + std::vector gate_enabling_assumptions; + CadicalSolver solver; + + + int addClause( int * pLits, int nLits ); + Vec_Int_t * solve(int size, double timeout); + int getAuxilaryVariableCountDerived(); + int getGateEnablingLiteralImpl(int index, bool negated); + void addAssumptions(int size); + void addGateDeactivatedConstraint(int out); + + std::vector getAssumptions(int size); + + friend exactSynthesisEngine; + }; + + class OneshotEngine { + protected: + int getAuxilaryVariableCountDerived() {return 0;}; + int getGateEnablingLiteralImpl(int index, bool negated) {return 0;}; + // void addAssumptions(int size) {}; + void addGateDeactivatedConstraint(int idx) {}; + }; + + template + class OneshotManager { + public: + OneshotManager(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int maxnNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + Mini_Aig_t* getCircuit(int size, double timeout); + + private: + T getOneshotEngine(int size); + + Vec_Wrd_t * vSimsIn; // input signatures (nWords = 1, nIns <= 64) + Vec_Wrd_t * vSimsOut; // output signatures (nWords = 1, nOuts <= 6) + int nIns; + int nDivs; // divisors (const + inputs + tfi + sidedivs) + int maxnNodes; + int nOuts; + + const std::unordered_map>& forbidden_pairs; + eSLIMLog& log; + const eSLIMConfig& cfg; + }; + + class CadicalEngineOneShot : public exactSynthesisEngine, public OneshotEngine { + + public: + CadicalEngineOneShot( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + Mini_Aig_t* getCircuit(int size, double timeout); + + private: + using exactSynthesisEngine::addClause; + + int addClause( int * pLits, int nLits ); + Vec_Int_t * solve(int size, double timeout); + + CadicalSolver solver; + + friend exactSynthesisEngine; + }; + + class KissatEngineOneShot : public exactSynthesisEngine, public OneshotEngine { + + public: + KissatEngineOneShot( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + Mini_Aig_t* getCircuit(int size, double timeout); + + private: + using exactSynthesisEngine::addClause; + + int addClause( int * pLits, int nLits ); + Vec_Int_t * solve(int size, double timeout); + + KissatSolver solver; + + friend exactSynthesisEngine; + }; + + + class KissatCmdEngine : public exactSynthesisEngine, public OneshotEngine { + + public: + KissatCmdEngine( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg); + Mini_Aig_t* getCircuit(int size, double timeout); + + private: + using exactSynthesisEngine::addClause; + + + int addClause( int * pLits, int nLits ); + Vec_Int_t * solve(int size, double timeout); + + FILE * encoding_file; + + // Ensure that there is no file with the same name in the diretory + constexpr static char * pFileNameIn = "_temp_.cnf"; + constexpr static char * pFileNameOut = "_temp_out.cnf"; + + #ifdef WIN32 + constexpr static char * pKissat = "kissat.exe"; + #else + constexpr static char * pKissat = "kissat"; + #endif + + friend exactSynthesisEngine; + }; + + + template + inline int exactSynthesisEngine::addClause(int lit1, int lit2, int lit3, int lit4) { + int clause[4] = {lit1, lit2, lit3, lit4}; + return static_cast(this)->addClause(clause, 4); + } + + template + inline int exactSynthesisEngine::getGateEnablingLiteral(int index, bool negated) { + return static_cast(this)->getGateEnablingLiteralImpl(index, negated); + } + + template + inline int exactSynthesisEngine::getAuxilaryVariableCount() { + int ncvars = connection_variables.empty() ? 0 : connection_variables.begin()->second.size() * connection_variables.size(); + return ncvars + static_cast(this)->getAuxilaryVariableCountDerived(); + } + + typedef OneshotManager CadicalOneShot; + typedef OneshotManager KissatOneShot; + typedef OneshotManager KissatCmdOneShot; + +} + +ABC_NAMESPACE_CXX_HEADER_END + +#include "synthesisEngine.tpp" + +#endif \ No newline at end of file diff --git a/src/opt/eslim/synthesisEngine.tpp b/src/opt/eslim/synthesisEngine.tpp new file mode 100644 index 000000000..cc1d3d610 --- /dev/null +++ b/src/opt/eslim/synthesisEngine.tpp @@ -0,0 +1,621 @@ +/**CFile**************************************************************** + + FileName [synthesisEngine.tpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Procedures for synthesising Boolean relations.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: synthesisEngine.tpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#include + +#include "misc/util/utilTruth.h" + +#include "synthesisEngine.hpp" +#include "utils.hpp" + +ABC_NAMESPACE_HEADER_START + Vec_Int_t * Exa4_ManParse( char * pFileName ); +ABC_NAMESPACE_HEADER_END + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + template + exactSynthesisEngine::exactSynthesisEngine( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : vSimsIn(vSimsIn), vSimsOut(vSimsOut), nIns(nIns), nDivs(nDivs), nNodes(nNodes), + nOuts(nOuts), forbidden_pairs(forbidden_pairs), log(log), cfg(cfg) { + assert( Vec_WrdSize(vSimsIn) == Vec_WrdSize(vSimsOut) ); + nObjs = nDivs + nNodes + nOuts; + nCnfVars = markup(); + introduceConnectionVariables(); + nCnfVars2 = 0; + nCnfClauses = 0; + assert( nObjs < 64 ); + } + + template + bool exactSynthesisEngine::isNormalized( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut ) { + int i, Count = 0; word Temp; + Vec_WrdForEachEntry( vSimsIn, Temp, i ) { + if ( Temp & 1 ) { + Count++; + } + } + if ( Count ) { + return false; + } + if ( !(Vec_WrdEntry(vSimsOut, 0) & 1) ) { + return false; + } + return true; + } + + template + int exactSynthesisEngine::markup() { + int i, k, j, nVars[3] = {1 + 3*nNodes, 0, 3*nNodes*Vec_WrdSize(vSimsIn)}; + assert( nObjs <= MAJ_NOBJS ); + for ( i = nDivs; i < nDivs + nNodes; i++ ) { + for ( k = 0; k < 2; k++ ) { + for ( j = 1+!k; j < i-k; j++ ) { + VarMarks[i][k][j] = nVars[0] + nVars[1]++; + } + } + } + for ( i = nDivs + nNodes; i < nObjs; i++ ) { + for ( j = 0; j < nDivs + nNodes; j++ ) { + VarMarks[i][0][j] = nVars[0] + nVars[1]++; + } + } + return nVars[0] + nVars[1] + nVars[2]; + } + + template + int exactSynthesisEngine::findFanin( Vec_Int_t * vValues, int i, int k, int nof_objs ) { + int j, Count = 0, iVar = -1; + for ( j = 0; j < nof_objs; j++ ) { + if ( VarMarks[i][k][j] && Vec_IntEntry(vValues, VarMarks[i][k][j]) ){ + iVar = j; + Count++; + } + } + assert( Count == 1 ); + return iVar; + } + + template + Mini_Aig_t * exactSynthesisEngine::getAig(Vec_Int_t * vValues) { + return getAig(vValues, nNodes); + } + + template + Mini_Aig_t * exactSynthesisEngine::getAig(Vec_Int_t * vValues, int size) { + assert (size >= 0 && size <= nNodes && "Invalid size for AIG construction given."); + int i, k, Compl[MAJ_NOBJS] = {0}; + int nof_Objs = nDivs + size + nOuts; + Mini_Aig_t * pMini = Mini_AigStartSupport( nDivs-1, nof_Objs ); + for ( i = nDivs; i < nDivs + size; i++ ) { + int iNodes[2] = {0}; + int iVarStart = 1 + 3*(i - nDivs);// + int Val1 = Vec_IntEntry(vValues, iVarStart); + int Val2 = Vec_IntEntry(vValues, iVarStart+1); + int Val3 = Vec_IntEntry(vValues, iVarStart+2); + Compl[i] = Val1 && Val2 && Val3; + for ( k = 0; k < 2; k++ ) { + int iNode = findFanin(vValues, i, !k, nof_Objs); + int fComp = k ? !Val1 && Val2 && !Val3 : Val1 && !Val2 && !Val3; + iNodes[k] = Abc_Var2Lit(iNode, fComp ^ Compl[iNode]); + } + if ( Val1 && Val2 ) { + if ( Val3 ) { + Mini_AigOr( pMini, iNodes[0], iNodes[1] ); + } else { + Mini_AigXorSpecial( pMini, iNodes[0], iNodes[1] ); + } + } else { + Mini_AigAnd( pMini, iNodes[0], iNodes[1] ); + } + } + for ( i = nDivs + nNodes; i < nObjs; i++ ) { + int iVar = findFanin( vValues, i, 0, nof_Objs); + Mini_AigCreatePo( pMini, Abc_Var2Lit(iVar, Compl[iVar]) ); + } + assert( nof_Objs == Mini_AigNodeNum(pMini) ); + return pMini; + } + + template + void exactSynthesisEngine::generateCNF( int fOrderNodes, int fUniqFans ) { + int m; + startEncoding( fOrderNodes, fUniqFans ); + // Ignore pattern for all false input pattern (as we start with m=1) + for ( m = 1; m < Vec_WrdSize(vSimsIn); m++ ) { + generateMinterm( m ); + } + + if (forbidden_pairs.size() > 0) { + addConnectivityConstraints(); + } + } + + template + void exactSynthesisEngine::introduceConnectionVariables() { + std::unordered_set inputs_in_pairs; + // for (const auto& [out, inputs] : forbidden_pairs) { + for (const auto& it: forbidden_pairs) { + const auto& inputs = it.second; + inputs_in_pairs.insert(inputs.begin(), inputs.end()); + } + int nCVars = nObjs - 1; // The constant node does not depend on any node + for (int in : inputs_in_pairs) { + connection_variables.emplace(in, std::vector (nCVars, 0)); + std::iota(connection_variables[in].begin(), connection_variables[in].end(), nCnfVars); + nCnfVars += nCVars; + } + } + + template + void exactSynthesisEngine::setupConnectionVariables() { + // for (const auto& [in, cvars] : connection_variables) { + for (const auto& it: connection_variables) { + const auto& in = it.first; + const auto& cvars = it.second; + addClause(Abc_Var2Lit(cvars[in],0),0,0,0); + for (int i = nDivs; i < nDivs + nNodes; i++ ) { + int gate_idx = i - nDivs; + for (int j = 1; j < i - 1; j++) { + addClause(Abc_Var2Lit(VarMarks[i][0][j + 1], 1), Abc_Var2Lit(cvars[j], 1), Abc_Var2Lit(cvars[i - 1], 0), getGateEnablingLiteral(gate_idx, 1)); + addClause(Abc_Var2Lit(VarMarks[i][1][j], 1), Abc_Var2Lit(cvars[j - 1], 1), Abc_Var2Lit(cvars[i - 1], 0), getGateEnablingLiteral(gate_idx, 1)); + } + } + for (int i = nDivs + nNodes; i < nObjs; i++) { + for (int j = 1; j < nDivs + nNodes; j++) { + addClause(Abc_Var2Lit(VarMarks[i][0][j], 1), Abc_Var2Lit(cvars[j - 1], 1), Abc_Var2Lit(cvars[i - 1], 0),0); + } + } + } + } + + template + void exactSynthesisEngine::addConnectivityConstraints() { + assert (forbidden_pairs.size() > 0 && "Connectivity constraints are only needed if there are forbidden pairs."); + setupConnectionVariables(); + // If there are forbidden pairs for more than one input it is possible that a loop is obtained via two pairs + if (forbidden_pairs.size() > 1) { + addCombinedCycleConstraints(); + } + + // for (const auto& [out, inputs] : forbidden_pairs) { + for (const auto& it: forbidden_pairs) { + const auto& out = it.first; + const auto& inputs = it.second; + for (int in : inputs) { + const auto& cvars = connection_variables.at(in); + int out_obj_idx = nDivs + nNodes + out; + addClause(Abc_Var2Lit(cvars[out_obj_idx - 1], 1), 0, 0, 0); + } + } + } + + template + void exactSynthesisEngine::addCombinedCycleConstraints() { + assert (forbidden_pairs.size() > 1 && "Combined connectivity constraints are only needed if there are forbidden pairs for multiple inputs."); + std::unordered_map> not_in_pair = computeNotInPair(forbidden_pairs); + + // for (const auto& [out, inputs] : not_in_pair) { + for (const auto& it: not_in_pair) { + const auto& out = it.first; + const auto& inputs = it.second; + for (int in : inputs) { + const auto& cvars = connection_variables.at(in); + int out_obj_idx = nDivs + nNodes + out; + for (int in2 : forbidden_pairs.at(out)) { + addClause(Abc_Var2Lit(cvars[out_obj_idx - 1], 1), Abc_Var2Lit(cvars[in2], 0),0,0); + } + } + } + } + + template + std::unordered_map> exactSynthesisEngine::computeNotInPair(const std::unordered_map>& pairs) { + std::unordered_set all_inputs_in_pairs; + // for (const auto& [out, in] : pairs) { + for (const auto& it: pairs) { + const auto& in = it.second; + all_inputs_in_pairs.insert(in.begin(), in.end()); + } + std::unordered_map> not_in_pair; + // for (const auto& [out, in] : pairs) { + for (const auto& it: pairs) { + const auto& out = it.first; + const auto& in = it.second; + if (in.size() == all_inputs_in_pairs.size()) { + continue; + } + for (int i : all_inputs_in_pairs) { + if (in.find(i) == in.end()) { + not_in_pair[out].insert(i); + } + } + } + return not_in_pair; + } + + template + int exactSynthesisEngine::startEncoding(int fOrderNodes, int fUniqFans ) + { + int pLits[2*MAJ_NOBJS], i, j, k, n, m, nLits; + for ( i = nDivs; i < nDivs + nNodes; i++ ) + { + int gate_idx = i - nDivs; + int iVarStart = 1 + 3*(i - nDivs);// + for ( k = 0; k < 2; k++ ) + { + nLits = 0; + for ( j = 0; j < nObjs; j++ ) + if ( VarMarks[i][k][j] ) + pLits[nLits++] = Abc_Var2Lit( VarMarks[i][k][j], 0 ); + assert( nLits > 0 ); + static_cast(this)->addClause( pLits, nLits ); + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + addClause( Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), getGateEnablingLiteral(gate_idx, 1), 0 ); + if ( k == 1 ) + break; + for ( j = 0; j < nObjs; j++ ) if ( VarMarks[i][0][j] ) + for ( n = j; n < nObjs; n++ ) if ( VarMarks[i][1][n] ) + addClause( Abc_Var2Lit(VarMarks[i][0][j], 1), Abc_Var2Lit(VarMarks[i][1][n], 1), getGateEnablingLiteral(gate_idx, 1), 0 ); + } + if ( fOrderNodes ) + for ( j = nDivs; j < i; j++ ) + for ( n = 0; n < nObjs; n++ ) if ( VarMarks[i][0][n] ) + for ( m = n+1; m < nObjs; m++ ) if ( VarMarks[j][0][m] ) + addClause( Abc_Var2Lit(VarMarks[i][0][n], 1), Abc_Var2Lit(VarMarks[j][0][m], 1), getGateEnablingLiteral(gate_idx, 1), 0 ); + for ( j = nDivs; j < i; j++ ) + for ( k = 0; k < 2; k++ ) if ( VarMarks[i][k][j] ) + for ( n = 0; n < nObjs; n++ ) if ( VarMarks[i][!k][n] ) + for ( m = 0; m < 2; m++ ) if ( VarMarks[j][m][n] ) + addClause( Abc_Var2Lit(VarMarks[i][k][j], 1), Abc_Var2Lit(VarMarks[i][!k][n], 1), Abc_Var2Lit(VarMarks[j][m][n], 1), getGateEnablingLiteral(gate_idx, 1) ); + for ( k = 0; k < 3; k++ ) + addClause( Abc_Var2Lit(iVarStart, k==1), Abc_Var2Lit(iVarStart+1, k==2), Abc_Var2Lit(iVarStart+2, k!=0), getGateEnablingLiteral(gate_idx, 1)); + if ( !cfg.allow_xors ) + addClause( Abc_Var2Lit(iVarStart, 1), Abc_Var2Lit(iVarStart+1, 1), Abc_Var2Lit(iVarStart+2, 0), getGateEnablingLiteral(gate_idx, 1)); + + } + for ( i = nDivs; i < nDivs + nNodes; i++ ) + { + int gate_idx = i - nDivs; + nLits = 0; + for ( k = 0; k < 2; k++ ) + for ( j = i+1; j < nObjs; j++ ) + if ( VarMarks[j][k][i] ) + pLits[nLits++] = Abc_Var2Lit( VarMarks[j][k][i], 0 ); + if ( fUniqFans ) + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + addClause( Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), getGateEnablingLiteral(gate_idx, 1), 0 ); + } + for ( i = nDivs + nNodes; i < nObjs; i++ ) + { + static_cast(this)->addGateDeactivatedConstraint(i); + nLits = 0; + for ( j = 0; j < nDivs + nNodes; j++ ) if ( VarMarks[i][0][j] ) { + pLits[nLits++] = Abc_Var2Lit( VarMarks[i][0][j], 0 ); + } + static_cast(this)->addClause( pLits, nLits ); + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + addClause( Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), 0, 0 ); + } + return 1; + } + + template + void exactSynthesisEngine::generateMinterm( int iMint) { + int internalCnfVars = nCnfVars - getAuxilaryVariableCount(); // for each gate we add an assumption + int iNodeVar = internalCnfVars + 3*nNodes*(iMint - Vec_WrdSize(vSimsIn)); + int iOutMint = Abc_Tt6FirstBit( Vec_WrdEntry(vSimsOut, iMint) ); + int fOnlyOne = Abc_TtSuppOnlyOne( (int)Vec_WrdEntry(vSimsOut, iMint) ); + int i, k, n, j, VarVals[MAJ_NOBJS]; + int fAllOnes = Abc_TtCountOnes( Vec_WrdEntry(vSimsOut, iMint) ) == (1 << nOuts); + if ( fAllOnes ) + return; + assert( nObjs <= MAJ_NOBJS ); + assert( iMint < Vec_WrdSize(vSimsIn) ); + assert( nOuts <= 6 ); + for ( i = 0; i < nDivs; i++ ) { + VarVals[i] = (Vec_WrdEntry(vSimsIn, iMint) >> i) & 1; + } + for ( i = 0; i < nNodes; i++ ) { + VarVals[nDivs + i] = Abc_Var2Lit(iNodeVar + 3*i + 2, 0); + } + if ( fOnlyOne ) { + for ( i = 0; i < nOuts; i++ ) + VarVals[nDivs + nNodes + i] = (iOutMint >> i) & 1; + } else { + word t = Abc_Tt6Stretch( Vec_WrdEntry(vSimsOut, iMint), nOuts ); + int i, c, nCubes = 0, pCover[100], pLits[10]; + int iOutVar = nCnfVars + nCnfVars2; nCnfVars2 += nOuts; + for ( i = 0; i < nOuts; i++ ) { + VarVals[nDivs + nNodes + i] = Abc_Var2Lit(iOutVar + i, 0); + } + assert( t ); + if ( ~t ) { + Abc_Tt6IsopCover( ~t, ~t, nOuts, pCover, &nCubes ); + for ( c = 0; c < nCubes; c++ ) { + int nLits = 0; + for ( i = 0; i < nOuts; i++ ) { + int iLit = (pCover[c] >> (2*i)) & 3; + if ( iLit == 1 || iLit == 2 ) + pLits[nLits++] = Abc_Var2Lit(iOutVar + i, iLit != 1); + } + static_cast(this)->addClause( pLits, nLits ); + } + } + } + + for ( i = nDivs; i < nDivs + nNodes; i++ ) { + int iVarStart = 1 + 3*(i - nDivs);// + int iBaseVarI = iNodeVar + 3*(i - nDivs); + for ( k = 0; k < 2; k++ ) { + for ( j = 0; j < i; j++ ) { + if ( VarMarks[i][k][j] ) { + for ( n = 0; n < 2; n++ ) { + addClause( Abc_Var2Lit(VarMarks[i][k][j], 1), Abc_Var2Lit(iBaseVarI + k, n), Abc_LitNotCond(VarVals[j], !n), 0); + } + } + } + } + for ( k = 0; k < 4; k++ ) { + for ( n = 0; n < 2; n++ ) { + addClause( Abc_Var2Lit(iBaseVarI + 0, k&1), Abc_Var2Lit(iBaseVarI + 1, k>>1), Abc_Var2Lit(iBaseVarI + 2, !n), Abc_Var2Lit(k ? iVarStart + k-1 : 0, n)); + } + } + } + for ( i = nDivs + nNodes; i < nObjs; i++ ) { + for ( j = 0; j < nDivs + nNodes; j++ ) { + if ( VarMarks[i][0][j] ) { + for ( n = 0; n < 2; n++ ) { + addClause( Abc_Var2Lit(VarMarks[i][0][j], 1), Abc_LitNotCond(VarVals[j], n), Abc_LitNotCond(VarVals[i], !n), 0); + } + } + } + } + } + + template + int exactSynthesisEngine::prepareLits(int * pLits, int& nLits) { + int k = 0; + for ( int i = 0; i < nLits; i++ ) { + if ( pLits[i] == 1 ) + return 0; + else if ( pLits[i] == 0 ) + continue; + else if ( pLits[i] <= 2*(nCnfVars + nCnfVars2) ) + pLits[k++] = pLits[i]; + else assert( 0 ); + } + nLits = k; + return 1; + } + + inline CadicalEngine::CadicalEngine(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : exactSynthesisEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, forbidden_pairs, log, cfg) { + gate_enabling_assumptions.reserve(nNodes); + for (int i = 0; i < nNodes; i++) { + gate_enabling_assumptions.push_back(nCnfVars + i); + } + nCnfVars += nNodes; + generateCNF(0, 0); + } + + inline int CadicalEngine::addClause( int * pLits, int nLits ) { + if (prepareLits(pLits, nLits) == 0) { + return 0; + } + assert( nLits > 0 ); + solver.addClause(pLits, nLits); + return 1; + } + + inline Vec_Int_t * CadicalEngine::solve( int size, double timeout) { + std::vector assumptions = getAssumptions(size); + solver.assume(assumptions); + int status = timeout > 0 ? solver.solve(timeout) : solver.solve(); + Vec_Int_t * vRes = status == 10 ? solver.getModelVec() : nullptr; + if (status == 10) { + log.cummulative_sat_runtimes_per_size[size] += solver.getRunTime(); + log.nof_sat_calls_per_size[size] ++; + } else if (status == 20) { + log.cummulative_unsat_runtimes_per_size[size] += solver.getRunTime(); + log.nof_unsat_calls_per_size[size] ++; + } + return vRes; + } + + Mini_Aig_t* CadicalEngine::getCircuit(int size, double timeout) { + addAssumptions(size); + Vec_Int_t * vValues = solve(size, timeout); + Mini_Aig_t * pMini = vValues ? getAig(vValues, size) : nullptr; + Vec_IntFreeP( &vValues ); + return pMini; + } + + inline std::vector CadicalEngine::getAssumptions(int size) { + std::vector assumptions(nNodes); + for (int i = 0; i < size; i++) { + assumptions[i] = gate_enabling_assumptions[i]; + } + for (int i = size; i < nNodes; i++) { + assumptions[i] = -gate_enabling_assumptions[i]; + } + return assumptions; + } + + inline void CadicalEngine::addGateDeactivatedConstraint(int out_idx) { + for (int j = nDivs; j < nDivs + nNodes; j++ ) { + int gate_idx = j - nDivs; + // if a gate is disabled then it shall not be an output + addClause( Abc_Var2Lit(VarMarks[out_idx][0][j],1), Abc_Var2Lit( gate_enabling_assumptions[gate_idx], 0 ), 0, 0 ); + } + } + + inline int CadicalEngine::getGateEnablingLiteralImpl(int index, bool negated) { + return Abc_Var2Lit( gate_enabling_assumptions[index], negated ); + } + + inline int CadicalEngine::getAuxilaryVariableCountDerived() { + return nNodes; // We add an assumption for each gate + } + + inline void CadicalEngine::addAssumptions(int size) { + solver.assume(getAssumptions(size)); + } + + template + OneshotManager::OneshotManager(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int maxnNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : vSimsIn(vSimsIn), vSimsOut(vSimsOut), nIns(nIns), nDivs(nDivs), maxnNodes(maxnNodes), nOuts(nOuts), forbidden_pairs(forbidden_pairs), log(log), cfg(cfg) { + } + + template + T OneshotManager::getOneshotEngine(int size) { + assert(size <= maxnNodes); + T oneshotEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, size, forbidden_pairs, log, cfg); + return oneshotEngine; + } + + template + Mini_Aig_t* OneshotManager::getCircuit(int size, double timeout) { + T synth = getOneshotEngine(size); + return synth.getCircuit(size, timeout); + } + + inline CadicalEngineOneShot::CadicalEngineOneShot( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : exactSynthesisEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, forbidden_pairs, log, cfg) { + } + + inline Vec_Int_t* CadicalEngineOneShot::solve( int size, double timeout) { + int status = timeout > 0 ? solver.solve(timeout) : solver.solve(); + Vec_Int_t * vRes = status != 10 ? nullptr : solver.getModelVec(); + return vRes; + } + + Mini_Aig_t* CadicalEngineOneShot::getCircuit(int size, double timeout) { + generateCNF(0, 0); + Vec_Int_t * vValues = solve(size, timeout); + Mini_Aig_t * pMini = vValues ? getAig(vValues, size) : nullptr; + Vec_IntFreeP( &vValues ); + return pMini; + } + + inline int CadicalEngineOneShot::addClause( int * pLits, int nLits ) { + if (prepareLits(pLits, nLits) == 0) { + return 0; + } + assert( nLits > 0 ); + solver.addClause(pLits, nLits); + return 1; + } + + inline KissatEngineOneShot::KissatEngineOneShot(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : exactSynthesisEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, forbidden_pairs, log, cfg) { + } + + Mini_Aig_t* KissatEngineOneShot::getCircuit(int size, double timeout) { + solver.init(nCnfVars); + generateCNF(0, 0); + Vec_Int_t * vValues = solve(size, timeout); + Mini_Aig_t * pMini = vValues ? getAig(vValues, size) : nullptr; + Vec_IntFreeP( &vValues ); + return pMini; + } + + inline Vec_Int_t *KissatEngineOneShot::solve( int size, double timeout) { + // TODO: The used interface does not yet allow timeouts + int status = solver.solve(); + Vec_Int_t * vRes = status != 10 ? nullptr : solver.getModelVec(); + return vRes; + } + + inline int KissatEngineOneShot::addClause( int * pLits, int nLits ) { + if (prepareLits(pLits, nLits) == 0) { + return 0; + } + assert( nLits > 0 ); + solver.addClause(pLits, nLits); + return 1; + } + + inline KissatCmdEngine::KissatCmdEngine(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes, + const std::unordered_map>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg) + : exactSynthesisEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, nNodes, forbidden_pairs, log, cfg) { + } + + Mini_Aig_t* KissatCmdEngine::getCircuit(int size, double timeout) { + encoding_file = fopen( pFileNameIn, "wb" ); + fputs( "p cnf \n", encoding_file ); + generateCNF(0, 0); + Vec_Int_t * vValues = solve(size, timeout); + Mini_Aig_t * pMini = vValues ? getAig(vValues, size) : nullptr; + Vec_IntFreeP( &vValues ); + return pMini; + } + + inline int KissatCmdEngine::addClause( int * pLits, int nLits ) { + if (prepareLits(pLits, nLits) == 0) { + return 0; + } + assert( nLits > 0 ); + if ( encoding_file ) { + nCnfClauses++; + for ( int i = 0; i < nLits; i++ ) { + fprintf( encoding_file, "%s%d ", Abc_LitIsCompl(pLits[i]) ? "-" : "", Abc_Lit2Var(pLits[i]) ); + } + fprintf( encoding_file, "0\n" ); + } + return 1; + } + + inline Vec_Int_t * KissatCmdEngine::solve(int size, double timeout) { + rewind( encoding_file ); + fprintf( encoding_file, "p cnf %d %d", nCnfVars + nCnfVars2, nCnfClauses ); + fclose( encoding_file ); + encoding_file = nullptr; + + char Command[1000], * pCommand = (char *)&Command; + + // TODO: + // if ( TimeOut ) + // sprintf( pCommand, "%s --time=%d -q %s > %s", pKissat, TimeOut, pFileNameIn, pFileNameOut ); + // else + // sprintf( pCommand, "%s -q %s > %s", pKissat, pFileNameIn, pFileNameOut ); + + sprintf( pCommand, "%s -q %s > %s", pKissat, pFileNameIn, pFileNameOut ); + if ( system( pCommand ) == -1 ) { + std::cerr << "Command " << pCommand << " failed\n"; + return nullptr; + } + Vec_Int_t * vRes = Exa4_ManParse( pFileNameOut ); + return vRes; + } + +} + +ABC_NAMESPACE_CXX_HEADER_END \ No newline at end of file diff --git a/src/opt/eslim/utils.hpp b/src/opt/eslim/utils.hpp new file mode 100644 index 000000000..bcf2262c1 --- /dev/null +++ b/src/opt/eslim/utils.hpp @@ -0,0 +1,103 @@ +/**CFile**************************************************************** + + FileName [utils.hpp] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).] + + Synopsis [Utilities for the eSLIM package.] + + Author [Franz-Xaver Reichl] + + Affiliation [University of Freiburg] + + Date [Ver. 1.0. Started - March 2025.] + + Revision [$Id: utils.hpp,v 1.00 2025/03/17 00:00:00 Exp $] + +***********************************************************************/ + +#ifndef ABC__OPT__ESLIM__UTILS_h +#define ABC__OPT__ESLIM__UTILS_h + +#include +#include +#include + +#include "misc/util/abc_namespaces.h" +#include "misc/vec/vec.h" +#include "aig/gia/gia.h" + +ABC_NAMESPACE_CXX_HEADER_START + +namespace eSLIM { + + struct eSLIMConfig { + bool extended_normality_processing = false; + bool apply_strash = true; + bool fix_seed = false; + bool fill_subcircuits = false; + bool trial_limit_active = true; + bool allow_xors = false; + + unsigned int timeout = 3600; + unsigned int iterations = 0; + unsigned int subcircuit_size_bound = 6; + unsigned int strash_intervall = 100; + int seed = 0; + unsigned int nselection_trials = 100; + double expansion_probability = 0.6; + + // times given in sec + int minimum_sat_timeout = 1; + int base_sat_timeout = 120; + int minimum_dynamic_timeout_sample_size = 50; + double dynamic_timeout_buffer_factor = 1.4; + + int verbose = 0; + }; + + struct eSLIMLog { + unsigned int iteration_count = 0; + double relation_generation_time = 0; + double synthesis_time = 0; + unsigned int subcircuits_with_forbidden_pairs = 0; + + std::vector nof_analyzed_circuits_per_size; + std::vector nof_replaced_circuits_per_size; + std::vector nof_reduced_circuits_per_size; + + std::vector cummulative_sat_runtimes_per_size; + std::vector nof_sat_calls_per_size; + std::vector cummulative_unsat_runtimes_per_size; + std::vector nof_unsat_calls_per_size; + + eSLIMLog(int size); + }; + + struct Subcircuit { + Vec_Int_t* nodes; + Vec_Int_t* io; + unsigned int nof_inputs; + std::unordered_map> forbidden_pairs; + void free(); + }; + + inline void Subcircuit::free() { + Vec_IntFree(nodes); + Vec_IntFree(io); + } + + inline eSLIMLog::eSLIMLog(int size) + : nof_analyzed_circuits_per_size(size + 1, 0), nof_replaced_circuits_per_size(size + 1, 0), + nof_reduced_circuits_per_size(size + 1, 0), cummulative_sat_runtimes_per_size(size + 1, 0), + nof_sat_calls_per_size(size + 1, 0), cummulative_unsat_runtimes_per_size(size + 1, 0), + nof_unsat_calls_per_size(size + 1, 0) { + } + +} + +ABC_NAMESPACE_CXX_HEADER_END + +#endif \ No newline at end of file From e3208881917163f949ef97759d8ebbc33ce11f7f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 19 Mar 2025 12:14:28 -0700 Subject: [PATCH 21/42] Adding structural guidance. --- src/sat/bmc/bmcMaj.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 3440ac514..5e85536ae 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -763,7 +763,28 @@ int Exa_ManSolverSolve( Exa_Man_t * p ) } int Exa_ManAddCnfStart( Exa_Man_t * p, int fOnlyAnd ) { - int pLits[MAJ_NOBJS], pLits2[3], i, j, k, n, m; + extern Vec_Int_t * Gia_ManKSatGenLevels( char * pGuide, int nIns, int nNodes ); + Vec_Int_t * vRes = p->pPars->pGuide ? Gia_ManKSatGenLevels( p->pPars->pGuide, p->nVars, p->nNodes ) : NULL; + int pLits[MAJ_NOBJS], pLits2[3], i, j, k, n, m, Start, Stop; + if ( vRes ) { + n = p->nVars; + Vec_IntForEachEntryDoubleStart( vRes, Start, Stop, i, 2*p->nVars ) { + for ( j = 0; j < Start; j++ ) + if ( p->VarMarks[n][0][j] ) { + pLits[0] = Abc_Var2Lit( p->VarMarks[n][0][j], 1 ); + Exa_ManAddClause( p, pLits, 1 ); + } + for ( k = 0; k < 2; k++ ) + for ( j = Stop; j < n; j++ ) + if ( p->VarMarks[n][k][j] ) { + pLits[0] = Abc_Var2Lit( p->VarMarks[n][k][j], 1 ); + Exa_ManAddClause( p, pLits, 1 ); + } + n++; + } + assert( n == p->nVars + p->nNodes ); + Vec_IntFreeP( &vRes ); + } // input constraints for ( i = p->nVars; i < p->nObjs; i++ ) { @@ -1959,6 +1980,7 @@ int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, n++; } assert( n == p->nDivs + p->nNodes ); + Vec_IntFreeP( &vRes ); } for ( i = p->nDivs; i < p->nDivs + p->nNodes; i++ ) { @@ -2039,7 +2061,6 @@ int Exa4_ManGenStart( Exa4_Man_t * p, int fOnlyAnd, int fFancy, int fOrderNodes, for ( m = n+1; m < nLits; m++ ) Exa4_ManAddClause4( p, Abc_LitNot(pLits[n]), Abc_LitNot(pLits[m]), 0, 0 ); } - Vec_IntFreeP( &vRes ); return 1; } void Exa4_ManGenMint( Exa4_Man_t * p, int iMint, int fOnlyAnd, int fFancy ) From f5ac2d4bd3fc749825795f18c795513e2e85a3b1 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 19 Mar 2025 12:20:25 -0700 Subject: [PATCH 22/42] Updates to LUT cascade decomposition. --- src/base/abci/abc.c | 42 +++++++++++++-- src/base/abci/abcCas.c | 118 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 154 insertions(+), 6 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 8ceb65167..95518cea6 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -8925,10 +8925,11 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern Abc_Ntk_t * Abc_NtkLutCascadeGen( int nLutSize, int nStages, int nRails, int nShared, int fVerbose ); extern Abc_Ntk_t * Abc_NtkLutCascade2( Abc_Ntk_t * pNtk, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, char * pGuide ); - Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pNtkRes; char * pGuide = NULL; - int c, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 1, fGen = 0, fVerbose = 0; + extern void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ); + Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pNtkRes; char * pGuide = NULL, * pFileName = NULL; + int c, nVarNum = -1, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 1, fGen = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KMRSIgvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KMRSINFgvh" ) ) != EOF ) { switch ( c ) { @@ -8987,6 +8988,26 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( nIters < 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; + } + nVarNum = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nVarNum < 0 ) + goto usage; + break; + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by a file name.\n" ); + goto usage; + } + pFileName = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'g': fGen ^= 1; break; @@ -8999,6 +9020,16 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } + if ( pFileName ) + { + if ( nVarNum == -1 ) + { + Abc_Print( -1, "The number of variables should be given on the command line using switch \"-N \".\n" ); + return 1; + } + Abc_NtkLutCascadeFile( pFileName, nVarNum, nLutSize, nStages, nRails, nIters, fVerbose ); + return 1; + } if ( fGen ) { pNtkRes = Abc_NtkLutCascadeGen( nLutSize, nStages, nRails, nShared, fVerbose ); @@ -9010,7 +9041,6 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); return 0; } - if ( pNtk == NULL ) { Abc_Print( -1, "Empty network.\n" ); @@ -9044,13 +9074,15 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutcasdec [-KMRSI ] [-vh]\n" ); + Abc_Print( -2, "usage: lutcasdec [-KMRSIN ] [-F ] [-vh]\n" ); Abc_Print( -2, "\t decomposes the primary output functions into LUT cascades\n" ); Abc_Print( -2, "\t-K : the number of LUT inputs [default = %d]\n", nLutSize ); Abc_Print( -2, "\t-M : the maximum delay (the number of stages) [default = %d]\n", nStages ); Abc_Print( -2, "\t-R : the number of direct connections (rails) [default = %d]\n", nRails ); Abc_Print( -2, "\t-S : the number of shared variables in each stage [default = %d]\n", nShared ); Abc_Print( -2, "\t-I : the number of iterations when looking for a solution [default = %d]\n", nIters ); + Abc_Print( -2, "\t-N : the number of support variables (for truth table files only) [default = unused]\n" ); + Abc_Print( -2, "\t-F : a text file with truth tables in hexadecimal listed one per line\n"); Abc_Print( -2, "\t-g : toggle generating random cascade with these parameters [default = %s]\n", fGen? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 3a5a2b808..8bddc27f4 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -500,7 +500,7 @@ static inline int Abc_LutCascadeDecStage( char * pGuide, int Iter, Vec_Wrd_t * v Vec_IntShrink( vVarIDs, nFVars+nSVars+nEVars ); return nEVars; } -static inline word * Abc_LutCascadeDec( char * pGuide, word * pTruth, Vec_Int_t * vVarIDs, int nRails, int nLutSize, int fVerbose ) +word * Abc_LutCascadeDec( char * pGuide, word * pTruth, Vec_Int_t * vVarIDs, int nRails, int nLutSize, int fVerbose ) { word * pRes = NULL; int i, nRVars = 0, nVars = Vec_IntSize(vVarIDs); Vec_Wrd_t * vFuncs[3] = { Vec_WrdStart(Abc_TtWordNum(nVars)), Vec_WrdAlloc(0), Vec_WrdAlloc(0) }; @@ -1079,6 +1079,122 @@ Abc_Ntk_t * Abc_NtkLutCascadeMap( Abc_Ntk_t * pNtk, int nLutsMax, int nIters, in } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarNum ) +{ + Vec_Wrd_t * vTruths = NULL; + int nWords = Abc_TtWordNum(nVarNum); + int nFileSize = Gia_FileSize( pFileName ); + FILE * pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) { printf("Cannot open file \"%s\" for reading.\n", pFileName); return NULL; } + word * pTruth = ABC_ALLOC( word, 2*nWords ); + char * pToken, * pLine = ABC_ALLOC( char, nFileSize ); + for ( int i = 0; fgets(pLine, nFileSize, pFile); i++ ) { + pToken = strtok(pLine, " ,\n\r\r"); + if ( pToken == NULL ) + continue; + if ( pToken[0] == '0' && pToken[1] == 'x' ) + pToken += 2; + if ( strlen(pToken) != (1 << (nVarNum-2)) ) { + printf( "Line %d has truth table of size %d while expected size is %d.\n", i, (int)strlen(pToken), 1 << (nVarNum-2) ); + Vec_WrdFreeP( &vTruths ); + break; + } + if ( !Abc_TtReadHex( pTruth, pToken ) ) { + printf( "Line %d has truth table that cannot be read correctly (%s).\n", i, pToken ); + Vec_WrdFreeP( &vTruths ); + break; + } + if ( vTruths == NULL ) + vTruths = Vec_WrdAlloc( 10000 ); + for ( int w = 0; w < nWords; w++ ) + Vec_WrdPush( vTruths, pTruth[w] ); + } + ABC_FREE( pTruth ); + ABC_FREE( pLine ); + fclose( pFile ); + return vTruths; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ) +{ + int nWords = Abc_TtWordNum(nVarNum); + Vec_Wrd_t * vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarNum ); + if ( vTruths == NULL ) + return; + + word * pCopy = ABC_ALLOC( word, nWords ); + int nFuncs = Vec_WrdSize(vTruths)/nWords; + printf( "Considering %d functions having %d variables from file \"%s\".\n", nFuncs, nVarNum, pFileName ); + for ( int i = 0; i < nFuncs; i++ ) + { + word * pTruth = Vec_WrdEntryP( vTruths, i*nWords ); + Abc_TtCopy( pCopy, pTruth, nWords, 0 ); + + if ( fVerbose ) + printf( "\n" ); + printf( "Function %3d : ", i ); + if ( fVerbose ) + Abc_TtPrintHexRev( stdout, pTruth, nVarNum ), printf( "\n" ); + //continue; + + int nVars = nVarNum; + Vec_Int_t * vVarIDs = Vec_IntStartNatural( nVars ); + Abc_TtMinimumBase( pTruth, Vec_IntArray(vVarIDs), nVars, &nVars ); + if ( fVerbose ) { + if ( Vec_IntSize(vVarIDs) != nVars ) + printf( "The support of the function is reduced from %d to %d variables.\n", Vec_IntSize(vVarIDs), nVars ); + printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs.\n", nVars, nRails, nLutSize ); + } + Vec_IntShrink( vVarIDs, nVars ); + + word * pLuts = Abc_LutCascadeDec( NULL, pTruth, vVarIDs, nRails, nLutSize, fVerbose ); + Vec_IntFree( vVarIDs ); + if ( pLuts == NULL ) { + printf( "Not decomposable.\n" ); + continue; + } + int nWords2 = Abc_TtWordNum(nVars); + word * pTruth2 = Abc_LutCascadeTruth( pLuts, nVars ); + if ( fVerbose ) + Abc_LutCascadePrint( pLuts ); + else + printf( "Decomposition exists. " ); + if ( !Abc_TtEqual(pTruth, pTruth2, nWords2) ) { + printf( "Verification FAILED.\n" ); + Abc_TtPrintHexRev( stdout, pCopy, nVarNum ), printf( "\n" ); + } + else + printf( "Verification passed.\n" ); + ABC_FREE( pTruth2 ); + ABC_FREE( pLuts ); + } + ABC_FREE( pCopy ); + Vec_WrdFree( vTruths ); + printf( "Finished decomposing functions from file \"%s\".\n", pFileName ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// From 938ae9428bcb565b94511995d2fddd49195e899a Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 28 Mar 2025 18:35:30 -0700 Subject: [PATCH 23/42] Extending interface of "permute". --- src/aig/saig/saigIso.c | 2 +- src/base/abc/abc.h | 2 +- src/base/abc/abcNtk.c | 175 +++++++++++++++++++++++++++-------------- src/base/abci/abc.c | 30 +++++-- src/base/io/ioResub.h | 4 +- 5 files changed, 143 insertions(+), 70 deletions(-) diff --git a/src/aig/saig/saigIso.c b/src/aig/saig/saigIso.c index 7ab8486e4..03ec21f3a 100644 --- a/src/aig/saig/saigIso.c +++ b/src/aig/saig/saigIso.c @@ -600,7 +600,7 @@ Aig_Man_t * Iso_ManTest888( Aig_Man_t * pAig1, int fVerbose ) Vec_Int_t * vMap; pNtk = Abc_NtkFromAigPhase( pAig1 ); - Abc_NtkPermute( pNtk, 1, 0, 1, NULL ); + Abc_NtkPermute( pNtk, 1, 0, 1, NULL, NULL, NULL ); pAig2 = Abc_NtkToDar( pNtk, 0, 1 ); Abc_NtkDelete( pNtk ); diff --git a/src/base/abc/abc.h b/src/base/abc/abc.h index ada1f499f..1d4bde4d7 100644 --- a/src/base/abc/abc.h +++ b/src/base/abc/abc.h @@ -792,7 +792,7 @@ extern ABC_DLL Abc_Ntk_t * Abc_NtkCreateWithNodes( Vec_Ptr_t * vSops ); extern ABC_DLL void Abc_NtkDelete( Abc_Ntk_t * pNtk ); extern ABC_DLL void Abc_NtkFixNonDrivenNets( Abc_Ntk_t * pNtk ); extern ABC_DLL void Abc_NtkMakeComb( Abc_Ntk_t * pNtk, int fRemoveLatches ); -extern ABC_DLL void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, char * pFlopPermFile ); +extern ABC_DLL void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, char * pInPermFile, char * pOutPermFile, char * pFlopPermFile ); extern ABC_DLL void Abc_NtkUnpermute( Abc_Ntk_t * pNtk ); extern ABC_DLL Abc_Ntk_t * Abc_NtkCreateFromSops( char * pName, Vec_Ptr_t * vSops ); extern ABC_DLL Abc_Ntk_t * Abc_NtkCreateFromGias( char * pName, Vec_Ptr_t * vGias, Gia_Man_t * pMulti ); diff --git a/src/base/abc/abcNtk.c b/src/base/abc/abcNtk.c index 5ea38cc12..45a479cf2 100644 --- a/src/base/abc/abcNtk.c +++ b/src/base/abc/abcNtk.c @@ -2059,11 +2059,11 @@ void Abc_NtkRemovePo( Abc_Ntk_t * pNtk, int iOutput, int fRemoveConst0 ) SeeAlso [] ***********************************************************************/ -Vec_Int_t * Abc_NtkReadFlopPerm( char * pFileName, int nFlops ) +Vec_Int_t * Abc_NtkReadSignalPerm( char * pFileName, int nSignals ) { char Buffer[1000]; FILE * pFile; - Vec_Int_t * vFlops; + Vec_Int_t * vSignals; int iFlop = -1; pFile = fopen( pFileName, "rb" ); if ( pFile == NULL ) @@ -2071,29 +2071,29 @@ Vec_Int_t * Abc_NtkReadFlopPerm( char * pFileName, int nFlops ) printf( "Cannot open input file \"%s\".\n", pFileName ); return NULL; } - vFlops = Vec_IntAlloc( nFlops ); + vSignals = Vec_IntAlloc( nSignals ); while ( fgets( Buffer, 1000, pFile ) != NULL ) { if ( Buffer[0] == ' ' || Buffer[0] == '\r' || Buffer[0] == '\n' ) continue; iFlop = atoi( Buffer ); - if ( iFlop < 0 || iFlop >= nFlops ) + if ( iFlop < 0 || iFlop >= nSignals ) { - printf( "Flop ID (%d) is out of range.\n", iFlop ); + printf( "Signal ID (%d) is out of range.\n", iFlop ); fclose( pFile ); - Vec_IntFree( vFlops ); + Vec_IntFree( vSignals ); return NULL; } - Vec_IntPush( vFlops, iFlop ); + Vec_IntPush( vSignals, iFlop ); } fclose( pFile ); - if ( Vec_IntSize(vFlops) != nFlops ) + if ( Vec_IntSize(vSignals) != nSignals ) { - printf( "The number of flops read in from file (%d) is different from the number of flops in the circuit (%d).\n", iFlop, nFlops ); - Vec_IntFree( vFlops ); + printf( "The number of indexes read in from file (%d) is different from the number of signals in the circuit (%d).\n", iFlop, nSignals ); + Vec_IntFree( vSignals ); return NULL; } - return vFlops; + return vSignals; } /**Function************************************************************* @@ -2106,61 +2106,98 @@ Vec_Int_t * Abc_NtkReadFlopPerm( char * pFileName, int nFlops ) SeeAlso [] ***********************************************************************/ -void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, char * pFlopPermFile ) +void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, char * pInPermFile, char * pOutPermFile, char * pFlopPermFile ) { Abc_Obj_t * pTemp; Vec_Int_t * vInputs, * vOutputs, * vFlops, * vTemp; int i, k, Entry; // start permutation arrays + if ( pInPermFile ) + { + vInputs = Abc_NtkReadSignalPerm( pInPermFile, Abc_NtkPiNum(pNtk) ); + if ( vInputs == NULL ) + return; + fInputs = 1; + } + else + vInputs = Vec_IntStartNatural( Abc_NtkPiNum(pNtk) ); + if ( pOutPermFile ) + { + vOutputs = Abc_NtkReadSignalPerm( pOutPermFile, Abc_NtkPoNum(pNtk) ); + if ( vOutputs == NULL ) + return; + fOutputs = 1; + } + else + vOutputs = Vec_IntStartNatural( Abc_NtkPoNum(pNtk) ); if ( pFlopPermFile ) { - vFlops = Abc_NtkReadFlopPerm( pFlopPermFile, Abc_NtkLatchNum(pNtk) ); + vFlops = Abc_NtkReadSignalPerm( pFlopPermFile, Abc_NtkLatchNum(pNtk) ); if ( vFlops == NULL ) return; - fInputs = 0; - fOutputs = 0; - fFlops = 0; + fFlops = 1; } else vFlops = Vec_IntStartNatural( Abc_NtkLatchNum(pNtk) ); - vInputs = Vec_IntStartNatural( Abc_NtkPiNum(pNtk) ); - vOutputs = Vec_IntStartNatural( Abc_NtkPoNum(pNtk) ); // permute inputs + Vec_Ptr_t * vCis = Vec_PtrDup(pNtk->vCis); + Vec_Ptr_t * vCos = Vec_PtrDup(pNtk->vCos); + Vec_Ptr_t * vFfs = Vec_PtrDup(pNtk->vBoxes); if ( fInputs ) for ( i = 0; i < Abc_NtkPiNum(pNtk); i++ ) { - k = rand() % Abc_NtkPiNum(pNtk); - // swap indexes - Entry = Vec_IntEntry( vInputs, i ); - Vec_IntWriteEntry( vInputs, i, Vec_IntEntry(vInputs, k) ); - Vec_IntWriteEntry( vInputs, k, Entry ); - // swap PIs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPis, i ); - Vec_PtrWriteEntry( pNtk->vPis, i, Vec_PtrEntry(pNtk->vPis, k) ); - Vec_PtrWriteEntry( pNtk->vPis, k, pTemp ); - // swap CIs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, i ); - Vec_PtrWriteEntry( pNtk->vCis, i, Vec_PtrEntry(pNtk->vCis, k) ); - Vec_PtrWriteEntry( pNtk->vCis, k, pTemp ); + if ( pInPermFile ) + { + k = Vec_IntEntry( vInputs, i ); + pTemp = (Abc_Obj_t *)Vec_PtrEntry( vCis, k ); + Vec_PtrWriteEntry( pNtk->vPis, i, pTemp ); + Vec_PtrWriteEntry( pNtk->vCis, i, pTemp ); + } + else + { + k = rand() % Abc_NtkPiNum(pNtk); + // swap indexes + Entry = Vec_IntEntry( vInputs, i ); + Vec_IntWriteEntry( vInputs, i, Vec_IntEntry(vInputs, k) ); + Vec_IntWriteEntry( vInputs, k, Entry ); + // swap PIs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPis, i ); + Vec_PtrWriteEntry( pNtk->vPis, i, Vec_PtrEntry(pNtk->vPis, k) ); + Vec_PtrWriteEntry( pNtk->vPis, k, pTemp ); + // swap CIs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, i ); + Vec_PtrWriteEntry( pNtk->vCis, i, Vec_PtrEntry(pNtk->vCis, k) ); + Vec_PtrWriteEntry( pNtk->vCis, k, pTemp ); + } //printf( "Swapping PIs %d and %d.\n", i, k ); } // permute outputs if ( fOutputs ) for ( i = 0; i < Abc_NtkPoNum(pNtk); i++ ) { - k = rand() % Abc_NtkPoNum(pNtk); - // swap indexes - Entry = Vec_IntEntry( vOutputs, i ); - Vec_IntWriteEntry( vOutputs, i, Vec_IntEntry(vOutputs, k) ); - Vec_IntWriteEntry( vOutputs, k, Entry ); - // swap POs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPos, i ); - Vec_PtrWriteEntry( pNtk->vPos, i, Vec_PtrEntry(pNtk->vPos, k) ); - Vec_PtrWriteEntry( pNtk->vPos, k, pTemp ); - // swap COs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, i ); - Vec_PtrWriteEntry( pNtk->vCos, i, Vec_PtrEntry(pNtk->vCos, k) ); - Vec_PtrWriteEntry( pNtk->vCos, k, pTemp ); + if ( pOutPermFile ) + { + k = Vec_IntEntry( vOutputs, i ); + pTemp = (Abc_Obj_t *)Vec_PtrEntry( vCos, k ); + Vec_PtrWriteEntry( pNtk->vPos, i, pTemp ); + Vec_PtrWriteEntry( pNtk->vCos, i, pTemp ); + } + else + { + k = rand() % Abc_NtkPoNum(pNtk); + // swap indexes + Entry = Vec_IntEntry( vOutputs, i ); + Vec_IntWriteEntry( vOutputs, i, Vec_IntEntry(vOutputs, k) ); + Vec_IntWriteEntry( vOutputs, k, Entry ); + // swap POs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vPos, i ); + Vec_PtrWriteEntry( pNtk->vPos, i, Vec_PtrEntry(pNtk->vPos, k) ); + Vec_PtrWriteEntry( pNtk->vPos, k, pTemp ); + // swap COs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, i ); + Vec_PtrWriteEntry( pNtk->vCos, i, Vec_PtrEntry(pNtk->vCos, k) ); + Vec_PtrWriteEntry( pNtk->vCos, k, pTemp ); + } //printf( "Swapping POs %d and %d.\n", i, k ); } // permute flops @@ -2168,26 +2205,42 @@ void Abc_NtkPermute( Abc_Ntk_t * pNtk, int fInputs, int fOutputs, int fFlops, ch if ( fFlops ) for ( i = 0; i < Abc_NtkLatchNum(pNtk); i++ ) { - k = rand() % Abc_NtkLatchNum(pNtk); - // swap indexes - Entry = Vec_IntEntry( vFlops, i ); - Vec_IntWriteEntry( vFlops, i, Vec_IntEntry(vFlops, k) ); - Vec_IntWriteEntry( vFlops, k, Entry ); - // swap flops - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vBoxes, i ); - Vec_PtrWriteEntry( pNtk->vBoxes, i, Vec_PtrEntry(pNtk->vBoxes, k) ); - Vec_PtrWriteEntry( pNtk->vBoxes, k, pTemp ); - // swap CIs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i ); - Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i, Vec_PtrEntry(pNtk->vCis, Abc_NtkPiNum(pNtk)+k) ); - Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+k, pTemp ); - // swap COs - pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i ); - Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i, Vec_PtrEntry(pNtk->vCos, Abc_NtkPoNum(pNtk)+k) ); - Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+k, pTemp ); + if ( pFlopPermFile ) + { + k = Vec_IntEntry( vFlops, i ); + pTemp = (Abc_Obj_t *)Vec_PtrEntry( vFfs, k ); + Vec_PtrWriteEntry( pNtk->vBoxes, i, pTemp ); + pTemp = (Abc_Obj_t *)Vec_PtrEntry( vCis, Abc_NtkPiNum(pNtk)+k ); + Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i, pTemp ); + pTemp = (Abc_Obj_t *)Vec_PtrEntry( vCos, Abc_NtkPoNum(pNtk)+k ); + Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i, pTemp ); + } + else + { + k = rand() % Abc_NtkLatchNum(pNtk); + // swap indexes + Entry = Vec_IntEntry( vFlops, i ); + Vec_IntWriteEntry( vFlops, i, Vec_IntEntry(vFlops, k) ); + Vec_IntWriteEntry( vFlops, k, Entry ); + // swap flops + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vBoxes, i ); + Vec_PtrWriteEntry( pNtk->vBoxes, i, Vec_PtrEntry(pNtk->vBoxes, k) ); + Vec_PtrWriteEntry( pNtk->vBoxes, k, pTemp ); + // swap CIs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i ); + Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+i, Vec_PtrEntry(pNtk->vCis, Abc_NtkPiNum(pNtk)+k) ); + Vec_PtrWriteEntry( pNtk->vCis, Abc_NtkPiNum(pNtk)+k, pTemp ); + // swap COs + pTemp = (Abc_Obj_t *)Vec_PtrEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i ); + Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+i, Vec_PtrEntry(pNtk->vCos, Abc_NtkPoNum(pNtk)+k) ); + Vec_PtrWriteEntry( pNtk->vCos, Abc_NtkPoNum(pNtk)+k, pTemp ); + } //printf( "Swapping flops %d and %d.\n", i, k ); } + Vec_PtrFree(vCis); + Vec_PtrFree(vCos); + Vec_PtrFree(vFfs); // invert arrays vInputs = Vec_IntInvert( vTemp = vInputs, -1 ); Vec_IntFree( vTemp ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 95518cea6..75504ad91 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -26067,7 +26067,7 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) extern Abc_Ntk_t * Abc_NtkRestrashRandom( Abc_Ntk_t * pNtk ); extern void Abc_NtkPermutePiUsingFanout( Abc_Ntk_t * pNtk ); Abc_Ntk_t * pNtk = pAbc->pNtkCur, * pNtkRes = NULL; - char * pFlopPermFile = NULL; + char * pFlopPermFile = NULL, * pInPermFile = NULL, * pOutPermFile = NULL; int fInputs = 1; int fOutputs = 1; int fFlops = 1; @@ -26076,7 +26076,7 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) int Seed = -1; int c; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "SFiofnxh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "SIOFiofnxh" ) ) != EOF ) { switch ( c ) { @@ -26091,6 +26091,24 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( Seed < 0 ) goto usage; break; + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by a file name.\n" ); + goto usage; + } + pInPermFile = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'O': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-O\" should be followed by a file name.\n" ); + goto usage; + } + pOutPermFile = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'F': if ( globalUtilOptind >= argc ) { @@ -26153,12 +26171,12 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Command \"permute\" has failed.\n" ); return 1; } - Abc_NtkPermute( pNtkRes, fInputs, fOutputs, fFlops, pFlopPermFile ); + Abc_NtkPermute( pNtkRes, fInputs, fOutputs, fFlops, pInPermFile, pOutPermFile, pFlopPermFile ); Abc_FrameReplaceCurrentNetwork( pAbc, pNtkRes ); return 0; usage: - Abc_Print( -2, "usage: permute [-S num] [-iofnxh] [-F filename]\n" ); + Abc_Print( -2, "usage: permute [-S num] [-iofnxh] [-I filename] [-O filename] [-F filename]\n" ); Abc_Print( -2, "\t performs random permutation of inputs/outputs/flops\n" ); Abc_Print( -2, "\t-S num : the random seed to generate permutations (0 <= num < INT_MAX) [default = %d]\n", Seed ); Abc_Print( -2, "\t-i : toggle permuting primary inputs [default = %s]\n", fInputs? "yes": "no" ); @@ -26167,6 +26185,8 @@ usage: Abc_Print( -2, "\t-n : toggle deriving new topological ordering of nodes [default = %s]\n", fNodes? "yes": "no" ); Abc_Print( -2, "\t-x : toggle permuting inputs based on their fanout count [default = %s]\n", fFanout? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t-I : (optional) file with the input permutation\n" ); + Abc_Print( -2, "\t-O : (optional) file with the output permutation\n" ); Abc_Print( -2, "\t-F : (optional) file with the flop permutation\n" ); return 1; } @@ -30881,7 +30901,7 @@ int Abc_CommandBm2( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } - Abc_NtkPermute(pNtk2, 1, 1, 0, NULL ); + Abc_NtkPermute(pNtk2, 1, 1, 0, NULL, NULL, NULL ); Abc_NtkShortNames(pNtk2); Abc_NtkForEachCi( pNtk1, pObj, i ) { diff --git a/src/base/io/ioResub.h b/src/base/io/ioResub.h index bd5175fbe..e566a0492 100644 --- a/src/base/io/ioResub.h +++ b/src/base/io/ioResub.h @@ -282,8 +282,8 @@ static inline Abc_RData_t * Abc_RData2Rel( Abc_RData_t * p ) Vec_WrdShrink( vTransOut, p->nPats ); Vec_Wrd_t * vTransInCopy = Vec_WrdDup(vTransIn); Vec_WrdUniqify( vTransInCopy ); - if ( Vec_WrdSize(vTransInCopy) == p->nPats ) - printf( "This resub problem is not a relation.\n" ); +// if ( Vec_WrdSize(vTransInCopy) == p->nPats ) +// printf( "This resub problem is not a relation.\n" ); // create the relation Abc_RData_t * pNew = Abc_RDataStart( p->nIns, 1 << (p->nOuts-1), Vec_WrdSize(vTransInCopy) ); pNew->nOuts = p->nOuts; From 244272052858599fef845f84a6c6b35b9996d73b Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 29 Mar 2025 11:11:13 -0700 Subject: [PATCH 24/42] Adding counter generation to "symfun". --- src/base/abc/abcSop.c | 30 ++++++++++++++++++++++++++++++ src/base/abci/abc.c | 25 ++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/base/abc/abcSop.c b/src/base/abc/abcSop.c index f24c55593..adc1639a6 100644 --- a/src/base/abc/abcSop.c +++ b/src/base/abc/abcSop.c @@ -21,6 +21,11 @@ #include "abc.h" #include "bool/kit/kit.h" +#ifdef _MSC_VER +# include +# define __builtin_popcount __popcnt +#endif + ABC_NAMESPACE_IMPL_START @@ -1135,6 +1140,31 @@ Vec_Ptr_t * Abc_SopFromTruthsHex( char * pTruth ) return vRes; } +Vec_Ptr_t * Abc_SopGenerateCounters( int nVars ) +{ + int m, i, o, nOuts = Abc_Base2Log( nVars + 1 ); + Vec_Ptr_t * vRes = Vec_PtrAlloc( nOuts ); + for ( o = 0; o < nOuts; o++ ) + { + Vec_Str_t * vStr = Vec_StrAlloc( 1000 ); + for ( m = 0; m < (1 << nVars); m++ ) { + int nOnes = __builtin_popcount(m); + if ( !((nOnes >> o) & 1) ) + continue; + for ( i = 0; i < nVars; i++ ) + Vec_StrPush( vStr, ((m >> i) & 1) ? '1' : '0' ); + Vec_StrPush( vStr, ' ' ); + Vec_StrPush( vStr, '1' ); + Vec_StrPush( vStr, '\n' ); + } + Vec_StrPush( vStr, '\0' ); + //printf( "%s\n", Vec_StrArray(vStr) ); + Vec_PtrPush( vRes, Vec_StrReleaseArray(vStr) ); + Vec_StrFree( vStr ); + } + return vRes; +} + /**Function************************************************************* Synopsis [Creates one encoder node.] diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 75504ad91..e52c1f4ee 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -25966,9 +25966,9 @@ int Abc_CommandSymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) extern void Ntk_SymFunGenerate( int nVars, int fVerbose ); word * pFun = NULL; char * pStr, * pTruth, * pCommand; - int c, k, nVars = -1, fVerbose = 0; + int c, k, nVars = -1, fCounter = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "Nvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "Ncvh" ) ) != EOF ) { switch ( c ) { @@ -25981,6 +25981,9 @@ int Abc_CommandSymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) nVars = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'c': + fCounter ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -25991,6 +25994,21 @@ int Abc_CommandSymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } + if ( fCounter ) + { + if ( nVars == -1 ) + { + printf( "The number of variables should be specified on the command line using \"-N \".\n" ); + return 1; + } + extern Vec_Ptr_t * Abc_SopGenerateCounters( int nVars ); + Vec_Ptr_t * vSops = Abc_SopGenerateCounters( nVars ); + Abc_Ntk_t * pNtk = Abc_NtkCreateWithNodes( vSops ); + Vec_PtrFreeFree( vSops ); + Abc_FrameReplaceCurrentNetwork( pAbc, pNtk ); + Abc_FrameClearVerifStatus( pAbc ); + return 0; + } if ( nVars != -1 ) { if ( nVars < 1 || nVars > 16 ) @@ -26040,9 +26058,10 @@ int Abc_CommandSymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: symfun [-N num] [-vh] \n" ); + Abc_Print( -2, "usage: symfun [-N num] [-cvh] \n" ); Abc_Print( -2, "\t generated a single-output symmetric function\n" ); Abc_Print( -2, "\t-N : prints truth tables of all N-var symmetric functions [default = not used]\n" ); + Abc_Print( -2, "\t-c : toggle generating a counter [default = %s]\n", fCounter? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\t : the string of N+1 zeros and ones, where N is the number of variables\n" ); From bb11cc4c46e8bea5096f0de1dfcb6f7d59e6c7b0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 29 Mar 2025 15:37:22 -0700 Subject: [PATCH 25/42] Experiments with adder-tree mapping. --- src/base/abc/abcUtil.c | 160 +++++++++++++++++++++++++++++++++++++++++ src/base/abci/abc.c | 78 +++++++++++++++++++- 2 files changed, 237 insertions(+), 1 deletion(-) diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index 88a16e7b6..812256a1d 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -24,6 +24,7 @@ #include "bool/dec/dec.h" #include "opt/fxu/fxu.h" #include "aig/miniaig/ndr.h" +#include "misc/util/utilTruth.h" #ifdef ABC_USE_CUDD #include "bdd/extrab/extraBdd.h" @@ -3352,6 +3353,165 @@ Abc_Ntk_t * Abc_NtkFromArray() return pNtkNew; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_PrintAT( Vec_Int_t * vRanks ) +{ + int i, Entry; + Vec_IntForEachEntryReverse( vRanks, Entry, i ) + if ( Entry == 0 ) + printf( " " ); + else + printf( "%4d", Entry ); + //printf( "\n" ); +} +int Abc_NtkMatchGpcPattern( Vec_Int_t * vRanks, int i, char * pGPC ) +{ + int k, Cur, Min = ABC_INFINITY; + for ( k = 0; pGPC[k] != ':' && i+k < Vec_IntSize(vRanks); k++ ) { + Cur = Vec_IntEntry(vRanks, i+k) / Abc_TtReadHexDigit(pGPC[k]); + if ( Min > Cur ) + Min = Cur; + } + return Min; +} +void Abc_NtkUpdateGpcPattern( Vec_Int_t * vRank, int i, char * pGPC, int nGpcs, Vec_Int_t * vRank2, Vec_Int_t * vLevel ) +{ + int k; char * pOut = strstr(pGPC, ":"); + assert( pOut && pOut[0] == ':' ); + pOut++; + Vec_IntAddToEntry( vLevel, i, nGpcs ); + for ( k = 0; pGPC[k] != ':'; k++ ) + Vec_IntAddToEntry( vRank, i+k, -nGpcs * Abc_TtReadHexDigit(pGPC[k]) ); + for ( k = 0; pOut[k] != ':'; k++ ) + Vec_IntAddToEntry( vRank2, i+k, nGpcs * Abc_TtReadHexDigit(pOut[k]) ); +} +int Abc_NtkGetGpcLutCount( char * pGPC ) +{ + char * pOut = strstr(pGPC, ":"); + char * pLut = strstr(pOut+1, ":"); + return atoi(pLut+1); +} +static inline int Vec_WecSum( Vec_Wec_t * p ) +{ + Vec_Int_t * vVec; + int i, Counter = 0; + Vec_WecForEachLevel( p, vVec, i ) + Counter += Vec_IntSum(vVec); + return Counter; +} +char ** Abc_NtkTransformGPCs( char ** pGPCs, int nGPCs ) +{ + char * pOut, * pLut, ** pRes = ABC_ALLOC( char *, nGPCs ); + int i, k, nLength; + for ( i = 0; i < nGPCs; i++ ) { + pRes[i] = Abc_UtilStrsav(pGPCs[i]); + pOut = strstr(pRes[i], ":"); + nLength = (int)(pOut-pRes[i]); + for ( k = 0; k < nLength/2; k++ ) + ABC_SWAP( char, pRes[i][k], pRes[i][nLength-1-k] ) + pLut = strstr(pOut+1, ":"); + nLength = (int)(pLut-pOut-1); + for ( k = 0; k < nLength/2; k++ ) + ABC_SWAP( char, pOut[1+k], pOut[1+nLength-1-k] ) + } + return pRes; +} +void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fVerbose ) +{ + abctime clkStart = Abc_Clock(); + char ** pGPCs = Abc_NtkTransformGPCs(pGPCs0, nGPCs); + int i, nGPCluts[100] = {0}; + for ( i = 0; i < nGPCs; i++ ) + nGPCluts[i] = Abc_NtkGetGpcLutCount(pGPCs[i]); + int x, n, Entry, iLevel = 0, Sum = 0, nGpcs = 0, nBits, fFinished, nLuts = 0; + for ( x = 0; x < nXVars; x++ ) + Sum += (1 << x) * nYVars; + nBits = Abc_Base2Log( Sum ); + printf( "Rectangular adder tree (X=%d Y=%d Sum=%d Out=%d) mapped with", nXVars, nYVars, Sum, nBits ); + for ( i = 0; i < nGPCs; i++ ) + printf( " GPC%d=%s", i, pGPCs0[i] ); + printf( "\n" ); + Vec_Int_t * vLevel; + Vec_Int_t * vRank[2] = { Vec_IntAlloc(100), Vec_IntAlloc(100) }; + Vec_Wec_t ** vGPCs = ABC_ALLOC( Vec_Wec_t *, nGPCs ); + for ( i = 0; i < nGPCs; i++ ) + vGPCs[i] = Vec_WecAlloc(100); + Vec_IntFill( vRank[0], nBits, 0 ); + for ( x = 0; x < nXVars; x++ ) + Vec_IntAddToEntry( vRank[0], x, nYVars ); + printf( "Ranks: " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " : " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " LUT6\n" ); + for ( n = 0; n < nGPCs; n++ ) + for ( i = 0, fFinished = 0; !fFinished; i++ ) + { + printf( "Lev%02d: ", iLevel++ ); + Abc_PrintAT( vRank[0] ); + vLevel = Vec_WecPushLevel( vGPCs[n] ); + Vec_IntFill( vLevel, nBits, 0 ); + Vec_IntFill( vRank[1], nBits, 0 ); + fFinished = 1; + for ( x = 0; x < nBits; x++ ) + if ( (nGpcs = Abc_NtkMatchGpcPattern(vRank[0], x, pGPCs[n])) ) + Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0; + printf( " GPC%d: ", n ); + Abc_PrintAT( vLevel ); + printf( " %4d", Vec_IntSum(vLevel) * nGPCluts[n] ); + printf( "\n" ); + nLuts += Vec_IntSum(vLevel) * nGPCluts[n]; + Vec_IntForEachEntry( vRank[1], Entry, x ) + Vec_IntAddToEntry( vRank[0], x, Entry ); + } + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[0], x) > 2 ) + break; + if ( x < nBits ) + printf( "Synthesis of the adder tree is incomplete. Try using the full adder \"3:11:1\" as the last GPC.\n" ); + else { + printf( "Lev%02d: ", iLevel++ ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", 1 ); + printf( " RCA : " ); + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[0], x) > 1 ) + break; + for ( i = nBits-1; i >= x; i-- ) + printf( "%4d", 1 ); + for ( ; i >= 0; i-- ) + printf( " " ); + printf( " %4d", nBits-x ); + printf( "\n" ); + } + printf( "Statistics: " ); + for ( n = 0; n < nGPCs; n++ ) + printf( "GPC%d = %d. ", n, Vec_WecSum(vGPCs[n]) ); + printf( "RCA = %d. ", nBits-x ); + printf( "Total LUT count = %d. ", nLuts+nBits-x ); + Vec_IntFree( vRank[0] ); + Vec_IntFree( vRank[1] ); + for ( i = 0; i < nGPCs; i++ ) + Vec_WecFree( vGPCs[i] ); + ABC_FREE( vGPCs ); + for ( i = 0; i < nGPCs; i++ ) + ABC_FREE( pGPCs[i] ); + ABC_FREE( pGPCs ); + Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e52c1f4ee..166ede24b 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -341,6 +341,7 @@ static int Abc_CommandClockGate ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandExtWin ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandInsWin ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandSymFun ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandATMap ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandPermute ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandUnpermute ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandCubeEnum ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1149,6 +1150,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Sequential", "extwin", Abc_CommandExtWin, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "inswin", Abc_CommandInsWin, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "symfun", Abc_CommandSymFun, 0 ); + Cmd_CommandAdd( pAbc, "Sequential", "atmap", Abc_CommandATMap, 0 ); Cmd_CommandAdd( pAbc, "Sequential", "permute", Abc_CommandPermute, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "unpermute", Abc_CommandUnpermute, 1 ); Cmd_CommandAdd( pAbc, "Sequential", "cubeenum", Abc_CommandCubeEnum, 0 ); @@ -26067,9 +26069,83 @@ usage: Abc_Print( -2, "\t : the string of N+1 zeros and ones, where N is the number of variables\n" ); Abc_Print( -2, "\t For example, to get 3-input NAND-gate, use \"symfun 1000\".\n" ); Abc_Print( -2, "\t To get 5-input majority gate, use \"symfun 000111\".\n" ); - return 1; } + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPC, int nGPCs, int fVerbose ); + int c, nXVars = -1, nYVars = -1, fVerbose = 0; + char * pGPCs0[1] = { (char*)"3:11:1" }; + char ** pGPCs = NULL; int nGPCs = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "XYvh" ) ) != EOF ) + { + switch ( c ) + { + case 'X': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-X\" should be followed by a file name.\n" ); + goto usage; + } + nXVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'Y': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-Y\" should be followed by a file name.\n" ); + goto usage; + } + nYVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + Abc_Print( -2, "Unknown switch.\n"); + goto usage; + } + } + pGPCs = argv + globalUtilOptind; + nGPCs = argc - globalUtilOptind; + if ( nGPCs == 0 ) + { + printf( "GPCs are not listed on the command line. The simplest GPC (full adder) will be used.\n" ); + pGPCs = pGPCs0; + nGPCs = 1; + } + Abc_NtkATMap( nXVars, nYVars, pGPCs, nGPCs, fVerbose ); + return 0; + +usage: + Abc_Print( -2, "usage: atmap [-XY num] [-G str] [-v] ... \n" ); + Abc_Print( -2, "\t maps rectangular adder tree using GPCs\n" ); + Abc_Print( -2, "\t-X : the number of different ranks [default = %d]\n", nXVars ); + Abc_Print( -2, "\t-Y : the number of bits of each rank [default = %d]\n", nYVars ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n\n"); + Abc_Print( -2, "\t For example, to map an adder tree with dimensions 4 x 648 using GPC(6,6,6,6:1,2,2,2,2,1)\n" ); + Abc_Print( -2, "\t having LUT efficiency E = 1.75, use the command line \"atmap -X 4 -Y 648 6666:122221:8 3:11:1\"\n" ); + Abc_Print( -2, "\t where 8 is the number of 6-LUTs needed to implement the GPC and E = (24-10)/8 = 1.75.\n" ); + return 1; +} + /**Function************************************************************* Synopsis [] From 2b5f102bdb0301120aa0ea20f7c612f84a391ec1 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 29 Mar 2025 15:48:07 -0700 Subject: [PATCH 26/42] Updating input file format in command "permute". --- src/base/abc/abcNtk.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/base/abc/abcNtk.c b/src/base/abc/abcNtk.c index 45a479cf2..c4dbb36ee 100644 --- a/src/base/abc/abcNtk.c +++ b/src/base/abc/abcNtk.c @@ -2059,7 +2059,7 @@ void Abc_NtkRemovePo( Abc_Ntk_t * pNtk, int iOutput, int fRemoveConst0 ) SeeAlso [] ***********************************************************************/ -Vec_Int_t * Abc_NtkReadSignalPerm( char * pFileName, int nSignals ) +Vec_Int_t * Abc_NtkReadSignalPerm2( char * pFileName, int nSignals ) { char Buffer[1000]; FILE * pFile; @@ -2079,7 +2079,7 @@ Vec_Int_t * Abc_NtkReadSignalPerm( char * pFileName, int nSignals ) iFlop = atoi( Buffer ); if ( iFlop < 0 || iFlop >= nSignals ) { - printf( "Signal ID (%d) is out of range.\n", iFlop ); + printf( "The zero-based signal ID (%d) is out of range.\n", iFlop ); fclose( pFile ); Vec_IntFree( vSignals ); return NULL; @@ -2089,12 +2089,45 @@ Vec_Int_t * Abc_NtkReadSignalPerm( char * pFileName, int nSignals ) fclose( pFile ); if ( Vec_IntSize(vSignals) != nSignals ) { - printf( "The number of indexes read in from file (%d) is different from the number of signals in the circuit (%d).\n", iFlop, nSignals ); + printf( "The number of indexes read in from file (%d) is different from the number of signals in the circuit (%d).\n", Vec_IntSize(vSignals), nSignals ); Vec_IntFree( vSignals ); return NULL; } return vSignals; } + +Vec_Int_t * Abc_NtkReadSignalPerm( char * pFileName, int nSignals ) +{ + int Num = -1; + Vec_Int_t * vSignals; + FILE * pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) + { + printf( "Cannot open input file \"%s\".\n", pFileName ); + return NULL; + } + vSignals = Vec_IntAlloc( nSignals ); + while ( fscanf( pFile, "%d", &Num ) == 1 ) + { + if ( Num <= 0 || Num > nSignals ) + { + printf( "The one-based signal ID (%d) is out of range (%d).\n", Num, nSignals ); + fclose( pFile ); + Vec_IntFree( vSignals ); + return NULL; + } + Vec_IntPush( vSignals, Num-1 ); + } + fclose( pFile ); + if ( Vec_IntSize(vSignals) != nSignals ) + { + printf( "The number of indexes read in from file (%d) is different from the number of signals in the circuit (%d).\n", Vec_IntSize(vSignals), nSignals ); + Vec_IntFree( vSignals ); + return NULL; + } + return vSignals; +} + /**Function************************************************************* Synopsis [] From db2b52ca030085e718fbe400214c644d4c3ba859 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 29 Mar 2025 16:54:10 -0700 Subject: [PATCH 27/42] Bug fix. --- src/base/abc/abcUtil.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index 812256a1d..6de7b50e7 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -3378,6 +3378,8 @@ int Abc_NtkMatchGpcPattern( Vec_Int_t * vRanks, int i, char * pGPC ) { int k, Cur, Min = ABC_INFINITY; for ( k = 0; pGPC[k] != ':' && i+k < Vec_IntSize(vRanks); k++ ) { + if ( Abc_TtReadHexDigit(pGPC[k]) == 0 ) + continue; Cur = Vec_IntEntry(vRanks, i+k) / Abc_TtReadHexDigit(pGPC[k]); if ( Min > Cur ) Min = Cur; From 4ac014db41145f6377f3314ecc58d019095f0222 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 30 Mar 2025 09:15:54 -0700 Subject: [PATCH 28/42] Experiments with adder mapping. --- src/base/abc/abcUtil.c | 111 ++++++++++++++++++++++++++++------------- src/base/abci/abc.c | 16 +++--- 2 files changed, 85 insertions(+), 42 deletions(-) diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index 6de7b50e7..e3633da4d 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -3428,81 +3428,120 @@ char ** Abc_NtkTransformGPCs( char ** pGPCs, int nGPCs ) } return pRes; } -void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fVerbose ) +int Abc_NtkCheckGpc( char * pGPC, char * pGPC0 ) +{ + int RetValue = 0, k, Sum[2] = {0}; + char * pOut = strstr(pGPC, ":"); + for ( k = 0; pGPC[k] != ':'; k++ ) + Sum[0] += (1 << k) * Abc_TtReadHexDigit(pGPC[k]); + for ( k = 0; pOut[1+k] != ':'; k++ ) + Sum[1] += (1 << k) * Abc_TtReadHexDigit(pOut[1+k]); + //printf( "GPC %s has input sum %d and output sum %d\n", pGPC0, Sum[0], Sum[1] ); + if ( Sum[0]+1 > (1 << Abc_Base2Log(Sum[1]+1)) ) + printf( "The largest value of GPC inputs (%d) exceeds the capacity of outputs (%d) for GPC %s.\n", Sum[0], Sum[1], pGPC0 ); + else if ( Sum[1]+1 > (1 << Abc_Base2Log(Sum[0]+1)) ) + printf( "The largest value of GPC outputs (%d) exceeds the capacity of inputs (%d) for GPC %s.\n", Sum[1], Sum[0], pGPC0 ); + else + RetValue = 1; + return RetValue; +} +void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fReturn, int fVerbose ) { abctime clkStart = Abc_Clock(); char ** pGPCs = Abc_NtkTransformGPCs(pGPCs0, nGPCs); int i, nGPCluts[100] = {0}; + for ( i = 0; i < nGPCs; i++ ) + if ( !Abc_NtkCheckGpc(pGPCs[i], pGPCs0[i]) ) + return; for ( i = 0; i < nGPCs; i++ ) nGPCluts[i] = Abc_NtkGetGpcLutCount(pGPCs[i]); - int x, n, Entry, iLevel = 0, Sum = 0, nGpcs = 0, nBits, fFinished, nLuts = 0; + int x, n, Entry, iLevel = 0, Sum = 0, nGpcs = 0, nBits, fFinished, nRcaLuts = 0, nLuts = 0; for ( x = 0; x < nXVars; x++ ) Sum += (1 << x) * nYVars; - nBits = Abc_Base2Log( Sum ); + nBits = Abc_Base2Log( Sum+1 ); printf( "Rectangular adder tree (X=%d Y=%d Sum=%d Out=%d) mapped with", nXVars, nYVars, Sum, nBits ); for ( i = 0; i < nGPCs; i++ ) printf( " GPC%d=%s", i, pGPCs0[i] ); printf( "\n" ); Vec_Int_t * vLevel; - Vec_Int_t * vRank[2] = { Vec_IntAlloc(100), Vec_IntAlloc(100) }; + Vec_Int_t * vRank[3] = { Vec_IntAlloc(100), Vec_IntAlloc(100), Vec_IntAlloc(100) }; Vec_Wec_t ** vGPCs = ABC_ALLOC( Vec_Wec_t *, nGPCs ); for ( i = 0; i < nGPCs; i++ ) vGPCs[i] = Vec_WecAlloc(100); Vec_IntFill( vRank[0], nBits, 0 ); for ( x = 0; x < nXVars; x++ ) Vec_IntAddToEntry( vRank[0], x, nYVars ); - printf( "Ranks: " ); - for ( i = nBits-1; i >= 0; i-- ) - printf( "%4d", i ); - printf( " : " ); - for ( i = nBits-1; i >= 0; i-- ) - printf( "%4d", i ); - printf( " LUT6\n" ); + if ( fVerbose ) { + printf( "Ranks: " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " : " ); + for ( i = nBits-1; i >= 0; i-- ) + printf( "%4d", i ); + printf( " LUT6\n" ); + } for ( n = 0; n < nGPCs; n++ ) for ( i = 0, fFinished = 0; !fFinished; i++ ) { - printf( "Lev%02d: ", iLevel++ ); - Abc_PrintAT( vRank[0] ); + int fAdded = 0; vLevel = Vec_WecPushLevel( vGPCs[n] ); Vec_IntFill( vLevel, nBits, 0 ); Vec_IntFill( vRank[1], nBits, 0 ); - fFinished = 1; + Vec_IntClear( vRank[2] ); + Vec_IntAppend( vRank[2], vRank[0] ); + fFinished = 1; for ( x = 0; x < nBits; x++ ) if ( (nGpcs = Abc_NtkMatchGpcPattern(vRank[0], x, pGPCs[n])) ) - Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0; - printf( " GPC%d: ", n ); - Abc_PrintAT( vLevel ); - printf( " %4d", Vec_IntSum(vLevel) * nGPCluts[n] ); - printf( "\n" ); + Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0, fAdded = 1; nLuts += Vec_IntSum(vLevel) * nGPCluts[n]; Vec_IntForEachEntry( vRank[1], Entry, x ) Vec_IntAddToEntry( vRank[0], x, Entry ); + if ( fVerbose && (fAdded || Vec_IntFindMax(vRank[2]) <= 2 ) ) { + printf( "Lev%02d: ", iLevel++ ); + Abc_PrintAT( vRank[2] ); + if ( fAdded ) { + printf( " GPC%d: ", n ); + Abc_PrintAT( vLevel ); + printf( " %4d", Vec_IntSum(vLevel) * nGPCluts[n] ); + } + else if ( Vec_IntFindMax(vRank[2]) == 2 ) { + printf( " RCA : " ); + x = Vec_IntArgMax(vRank[2]); + assert( Vec_IntEntry(vRank[2], x) == 2 ); + for ( i = nBits-1; i >= x; i-- ) + printf( "%4d", 1 ); + for ( ; i >= 0; i-- ) + printf( " " ); + printf( " %4d", (nBits-x+1)/2 ); + } + printf( "\n" ); + } + if ( fAdded ) { + if ( fReturn ) { + fFinished = 1; + n = -1; + } + } + else if ( Vec_IntFindMax(vRank[2]) <= 2 ) { + fFinished = 1; + n = nGPCs; + } } - for ( x = 0; x < nBits; x++ ) - if ( Vec_IntEntry(vRank[0], x) > 2 ) - break; - if ( x < nBits ) + if ( Vec_IntFindMax(vRank[0]) > 2 ) printf( "Synthesis of the adder tree is incomplete. Try using the full adder \"3:11:1\" as the last GPC.\n" ); - else { + else if ( fVerbose && Vec_IntFindMax(vRank[0]) == 2 ) { printf( "Lev%02d: ", iLevel++ ); for ( i = nBits-1; i >= 0; i-- ) printf( "%4d", 1 ); - printf( " RCA : " ); - for ( x = 0; x < nBits; x++ ) - if ( Vec_IntEntry(vRank[0], x) > 1 ) - break; - for ( i = nBits-1; i >= x; i-- ) - printf( "%4d", 1 ); - for ( ; i >= 0; i-- ) - printf( " " ); - printf( " %4d", nBits-x ); printf( "\n" ); } - printf( "Statistics: " ); + printf( "Statistics: " ); for ( n = 0; n < nGPCs; n++ ) printf( "GPC%d = %d. ", n, Vec_WecSum(vGPCs[n]) ); - printf( "RCA = %d. ", nBits-x ); - printf( "Total LUT count = %d. ", nLuts+nBits-x ); + x = Vec_IntArgMax(vRank[0]); + nRcaLuts = Vec_IntFindMax(vRank[0]) == 2 ? (nBits-x+1)/2 : 0; + printf( "RCA = %d. ", nRcaLuts ); + printf( "Total LUT count = %d. ", nLuts+nRcaLuts ); Vec_IntFree( vRank[0] ); Vec_IntFree( vRank[1] ); for ( i = 0; i < nGPCs; i++ ) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 166ede24b..aaa62c8cb 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -26085,12 +26085,12 @@ usage: ***********************************************************************/ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPC, int nGPCs, int fVerbose ); - int c, nXVars = -1, nYVars = -1, fVerbose = 0; + extern void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPC, int nGPCs, int fReturn, int fVerbose ); + int c, nXVars = -1, nYVars = -1, fReturn = 0, fVerbose = 1; char * pGPCs0[1] = { (char*)"3:11:1" }; char ** pGPCs = NULL; int nGPCs = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "XYvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "XYrvh" ) ) != EOF ) { switch ( c ) { @@ -26112,13 +26112,16 @@ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) nYVars = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'r': + fReturn ^= 1; + break; case 'v': fVerbose ^= 1; break; case 'h': goto usage; default: - Abc_Print( -2, "Unknown switch.\n"); + //Abc_Print( -2, "Unknown switch.\n"); goto usage; } } @@ -26130,14 +26133,15 @@ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) pGPCs = pGPCs0; nGPCs = 1; } - Abc_NtkATMap( nXVars, nYVars, pGPCs, nGPCs, fVerbose ); + Abc_NtkATMap( nXVars, nYVars, pGPCs, nGPCs, fReturn, fVerbose ); return 0; usage: - Abc_Print( -2, "usage: atmap [-XY num] [-G str] [-v] ... \n" ); + Abc_Print( -2, "usage: atmap [-XY num] [-G str] [-rv] ... \n" ); Abc_Print( -2, "\t maps rectangular adder tree using GPCs\n" ); Abc_Print( -2, "\t-X : the number of different ranks [default = %d]\n", nXVars ); Abc_Print( -2, "\t-Y : the number of bits of each rank [default = %d]\n", nYVars ); + Abc_Print( -2, "\t-r : return to the first GPC after each step [default = %s]\n", fReturn? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n\n"); Abc_Print( -2, "\t For example, to map an adder tree with dimensions 4 x 648 using GPC(6,6,6,6:1,2,2,2,2,1)\n" ); From 6d6a5accb4a9c140484455a700f10d994ffdd8fb Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 30 Mar 2025 18:20:55 -0700 Subject: [PATCH 29/42] Experiments with LUT cascade mapping. --- src/base/abci/abc.c | 14 ++++--- src/base/abci/abcCas.c | 79 +++++++++++++++++++++++++++------------- src/misc/util/utilBSet.c | 55 +++++++++++++++++++--------- 3 files changed, 100 insertions(+), 48 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index aaa62c8cb..0ec80baeb 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -8927,11 +8927,11 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern Abc_Ntk_t * Abc_NtkLutCascadeGen( int nLutSize, int nStages, int nRails, int nShared, int fVerbose ); extern Abc_Ntk_t * Abc_NtkLutCascade2( Abc_Ntk_t * pNtk, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, char * pGuide ); - extern void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ); + extern void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ); Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pNtkRes; char * pGuide = NULL, * pFileName = NULL; - int c, nVarNum = -1, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 1, fGen = 0, fVerbose = 0; + int c, nVarNum = -1, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 1, fGen = 0, fVerbose = 0, fVeryVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KMRSINFgvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KMRSINFgvwh" ) ) != EOF ) { switch ( c ) { @@ -9016,6 +9016,9 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'v': fVerbose ^= 1; break; + case 'w': + fVeryVerbose ^= 1; + break; case 'h': goto usage; default: @@ -9029,7 +9032,7 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "The number of variables should be given on the command line using switch \"-N \".\n" ); return 1; } - Abc_NtkLutCascadeFile( pFileName, nVarNum, nLutSize, nStages, nRails, nIters, fVerbose ); + Abc_NtkLutCascadeFile( pFileName, nVarNum, nLutSize, nStages, nRails, nIters, fVerbose, fVeryVerbose ); return 1; } if ( fGen ) @@ -9076,7 +9079,7 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutcasdec [-KMRSIN ] [-F ] [-vh]\n" ); + Abc_Print( -2, "usage: lutcasdec [-KMRSIN ] [-F ] [-vwh]\n" ); Abc_Print( -2, "\t decomposes the primary output functions into LUT cascades\n" ); Abc_Print( -2, "\t-K : the number of LUT inputs [default = %d]\n", nLutSize ); Abc_Print( -2, "\t-M : the maximum delay (the number of stages) [default = %d]\n", nStages ); @@ -9087,6 +9090,7 @@ usage: Abc_Print( -2, "\t-F : a text file with truth tables in hexadecimal listed one per line\n"); Abc_Print( -2, "\t-g : toggle generating random cascade with these parameters [default = %s]\n", fGen? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-w : toggle additional verbose printout [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); return 1; } diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 8bddc27f4..471391964 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -310,7 +310,10 @@ word * Abc_LutCascadeTruth( word * pLuts, int nVars ) Vec_WrdFree( vFuncs ); return pRes; } - +int Abc_LutCascadeCount( word * pLuts ) +{ + return (int)pLuts[0]; +} word * Abc_LutCascadeTest( Mini_Aig_t * p, int nLutSize, int fVerbose ) { word * pLuts = Abc_LutCascadeGenTest(); @@ -447,13 +450,14 @@ static inline int Abc_LutCascadeDecStage( char * pGuide, int Iter, Vec_Wrd_t * v assert( Vec_IntSize(vVarIDs) > nLutSize ); assert( Vec_IntSize(vVarIDs) <= 24 ); word Guide = pGuide ? 0 : Abc_TtFindBVarsSVars( Vec_WrdArray(vFuncs[0]), Vec_IntSize(vVarIDs), nRVars, nRails, nLutSize, fVerbose ); + if ( !pGuide && !Guide ) { + if ( fVerbose ) + printf( "The function is not decomposable with %d rails.\n", nRails ); + Vec_IntClear( vVarIDs ); + return -1; + } int m, Myu = pGuide ? 1 << nRails : (Guide >> 48) & 0xFF; int nEVars = Abc_Base2Log(Myu); - if ( nEVars > nRails ) { - printf( "Best Myu (%d) requires %d rails that is more than available (%d).\n", Myu, nEVars, nRails ); - Vec_IntClear( vVarIDs ); - return 0; - } int nVars = Vec_IntSize(vVarIDs); int mBVars = pGuide ? Abc_TtGetGuide(pGuide, Iter, vVarIDs, 0) : Guide & 0xFFFFFF; int nBVars = __builtin_popcount(mBVars); @@ -506,9 +510,12 @@ word * Abc_LutCascadeDec( char * pGuide, word * pTruth, Vec_Int_t * vVarIDs, int Vec_Wrd_t * vFuncs[3] = { Vec_WrdStart(Abc_TtWordNum(nVars)), Vec_WrdAlloc(0), Vec_WrdAlloc(0) }; Abc_TtCopy( Vec_WrdArray(vFuncs[0]), pTruth, Abc_TtWordNum(nVars), 0 ); Vec_Wrd_t * vCas = Vec_WrdAlloc( 100 ); Vec_WrdPush( vCas, nVars ); - for ( i = 0; Vec_IntSize(vVarIDs) > nLutSize; i++ ) + for ( i = 0; Vec_IntSize(vVarIDs) > nLutSize; i++ ) { nRVars = Abc_LutCascadeDecStage( pGuide, i, vFuncs, vVarIDs, nRVars, nRails, nLutSize, fVerbose, vCas ); - if ( Vec_IntSize(vVarIDs) > 0 ) { + if ( nRVars == -1 ) + break; + } + if ( nRVars != -1 && Vec_IntSize(vVarIDs) > 0 ) { Abc_LutCascadeGenOne( vCas, Vec_IntSize(vVarIDs), Vec_IntArray(vVarIDs), Vec_WrdEntry(vCas, 0), Vec_WrdArray(vFuncs[0]) ); Vec_WrdAddToEntry( vCas, 0, -nVars ); pRes = Vec_WrdReleaseArray(vCas); @@ -1137,62 +1144,84 @@ Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarNum ) SeeAlso [] ***********************************************************************/ -void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ) +void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ) { - int nWords = Abc_TtWordNum(nVarNum); - Vec_Wrd_t * vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarNum ); + abctime clkStart = Abc_Clock(); + int i, Sum = 0, nWords = Abc_TtWordNum(nVarNum); + Vec_Wrd_t * vTruths = NULL; + if ( strstr(pFileName, ".txt") ) + vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarNum ); + else + vTruths = Vec_WrdReadBin( pFileName, 0 ); if ( vTruths == NULL ) return; - word * pCopy = ABC_ALLOC( word, nWords ); int nFuncs = Vec_WrdSize(vTruths)/nWords; + if ( Vec_WrdSize(vTruths) != nFuncs * nWords ) { + printf( "The files size (%d bytes) does not match the truth table size (%d) for the given number of functions (%d).\n", 8*Vec_WrdSize(vTruths), 8*nWords, nFuncs ); + Vec_WrdFree( vTruths ); + return; + } + printf( "Considering %d functions having %d variables from file \"%s\".\n", nFuncs, nVarNum, pFileName ); - for ( int i = 0; i < nFuncs; i++ ) + word * pCopy = ABC_ALLOC( word, nWords ); + int LutStats[100] = {0}; + for ( i = 0; i < nFuncs; i++ ) { word * pTruth = Vec_WrdEntryP( vTruths, i*nWords ); Abc_TtCopy( pCopy, pTruth, nWords, 0 ); - if ( fVerbose ) + if ( fVeryVerbose ) printf( "\n" ); - printf( "Function %3d : ", i ); - if ( fVerbose ) + if ( fVerbose || fVeryVerbose ) + printf( "Function %3d : ", i ); + if ( fVeryVerbose ) Abc_TtPrintHexRev( stdout, pTruth, nVarNum ), printf( "\n" ); //continue; int nVars = nVarNum; Vec_Int_t * vVarIDs = Vec_IntStartNatural( nVars ); Abc_TtMinimumBase( pTruth, Vec_IntArray(vVarIDs), nVars, &nVars ); - if ( fVerbose ) { + if ( fVeryVerbose ) { if ( Vec_IntSize(vVarIDs) != nVars ) printf( "The support of the function is reduced from %d to %d variables.\n", Vec_IntSize(vVarIDs), nVars ); printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs.\n", nVars, nRails, nLutSize ); } Vec_IntShrink( vVarIDs, nVars ); - word * pLuts = Abc_LutCascadeDec( NULL, pTruth, vVarIDs, nRails, nLutSize, fVerbose ); + word * pLuts = Abc_LutCascadeDec( NULL, pTruth, vVarIDs, nRails, nLutSize, fVeryVerbose ); Vec_IntFree( vVarIDs ); if ( pLuts == NULL ) { - printf( "Not decomposable.\n" ); + if ( fVerbose || fVeryVerbose ) + printf( "Not decomposable.\n" ); continue; } + Sum++; + LutStats[Abc_LutCascadeCount(pLuts)]++; int nWords2 = Abc_TtWordNum(nVars); word * pTruth2 = Abc_LutCascadeTruth( pLuts, nVars ); - if ( fVerbose ) + if ( fVeryVerbose ) Abc_LutCascadePrint( pLuts ); - else + if ( fVerbose || fVeryVerbose ) printf( "Decomposition exists. " ); if ( !Abc_TtEqual(pTruth, pTruth2, nWords2) ) { - printf( "Verification FAILED.\n" ); - Abc_TtPrintHexRev( stdout, pCopy, nVarNum ), printf( "\n" ); + printf( "Verification FAILED for function %d.\n", i ); + Abc_TtPrintHexRev( stdout, pTruth, nVarNum ), printf( "\n" ); } - else + else if ( fVerbose || fVeryVerbose ) printf( "Verification passed.\n" ); ABC_FREE( pTruth2 ); ABC_FREE( pLuts ); } ABC_FREE( pCopy ); Vec_WrdFree( vTruths ); - printf( "Finished decomposing functions from file \"%s\".\n", pFileName ); + printf( "Statistics for %d-rail LUT cascade:\n", nRails ); + for ( i = 0; i < 100; i++ ) + if ( LutStats[i] ) + printf( " %d LUT6 : Function count = %8d (%6.2f %%)\n", i, LutStats[i], 100.0*LutStats[i]/nFuncs ); + printf( "Non-decomp : Function count = %8d (%6.2f %%)\n", nFuncs-Sum, 100.0*(nFuncs-Sum)/Abc_MaxInt(1, nFuncs) ); + printf( "Finished %d functions (speed = %.2f functions / second). ", nFuncs, 1.0*nFuncs/(((double)(Abc_Clock() - clkStart))/((double)CLOCKS_PER_SEC)) ); + Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); } //////////////////////////////////////////////////////////////////////// diff --git a/src/misc/util/utilBSet.c b/src/misc/util/utilBSet.c index 8cee38e1b..e6d8a6673 100644 --- a/src/misc/util/utilBSet.c +++ b/src/misc/util/utilBSet.c @@ -589,7 +589,7 @@ int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int n { int i, k, Var0, Var1, Pla2Var[32], Var2Pla[32]; int nPermVars = nVars-nCVars; - assert( p->nVars == nPermVars && p->nBVars == nPermVars-nFVars ); + assert( p->nVars == nPermVars && p->nBVars == nVars-nFVars ); for ( i = 0; i < nVars; i++ ) Pla2Var[i] = Var2Pla[i] = i; if ( pPermBest ) @@ -617,8 +617,20 @@ int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int n for ( k = nFVars-1; k >= 0; k-- ) printf( " %d", Pla2Var[k] ); printf( " : Myu = %3d", CostThis ); - printf( "\n" ); + //printf( "\n" ); } + if ( 0 ) { + word pPat[1024]; + int nRails = 1, Shared = 0; + if ( CostThis > (1 << nRails) ) { + extern int Abc_SharedEvalBest( Abc_BSEval_t * p, word * pTruth, int nVars, int nCVars, int nFVars, int MyuMin, int nRails, int fVerbose, int * pSetShared, word * pPat ); + int nRailsMin = Abc_SharedEvalBest( p, pIn, nVars, nCVars, nFVars, CostThis, nRails, 0, &Shared, pPat ); + printf( " RailMin = %d. Shared = %2d. ", nRailsMin, Shared ); + } + } + if ( fVerbose ) + printf( "\n" ); + int iPlace0 = Var2Pla[Var0]; int iPlace1 = Var2Pla[Var1]; if ( iPlace0 == iPlace1 ) @@ -859,17 +871,19 @@ int Abc_BSEvalFindShared( int nVars, word * pISets, int nISets, int nBSWords, Ve ***********************************************************************/ int Abc_SharedEvalBest( Abc_BSEval_t * p, word * pTruth, int nVars, int nCVars, int nFVars, int MyuMin, int nRails, int fVerbose, int * pSetShared, word * pPat ) { - int nBSWords = Abc_Truth6WordNum( nVars - nFVars ), CVarMask = Abc_InfoMask(nCVars) << (nVars - nFVars - nCVars); + int nBSWords = Abc_Truth6WordNum( nVars - nFVars ), CVarMask = nCVars ? Abc_InfoMask(nCVars) << (nVars - nCVars - nFVars) : 0; int MyuCur, Myu = Abc_TtGetCMInt( pTruth, nVars, nFVars, p->vCounts, p->vTable, p->vStore, p->vUsed, pPat ); int nRailsCur = Abc_Base2Log( Myu ); Vec_Int_t * vLevel; assert( Myu == MyuMin && nRailsCur > nRails ); - int i, k, iSet, iStart, nSharedMax = nVars - nFVars - 1, nRailsMin = 100; - Vec_WecForEachLevelStartStop( p->vSets, vLevel, i, 1, nSharedMax+1 ) { + int i, k, iSet, iStart, nSharedMax = nVars - nCVars - nFVars - 1, nRailsMin = 100; + Vec_WecForEachLevelStartStop( p->vSets, vLevel, i, 1, nSharedMax ) { Vec_IntForEachEntryDouble( vLevel, iSet, iStart, k ) { if ( iSet & CVarMask ) continue; + //printf( "\nTrying set " ); Extra_PrintBinary( stdout, &iSet, nVars-nFVars ); printf( "\n" ); MyuCur = Abc_BSEvalCountUniqueMax( pPat, Myu, nBSWords, Vec_WrdEntryP(p->vCofs, iStart), i, 1 << nRails ); - if ( MyuCur == 0 ) + //printf( " Res = %d", MyuCur ); + if ( MyuCur == 0 || MyuCur > (1 << nRails) ) continue; nRailsCur = Abc_Base2Log(MyuCur); if ( nRailsCur > nRails ) @@ -972,23 +986,24 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int { Abc_BSEval_t * p = Abc_BSEvalAlloc(); int nPermVars = nVars-nRVars; - if ( p->nVars != nPermVars || p->nBVars != nLutSize ) { - if ( p->nBVars != nLutSize ) { - Vec_WecFreeP( &p->vSets ); - Vec_WrdFreeP( &p->vCofs ); - p->vCofs = Abc_BSEvalCreateCofactorSets( nLutSize, &p->vSets ); - } + if ( p->nVars != nPermVars ) { Vec_IntFreeP( &p->vPairs ); - p->vPairs = Abc_GenChasePairs( nPermVars, nLutSize ); - p->nVars = nPermVars; - p->nBVars = nLutSize; + p->vPairs = Abc_GenChasePairs( nPermVars, nLutSize-nRVars ); + p->nVars = nPermVars; } + if ( p->nBVars != nLutSize ) { + Vec_WecFreeP( &p->vSets ); + Vec_WrdFreeP( &p->vCofs ); + p->vCofs = Abc_BSEvalCreateCofactorSets( nLutSize, &p->vSets ); + p->nBVars = nLutSize; + } int v, nWords = Abc_TtWordNum(nVars); word * pCopy = ABC_ALLOC( word, nWords ); Abc_TtCopy( pCopy, pTruth, nWords, 0 ); word pPat[1024]; + //Abc_TtPrintHexRev( stdout, pTruth, nVars ); printf( "\n" ); int pPermBest[32] = {0}; word * pBest = ABC_ALLOC( word, nWords ); @@ -1009,9 +1024,16 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int MyuMin = 1 << nRailsMin; } + ABC_FREE( pCopy ); + ABC_FREE( pBest ); + Abc_BSEvalFree(p); + if ( fVerbose ) printf( "Myu min = %d. Rail min = %d. Shared = %x.\n", MyuMin, nRailsMin, Shared ); + if ( nRailsMin > nRails ) + return 0; + word mBVars = 0; for ( v = 0; v < nLutSize; v++ ) mBVars |= (word)1 << pPermBest[nVars-nLutSize+v]; @@ -1021,9 +1043,6 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int if ( (Shared >> v) & 1 ) mSVars |= (word)1 << (nVars-nLutSize+v); - ABC_FREE( pCopy ); - ABC_FREE( pBest ); - Abc_BSEvalFree(p); return ((word)MyuMin << 48) | (mSVars << 24) | mBVars; } From 4656ae10e08a086d111e6982f057d18babad1150 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 30 Mar 2025 19:55:07 -0700 Subject: [PATCH 30/42] Updates to the GPC-based mapping. --- src/base/abc/abcUtil.c | 47 +++++++++++++++++++++++------------------- src/base/abci/abc.c | 26 +++++++++++++++++------ 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index e3633da4d..fddc04beb 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -3445,7 +3445,7 @@ int Abc_NtkCheckGpc( char * pGPC, char * pGPC0 ) RetValue = 1; return RetValue; } -void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fReturn, int fVerbose ) +void Abc_NtkATMap( int nXVars, int nYVars, int nAdder, char ** pGPCs0, int nGPCs, int fReturn, int fVerbose ) { abctime clkStart = Abc_Clock(); char ** pGPCs = Abc_NtkTransformGPCs(pGPCs0, nGPCs); @@ -3490,13 +3490,15 @@ void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fRetur Vec_IntClear( vRank[2] ); Vec_IntAppend( vRank[2], vRank[0] ); fFinished = 1; - for ( x = 0; x < nBits; x++ ) - if ( (nGpcs = Abc_NtkMatchGpcPattern(vRank[0], x, pGPCs[n])) ) - Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0, fAdded = 1; - nLuts += Vec_IntSum(vLevel) * nGPCluts[n]; - Vec_IntForEachEntry( vRank[1], Entry, x ) - Vec_IntAddToEntry( vRank[0], x, Entry ); - if ( fVerbose && (fAdded || Vec_IntFindMax(vRank[2]) <= 2 ) ) { + if ( Vec_IntFindMax(vRank[0]) > nAdder ) { + for ( x = 0; x < nBits; x++ ) + if ( (nGpcs = Abc_NtkMatchGpcPattern(vRank[0], x, pGPCs[n])) ) + Abc_NtkUpdateGpcPattern(vRank[0], x, pGPCs[n], nGpcs, vRank[1], vLevel), fFinished = 0, fAdded = 1; + nLuts += Vec_IntSum(vLevel) * nGPCluts[n]; + Vec_IntForEachEntry( vRank[1], Entry, x ) + Vec_IntAddToEntry( vRank[0], x, Entry ); + } + if ( fVerbose && (fAdded || Vec_IntFindMax(vRank[2]) <= nAdder ) ) { printf( "Lev%02d: ", iLevel++ ); Abc_PrintAT( vRank[2] ); if ( fAdded ) { @@ -3504,15 +3506,16 @@ void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fRetur Abc_PrintAT( vLevel ); printf( " %4d", Vec_IntSum(vLevel) * nGPCluts[n] ); } - else if ( Vec_IntFindMax(vRank[2]) == 2 ) { - printf( " RCA : " ); - x = Vec_IntArgMax(vRank[2]); - assert( Vec_IntEntry(vRank[2], x) == 2 ); + else if ( Vec_IntFindMax(vRank[2]) <= nAdder ) { + printf( " ADD%d: ", nAdder ); + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[2], x) > 1 ) + break; for ( i = nBits-1; i >= x; i-- ) printf( "%4d", 1 ); for ( ; i >= 0; i-- ) printf( " " ); - printf( " %4d", (nBits-x+1)/2 ); + printf( " %4d", (nBits-x)*(nAdder == 4 ? 2 : 1) ); } printf( "\n" ); } @@ -3522,14 +3525,14 @@ void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fRetur n = -1; } } - else if ( Vec_IntFindMax(vRank[2]) <= 2 ) { + else if ( Vec_IntFindMax(vRank[2]) <= nAdder ) { fFinished = 1; n = nGPCs; } } - if ( Vec_IntFindMax(vRank[0]) > 2 ) + if ( Vec_IntFindMax(vRank[0]) > nAdder ) printf( "Synthesis of the adder tree is incomplete. Try using the full adder \"3:11:1\" as the last GPC.\n" ); - else if ( fVerbose && Vec_IntFindMax(vRank[0]) == 2 ) { + else if ( fVerbose && Vec_IntFindMax(vRank[0]) <= nAdder ) { printf( "Lev%02d: ", iLevel++ ); for ( i = nBits-1; i >= 0; i-- ) printf( "%4d", 1 ); @@ -3538,12 +3541,14 @@ void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPCs0, int nGPCs, int fRetur printf( "Statistics: " ); for ( n = 0; n < nGPCs; n++ ) printf( "GPC%d = %d. ", n, Vec_WecSum(vGPCs[n]) ); - x = Vec_IntArgMax(vRank[0]); - nRcaLuts = Vec_IntFindMax(vRank[0]) == 2 ? (nBits-x+1)/2 : 0; - printf( "RCA = %d. ", nRcaLuts ); + for ( x = 0; x < nBits; x++ ) + if ( Vec_IntEntry(vRank[0], x) > 1 ) + break; + nRcaLuts = (nBits-x)*(nAdder == 4 ? 2 : 1); + printf( "ADD%d = %d. ", nAdder, nRcaLuts ); printf( "Total LUT count = %d. ", nLuts+nRcaLuts ); - Vec_IntFree( vRank[0] ); - Vec_IntFree( vRank[1] ); + for ( i = 0; i < 3; i++ ) + Vec_IntFree( vRank[i] ); for ( i = 0; i < nGPCs; i++ ) Vec_WecFree( vGPCs[i] ); ABC_FREE( vGPCs ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0ec80baeb..2a00d2297 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -26089,12 +26089,12 @@ usage: ***********************************************************************/ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern void Abc_NtkATMap( int nXVars, int nYVars, char ** pGPC, int nGPCs, int fReturn, int fVerbose ); - int c, nXVars = -1, nYVars = -1, fReturn = 0, fVerbose = 1; + extern void Abc_NtkATMap( int nXVars, int nYVars, int nAdder, char ** pGPC, int nGPCs, int fReturn, int fVerbose ); + int c, nXVars = -1, nYVars = -1, nAdder = 2, fReturn = 0, fVerbose = 1; char * pGPCs0[1] = { (char*)"3:11:1" }; char ** pGPCs = NULL; int nGPCs = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "XYrvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "XYArvh" ) ) != EOF ) { switch ( c ) { @@ -26116,6 +26116,15 @@ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) nYVars = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'A': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-A\" should be followed by a file name.\n" ); + goto usage; + } + nAdder = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'r': fReturn ^= 1; break; @@ -26125,10 +26134,14 @@ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'h': goto usage; default: - //Abc_Print( -2, "Unknown switch.\n"); goto usage; } } + if ( nAdder < 2 || nAdder > 4 ) + { + printf( "The terminal adder should have 2, 3, or 4 bits.\n" ); + return 0; + } pGPCs = argv + globalUtilOptind; nGPCs = argc - globalUtilOptind; if ( nGPCs == 0 ) @@ -26137,14 +26150,15 @@ int Abc_CommandATMap( Abc_Frame_t * pAbc, int argc, char ** argv ) pGPCs = pGPCs0; nGPCs = 1; } - Abc_NtkATMap( nXVars, nYVars, pGPCs, nGPCs, fReturn, fVerbose ); + Abc_NtkATMap( nXVars, nYVars, nAdder, pGPCs, nGPCs, fReturn, fVerbose ); return 0; usage: - Abc_Print( -2, "usage: atmap [-XY num] [-G str] [-rv] ... \n" ); + Abc_Print( -2, "usage: atmap [-XYA num] [-G str] [-rv] ... \n" ); Abc_Print( -2, "\t maps rectangular adder tree using GPCs\n" ); Abc_Print( -2, "\t-X : the number of different ranks [default = %d]\n", nXVars ); Abc_Print( -2, "\t-Y : the number of bits of each rank [default = %d]\n", nYVars ); + Abc_Print( -2, "\t-A : the number of arguments in the terminal adder [default = %d]\n", nAdder ); Abc_Print( -2, "\t-r : return to the first GPC after each step [default = %s]\n", fReturn? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n\n"); From dc72d1e120f141177b2ac86a4a49190dbe8f10d7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 31 Mar 2025 15:24:15 -0700 Subject: [PATCH 31/42] New command &store. --- src/base/abci/abc.c | 59 +++++++++++++++++++++++++++++++++++++++ src/base/main/mainFrame.c | 1 + src/base/main/mainInt.h | 7 ++++- src/base/main/mainUtils.c | 56 +++++++++++++++++++++++++++++++++++++ src/misc/vec/vecHsh.h | 6 +++- 5 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 2a00d2297..433f3cac0 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -552,6 +552,7 @@ static int Abc_CommandAbc9Mesh ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9Iso ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9IsoNpn ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9IsoSt ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Store ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Compare ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9RevEng ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Uif ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1364,6 +1365,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&iso", Abc_CommandAbc9Iso, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&isonpn", Abc_CommandAbc9IsoNpn, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&isost", Abc_CommandAbc9IsoSt, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&store", Abc_CommandAbc9Store, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&compare", Abc_CommandAbc9Compare, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&reveng", Abc_CommandAbc9RevEng, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&uif", Abc_CommandAbc9Uif, 0 ); @@ -48191,6 +48193,63 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Store( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + int c, fClean = 0, fPrint = 0, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "cpvh" ) ) != EOF ) + { + switch ( c ) + { + case 'c': + fClean ^= 1; + break; + case 'p': + fPrint ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Store(): There is no AIG.\n" ); + return 1; + } + if ( fClean ) + Abc_FrameStoreStop( pAbc ); + else if ( fPrint ) + Abc_FrameStorePrint( pAbc ); + else + Abc_FrameStoreAdd( pAbc, pAbc->pGia ); + return 0; + +usage: + Abc_Print( -2, "usage: &store [-cpvh]\n" ); + Abc_Print( -2, "\t maintains the store of unique AIG structures\n" ); + Abc_Print( -2, "\t-c : toggle cleaning the store [default = %s]\n", fClean? "yes": "no" ); + Abc_Print( -2, "\t-p : toggle printing the store statistics [default = %s]\n", fPrint? "yes": "no" ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/base/main/mainFrame.c b/src/base/main/mainFrame.c index ba41d4c1c..77faabb0d 100644 --- a/src/base/main/mainFrame.c +++ b/src/base/main/mainFrame.c @@ -248,6 +248,7 @@ void Abc_FrameDeallocate( Abc_Frame_t * p ) Vec_WecFreeP( &s_GlobalFrame->vJsonObjs ); Ndr_Delete( s_GlobalFrame->pNdr ); ABC_FREE( s_GlobalFrame->pNdrArray ); + Abc_FrameStoreStop( s_GlobalFrame ); Gia_ManStopP( &p->pGiaMiniAig ); Gia_ManStopP( &p->pGiaMiniLut ); diff --git a/src/base/main/mainInt.h b/src/base/main/mainInt.h index 2d099577a..dd86642cb 100644 --- a/src/base/main/mainInt.h +++ b/src/base/main/mainInt.h @@ -33,6 +33,7 @@ #include "aig/gia/gia.h" #include "proof/ssw/ssw.h" #include "proof/fra/fra.h" +#include "misc/vec/vecHsh.h" #ifdef ABC_USE_CUDD #include "bdd/extrab/extraBdd.h" @@ -151,6 +152,7 @@ struct Abc_Frame_t_ void * pAbcPla; Abc_Nam_t * pJsonStrs; Vec_Wec_t * vJsonObjs; + Hsh_VecMan_t * pHash; #ifdef ABC_USE_CUDD DdManager * dd; // temporary BDD package #endif @@ -210,7 +212,10 @@ extern ABC_DLL char * Abc_UtilsGetUsersInput( Abc_Frame_t * pAbc ); extern ABC_DLL void Abc_UtilsPrintHello( Abc_Frame_t * pAbc ); extern ABC_DLL void Abc_UtilsPrintUsage( Abc_Frame_t * pAbc, char * ProgName ); extern ABC_DLL void Abc_UtilsSource( Abc_Frame_t * pAbc ); - +extern ABC_DLL void Abc_FrameStoreStart( Abc_Frame_t * pAbc ); +extern ABC_DLL void Abc_FrameStoreStop( Abc_Frame_t * pAbc ); +extern ABC_DLL void Abc_FrameStoreAdd( Abc_Frame_t * pAbc, Gia_Man_t * p ); +extern ABC_DLL void Abc_FrameStorePrint( Abc_Frame_t * pAbc ); ABC_NAMESPACE_HEADER_END diff --git a/src/base/main/mainUtils.c b/src/base/main/mainUtils.c index 245e936af..22d0e8774 100644 --- a/src/base/main/mainUtils.c +++ b/src/base/main/mainUtils.c @@ -291,7 +291,63 @@ char * DateReadFromDateString( char * datestr ) } } +/**Function******************************************************************** + Synopsis [] + + Description [] + + SideEffects [] + +******************************************************************************/ +void Abc_FrameStoreStop( Abc_Frame_t * pAbc ) +{ + if ( pAbc->pHash ) + Hsh_VecManStop( pAbc->pHash ); + pAbc->pHash = NULL; +} +void Abc_FrameStoreStart( Abc_Frame_t * pAbc ) +{ + Abc_FrameStoreStop( pAbc ); + pAbc->pHash = Hsh_VecManStart( 1000 ); + pAbc->pHash->vEntry = Vec_IntAlloc( 1000 ); + pAbc->pHash->vValue = Vec_IntAlloc( 1000 ); +} +void Abc_FrameStoreAdd( Abc_Frame_t * pAbc, Gia_Man_t * pGia ) +{ + if ( pAbc->pHash == NULL ) + Abc_FrameStoreStart( pAbc ); + Gia_Man_t * p = Gia_ManIsoCanonicize( pGia, 0 ); + Vec_IntClear( pAbc->pHash->vEntry ); + Vec_IntPush( pAbc->pHash->vEntry, 0 ); + Vec_IntPush( pAbc->pHash->vEntry, Gia_ManPiNum(p) ); + Vec_IntPush( pAbc->pHash->vEntry, Gia_ManPoNum(p) ); + Vec_IntPush( pAbc->pHash->vEntry, Gia_ManRegNum(p) ); + Gia_Obj_t * pObj; int i; + Gia_ManForEachAnd( p, pObj, i ) + Vec_IntPushTwo( pAbc->pHash->vEntry, Gia_ObjFaninLit0(pObj, i), Gia_ObjFaninLit1(pObj, i) ); + int iEntry = Hsh_VecManAdd( pAbc->pHash, pAbc->pHash->vEntry ); + if ( Vec_IntSize(pAbc->pHash->vValue) == iEntry ) + Vec_IntPush( pAbc->pHash->vValue, 0 ); + Vec_IntAddToEntry( pAbc->pHash->vValue, iEntry, 1 ); + assert( Vec_IntSize(pAbc->pHash->vValue) == Hsh_VecSize(pAbc->pHash) ); + Gia_ManStop( p ); +} +void Abc_FrameStorePrint( Abc_Frame_t * pAbc ) +{ + if ( pAbc->pHash == NULL ) + Abc_FrameStoreStart( pAbc ); + int i, Entry, Max = Vec_IntFindMax( pAbc->pHash->vValue ); + Vec_Int_t * vCounts = Vec_IntStart( Max+1 ); + Vec_IntForEachEntry( pAbc->pHash->vValue, Entry, i ) + Vec_IntAddToEntry( vCounts, Entry, 1 ); + printf( "Distribution of %d stored items by reference count (=): ", Hsh_VecSize(pAbc->pHash) ); + Vec_IntForEachEntry( vCounts, Entry, i ) + if ( Entry ) + printf( "%d=%d ", i, Entry ); + printf( "\n" ); + Vec_IntFree( vCounts ); +} //////////////////////////////////////////////////////////////////////// /// END OF FILE /// diff --git a/src/misc/vec/vecHsh.h b/src/misc/vec/vecHsh.h index b87904a28..bb3c87f27 100644 --- a/src/misc/vec/vecHsh.h +++ b/src/misc/vec/vecHsh.h @@ -87,7 +87,9 @@ struct Hsh_VecMan_t_ { Vec_Int_t * vTable; // hash table Vec_Int_t * vData; // data storage - Vec_Int_t * vMap; // mapping entries into data; + Vec_Int_t * vMap; // mapping entries into data + Vec_Int_t * vValue; // mapping entries into values + Vec_Int_t * vEntry; // temporary entry Vec_Int_t vTemp; // temporary array Vec_Int_t vTemp1; // temporary array Vec_Int_t vTemp2; // temporary array @@ -461,6 +463,8 @@ static inline void Hsh_VecManStop( Hsh_VecMan_t * p ) Vec_IntFree( p->vTable ); Vec_IntFree( p->vData ); Vec_IntFree( p->vMap ); + Vec_IntFreeP( &p->vValue ); + Vec_IntFreeP( &p->vEntry ); ABC_FREE( p ); } static inline int * Hsh_VecReadArray( Hsh_VecMan_t * p, int i ) From 9cdbb79338590477f654c788551bc373bac31a77 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 31 Mar 2025 15:39:05 -0700 Subject: [PATCH 32/42] Bug fix in handling concurrency in "stochmap". --- src/base/abci/abcPart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/abci/abcPart.c b/src/base/abci/abcPart.c index 8f943f379..9411a0bba 100644 --- a/src/base/abci/abcPart.c +++ b/src/base/abci/abcPart.c @@ -1341,7 +1341,7 @@ Vec_Ptr_t * Abc_NtkStochProcess( Vec_Ptr_t * vWins, char * pScript, int nProcs, StochSynData_t * pData = ABC_CALLOC( StochSynData_t, Vec_PtrSize(vWins) ); Vec_Ptr_t * vData = Vec_PtrAlloc( Vec_PtrSize(vWins) ); Abc_Ntk_t * pNtk; int i; - Abc_Random(1); + //Abc_Random(1); Vec_PtrForEachEntry( Abc_Ntk_t *, vWins, pNtk, i ) { pData[i].pIn = pNtk; pData[i].pOut = NULL; From 80becaf2e290fe9d975daad6d3c249169ca77072 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 31 Mar 2025 18:33:38 -0700 Subject: [PATCH 33/42] Bug fix in LUT cascade decomposition. --- src/base/abci/abcCas.c | 83 +++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 471391964..612de7e64 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -504,12 +504,12 @@ static inline int Abc_LutCascadeDecStage( char * pGuide, int Iter, Vec_Wrd_t * v Vec_IntShrink( vVarIDs, nFVars+nSVars+nEVars ); return nEVars; } -word * Abc_LutCascadeDec( char * pGuide, word * pTruth, Vec_Int_t * vVarIDs, int nRails, int nLutSize, int fVerbose ) +word * Abc_LutCascadeDec( char * pGuide, word * pTruth, int nVarsOrig, Vec_Int_t * vVarIDs, int nRails, int nLutSize, int fVerbose ) { word * pRes = NULL; int i, nRVars = 0, nVars = Vec_IntSize(vVarIDs); Vec_Wrd_t * vFuncs[3] = { Vec_WrdStart(Abc_TtWordNum(nVars)), Vec_WrdAlloc(0), Vec_WrdAlloc(0) }; Abc_TtCopy( Vec_WrdArray(vFuncs[0]), pTruth, Abc_TtWordNum(nVars), 0 ); - Vec_Wrd_t * vCas = Vec_WrdAlloc( 100 ); Vec_WrdPush( vCas, nVars ); + Vec_Wrd_t * vCas = Vec_WrdAlloc( 100 ); Vec_WrdPush( vCas, nVarsOrig ); for ( i = 0; Vec_IntSize(vVarIDs) > nLutSize; i++ ) { nRVars = Abc_LutCascadeDecStage( pGuide, i, vFuncs, vVarIDs, nRVars, nRails, nLutSize, fVerbose, vCas ); if ( nRVars == -1 ) @@ -517,7 +517,7 @@ word * Abc_LutCascadeDec( char * pGuide, word * pTruth, Vec_Int_t * vVarIDs, int } if ( nRVars != -1 && Vec_IntSize(vVarIDs) > 0 ) { Abc_LutCascadeGenOne( vCas, Vec_IntSize(vVarIDs), Vec_IntArray(vVarIDs), Vec_WrdEntry(vCas, 0), Vec_WrdArray(vFuncs[0]) ); - Vec_WrdAddToEntry( vCas, 0, -nVars ); + Vec_WrdAddToEntry( vCas, 0, -nVarsOrig ); pRes = Vec_WrdReleaseArray(vCas); } Vec_WrdFree( vCas ); @@ -623,36 +623,43 @@ Abc_Ntk_t * Abc_NtkLutCascade2( Abc_Ntk_t * pNtk, int nLutSize, int nLuts, int n extern word * Abc_LutCascade2( word * p, int nVars, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ); Gia_Man_t * pGia = Abc_NtkStrashToGia( pNtk ); word * pTruth1 = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, 0) ); + int nWords = Abc_TtWordNum(Abc_NtkCiNum(pNtk)); + word * pCopy = ABC_ALLOC( word, nWords ); + Abc_TtCopy( pCopy, pTruth1, nWords, 0 ); - int nVars = Abc_NtkCiNum(pNtk); - Vec_Int_t * vVarIDs = Vec_IntStartNatural( nVars ); - Abc_TtMinimumBase( pTruth1, Vec_IntArray(vVarIDs), nVars, &nVars ); + int nVars = -1; + Vec_Int_t * vVarIDs = Vec_IntStartNatural( Abc_NtkCiNum(pNtk) ); + Abc_TtMinimumBase( pTruth1, Vec_IntArray(vVarIDs), Abc_NtkCiNum(pNtk), &nVars ); + Vec_IntShrink( vVarIDs, nVars ); if ( fVerbose ) { - if ( Vec_IntSize(vVarIDs) != nVars ) - printf( "The support of the function is reduced from %d to %d variables.\n", Vec_IntSize(vVarIDs), nVars ); + if ( Abc_NtkCiNum(pNtk) != nVars ) + printf( "The support of the function is reduced from %d to %d variables.\n", Abc_NtkCiNum(pNtk), nVars ); printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs", nVars, nRails, nLutSize ); if ( pGuide ) printf( " using structural info: %s", pGuide ); printf( ".\n" ); } - Vec_IntShrink( vVarIDs, nVars ); - //word * pLuts = Abc_LutCascade2( pTruth1, nVars, nLutSize, nLuts, nRails, nIters, fVerbose ); - word * pLuts = Abc_LutCascadeDec( pGuide, pTruth1, vVarIDs, nRails, nLutSize, fVerbose ); - Abc_Ntk_t * pNew = pLuts ? Abc_NtkLutCascadeFromLuts( pLuts, nVars, pNtk, nLutSize, fVerbose ) : NULL; + word * pLuts = Abc_LutCascadeDec( pGuide, pTruth1, Abc_NtkCiNum(pNtk), vVarIDs, nRails, nLutSize, fVerbose ); + Abc_Ntk_t * pNew = pLuts ? Abc_NtkLutCascadeFromLuts( pLuts, Abc_NtkCiNum(pNtk), pNtk, nLutSize, fVerbose ) : NULL; Vec_IntFree( vVarIDs ); - if ( pLuts && fVerbose ) { + if ( pLuts ) { + if ( fVerbose ) + Abc_LutCascadePrint( pLuts ); word * pTruth2 = Abc_LutCascadeTruth( pLuts, Abc_NtkCiNum(pNtk) ); - if ( nVars < 9 ) { - printf("Function before: "); Abc_TtPrintHexRev( stdout, pTruth1, nVars ); printf( "\n" ); - printf("Function after: "); Abc_TtPrintHexRev( stdout, pTruth2, nVars ); printf( "\n" ); + if ( !Abc_TtEqual(pCopy, pTruth2, nWords) ) { + printf( "Verification FAILED.\n" ); + printf("Function before: "); Abc_TtPrintHexRev( stdout, pCopy, Abc_NtkCiNum(pNtk) ); printf( "\n" ); + printf("Function after: "); Abc_TtPrintHexRev( stdout, pTruth2, Abc_NtkCiNum(pNtk) ); printf( "\n" ); } - Abc_LutCascadePrint( pLuts ); + else if ( fVerbose ) + printf( "Verification passed.\n" ); ABC_FREE( pLuts ); ABC_FREE( pTruth2 ); } Gia_ManStop( pGia ); + ABC_FREE( pCopy ); //ABC_FREE( pTruth1 ); return pNew; } @@ -1097,10 +1104,10 @@ Abc_Ntk_t * Abc_NtkLutCascadeMap( Abc_Ntk_t * pNtk, int nLutsMax, int nIters, in SeeAlso [] ***********************************************************************/ -Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarNum ) +Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarsOrig ) { Vec_Wrd_t * vTruths = NULL; - int nWords = Abc_TtWordNum(nVarNum); + int nWords = Abc_TtWordNum(nVarsOrig); int nFileSize = Gia_FileSize( pFileName ); FILE * pFile = fopen( pFileName, "rb" ); if ( pFile == NULL ) { printf("Cannot open file \"%s\" for reading.\n", pFileName); return NULL; } @@ -1112,8 +1119,8 @@ Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarNum ) continue; if ( pToken[0] == '0' && pToken[1] == 'x' ) pToken += 2; - if ( strlen(pToken) != (1 << (nVarNum-2)) ) { - printf( "Line %d has truth table of size %d while expected size is %d.\n", i, (int)strlen(pToken), 1 << (nVarNum-2) ); + if ( strlen(pToken) != (1 << (nVarsOrig-2)) ) { + printf( "Line %d has truth table of size %d while expected size is %d.\n", i, (int)strlen(pToken), 1 << (nVarsOrig-2) ); Vec_WrdFreeP( &vTruths ); break; } @@ -1144,13 +1151,13 @@ Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarNum ) SeeAlso [] ***********************************************************************/ -void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ) +void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ) { abctime clkStart = Abc_Clock(); - int i, Sum = 0, nWords = Abc_TtWordNum(nVarNum); + int i, Sum = 0, nWords = Abc_TtWordNum(nVarsOrig); Vec_Wrd_t * vTruths = NULL; if ( strstr(pFileName, ".txt") ) - vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarNum ); + vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarsOrig ); else vTruths = Vec_WrdReadBin( pFileName, 0 ); if ( vTruths == NULL ) @@ -1163,7 +1170,7 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLu return; } - printf( "Considering %d functions having %d variables from file \"%s\".\n", nFuncs, nVarNum, pFileName ); + printf( "Considering %d functions having %d variables from file \"%s\".\n", nFuncs, nVarsOrig, pFileName ); word * pCopy = ABC_ALLOC( word, nWords ); int LutStats[100] = {0}; for ( i = 0; i < nFuncs; i++ ) @@ -1176,20 +1183,20 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLu if ( fVerbose || fVeryVerbose ) printf( "Function %3d : ", i ); if ( fVeryVerbose ) - Abc_TtPrintHexRev( stdout, pTruth, nVarNum ), printf( "\n" ); + Abc_TtPrintHexRev( stdout, pTruth, nVarsOrig ), printf( "\n" ); //continue; - int nVars = nVarNum; - Vec_Int_t * vVarIDs = Vec_IntStartNatural( nVars ); - Abc_TtMinimumBase( pTruth, Vec_IntArray(vVarIDs), nVars, &nVars ); + int nVars = -1; + Vec_Int_t * vVarIDs = Vec_IntStartNatural( nVarsOrig ); + Abc_TtMinimumBase( pTruth, Vec_IntArray(vVarIDs), nVarsOrig, &nVars ); + Vec_IntShrink( vVarIDs, nVars ); if ( fVeryVerbose ) { - if ( Vec_IntSize(vVarIDs) != nVars ) - printf( "The support of the function is reduced from %d to %d variables.\n", Vec_IntSize(vVarIDs), nVars ); + if ( nVarsOrig != nVars ) + printf( "The support of the function is reduced from %d to %d variables.\n", nVarsOrig, nVars ); printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs.\n", nVars, nRails, nLutSize ); } - Vec_IntShrink( vVarIDs, nVars ); - - word * pLuts = Abc_LutCascadeDec( NULL, pTruth, vVarIDs, nRails, nLutSize, fVeryVerbose ); + + word * pLuts = Abc_LutCascadeDec( NULL, pTruth, nVarsOrig, vVarIDs, nRails, nLutSize, fVeryVerbose ); Vec_IntFree( vVarIDs ); if ( pLuts == NULL ) { if ( fVerbose || fVeryVerbose ) @@ -1198,15 +1205,15 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLu } Sum++; LutStats[Abc_LutCascadeCount(pLuts)]++; - int nWords2 = Abc_TtWordNum(nVars); - word * pTruth2 = Abc_LutCascadeTruth( pLuts, nVars ); + word * pTruth2 = Abc_LutCascadeTruth( pLuts, nVarsOrig ); if ( fVeryVerbose ) Abc_LutCascadePrint( pLuts ); if ( fVerbose || fVeryVerbose ) printf( "Decomposition exists. " ); - if ( !Abc_TtEqual(pTruth, pTruth2, nWords2) ) { + if ( !Abc_TtEqual(pCopy, pTruth2, nWords) ) { printf( "Verification FAILED for function %d.\n", i ); - Abc_TtPrintHexRev( stdout, pTruth, nVarNum ), printf( "\n" ); + printf( "Before: " ); Abc_TtPrintHexRev( stdout, pCopy, nVarsOrig ), printf( "\n" ); + printf( "After: " ); Abc_TtPrintHexRev( stdout, pTruth2, nVarsOrig ), printf( "\n" ); } else if ( fVerbose || fVeryVerbose ) printf( "Verification passed.\n" ); From 29706ebede44660483e72c54448236943a7a8dcf Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 31 Mar 2025 19:09:54 -0700 Subject: [PATCH 34/42] Bug with LUT cascade mapping. --- src/misc/util/utilBSet.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/misc/util/utilBSet.c b/src/misc/util/utilBSet.c index e6d8a6673..b331c29df 100644 --- a/src/misc/util/utilBSet.c +++ b/src/misc/util/utilBSet.c @@ -52,6 +52,8 @@ struct Abc_BSEval_t_ Vec_Wrd_t * vCofs; // cofactors }; +#define MAX_PAT_WORD_SIZE 1024 // 64 cofs * 16 words + //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -197,7 +199,7 @@ int Abc_TtGetCMCount( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_ return Abc_TtGetCM4( p, nVars, Vec_IntArray(vCounts), vUsed ); if ( nFVars == 5 ) return Abc_TtGetCM5( p, nVars, vTable, vStore, vUsed ); - if ( nFVars == 6 ) + if ( nFVars >= 6 && nFVars <= 10 ) return Abc_TtGetCM6( p, nVars, nFVars, vTable, vStore, vUsed ); assert( 0 ); return 0; @@ -345,7 +347,7 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In { int nMintsBS = 1 << (nVars - nFVars); int nWordsBS = Abc_TtWordNum(nVars - nFVars); - assert( nMintsBS * nWordsBS <= 1024 ); + assert( nMintsBS * nWordsBS <= MAX_PAT_WORD_SIZE ); memset( pPat, 0, 8 * nMintsBS * nWordsBS ); int nMyu = 0; if ( nFVars == 1 ) @@ -358,7 +360,7 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In nMyu = Abc_TtGetCM4Pat( p, nVars, Vec_IntArray(vCounts), vUsed, pPat ); else if ( nFVars == 5 ) nMyu = Abc_TtGetCM5Pat( p, nVars, vTable, vStore, vUsed, pPat ); - else if ( nFVars == 6 ) + else if ( nFVars >= 6 && nFVars <= 10 ) nMyu = Abc_TtGetCM6Pat( p, nVars, nFVars, vTable, vStore, vUsed, pPat ); else assert( 0 ); return nMyu; @@ -366,7 +368,7 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In int Abc_TtGetCMPat( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_Int_t * vTable, Vec_Wrd_t * vStore, Vec_Int_t * vUsed ) { - word pPat[1024]; + word pPat[MAX_PAT_WORD_SIZE]; int nRails, nMyu = Abc_TtGetCMInt( p, nVars, nFVars, vCounts, vTable, vStore, vUsed, pPat ); if ( nMyu <= 2 ) nRails = 1; @@ -620,7 +622,7 @@ int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int n //printf( "\n" ); } if ( 0 ) { - word pPat[1024]; + word pPat[MAX_PAT_WORD_SIZE]; int nRails = 1, Shared = 0; if ( CostThis > (1 << nRails) ) { extern int Abc_SharedEvalBest( Abc_BSEval_t * p, word * pTruth, int nVars, int nCVars, int nFVars, int MyuMin, int nRails, int fVerbose, int * pSetShared, word * pPat ); @@ -921,7 +923,8 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR word * pTruth = ABC_ALLOC( word, Abc_TtWordNum(nVars) ); word * pBest = ABC_ALLOC( word, Abc_TtWordNum(nVars) ); Abc_TtCopy( pTruth, pFunc, Abc_TtWordNum(nVars), 0 ); - int i, nVarsCur = nVars, nOutVars = 0; word pPat[1024]; + int i, nVarsCur = nVars, nOutVars = 0; + word pPat[MAX_PAT_WORD_SIZE]; while ( nVarsCur > nLutSize ) { int pPerm[32] = {0}; @@ -1001,9 +1004,7 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int int v, nWords = Abc_TtWordNum(nVars); word * pCopy = ABC_ALLOC( word, nWords ); Abc_TtCopy( pCopy, pTruth, nWords, 0 ); - word pPat[1024]; - - //Abc_TtPrintHexRev( stdout, pTruth, nVars ); printf( "\n" ); + word pPat[MAX_PAT_WORD_SIZE]; int pPermBest[32] = {0}; word * pBest = ABC_ALLOC( word, nWords ); From 2c003f88655754dd99367bc9e156dfb7cbc82c70 Mon Sep 17 00:00:00 2001 From: Franz Reichl Date: Tue, 1 Apr 2025 11:25:30 +0200 Subject: [PATCH 35/42] Extend logging for eSLIM --- src/base/abci/abc.c | 62 ++++++------ src/opt/eslim/eSLIM.cpp | 137 +++++++++++++++++---------- src/opt/eslim/eSLIM.h | 8 +- src/opt/eslim/eSLIMMan.hpp | 4 - src/opt/eslim/eSLIMMan.tpp | 82 +++++----------- src/opt/eslim/relationGeneration.hpp | 96 ++++++++++++++++++- src/opt/eslim/selectionStrategy.hpp | 2 +- src/opt/eslim/selectionStrategy.tpp | 4 +- src/opt/eslim/synthesisEngine.tpp | 7 ++ src/opt/eslim/utils.hpp | 2 +- 10 files changed, 253 insertions(+), 151 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 433f3cac0..c3c31267c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -56681,17 +56681,13 @@ usage: int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void seteSLIMParams(eSLIM_ParamStruct* params); extern Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params); - extern Gia_Man_t* applyeSLIMIncremental(Gia_Man_t * pGia, const eSLIM_ParamStruct* params, unsigned int restarts, unsigned int deepsynTimeout); - - int nruns = 0; - int deepsynTimeout = 180; - int runOneShotMode = 0; + eSLIM_ParamStruct params; int c; Gia_Man_t * pTemp; seteSLIMParams(¶ms); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "DIPRSTVZfhnos" ) ) != EOF ) { + while ( ( c = Extra_UtilGetopt( argc, argv, "DIMPRSTVZdfhns" ) ) != EOF ) { switch ( c ) { case 'D': if ( globalUtilOptind >= argc ) @@ -56699,9 +56695,9 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Print( -1, "Command line switch \"-D\" should be followed by an integer.\n" ); goto usage; } - deepsynTimeout = atoi(argv[globalUtilOptind]); + params.timeout_inprocessing = atoi(argv[globalUtilOptind]); globalUtilOptind++; - if ( deepsynTimeout < 1 ) + if ( params.timeout_inprocessing < 1 ) goto usage; break; case 'I': @@ -56715,6 +56711,17 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { if ( params.iterations < 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; + } + params.mode = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( params.mode < 0 || params.mode > 2) + goto usage; + break; case 'P': if ( globalUtilOptind >= argc ) { @@ -56723,7 +56730,7 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { } params.expansion_probability = atof(argv[globalUtilOptind]); globalUtilOptind++; - if ( params.expansion_probability < 0 ) + if ( params.expansion_probability <= 0 || params.expansion_probability > 1) goto usage; break; case 'R': @@ -56732,9 +56739,9 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" ); goto usage; } - nruns = atoi(argv[globalUtilOptind]); + params.nruns = atoi(argv[globalUtilOptind]); globalUtilOptind++; - if ( nruns < 0 ) + if ( params.nruns < 1 ) goto usage; break; case 'S': @@ -56765,9 +56772,9 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { Abc_Print( -1, "Command line switch \"-V\" should be followed by an integer.\n" ); goto usage; } - params.verbose = atoi(argv[globalUtilOptind]); + params.verbosity_level = atoi(argv[globalUtilOptind]); globalUtilOptind++; - if ( params.verbose < 0 || params.verbose > 2 ) + if ( params.verbosity_level < 0 || params.verbosity_level > 3 ) goto usage; break; case 'Z': @@ -56780,6 +56787,9 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { params.seed = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'd' : + params.apply_inprocessing ^= 1; + break; case 'f' : params.forbidden_pairs ^= 1; break; @@ -56788,9 +56798,6 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { case 'n' : params.extended_normality_processing ^= 1; break; - case 'o' : - runOneShotMode ^= 1; - break; case 's' : params.fill_subcircuits ^= 1; break; @@ -56803,31 +56810,28 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) { return 1; } - if (runOneShotMode) { - pTemp = applyeSLIM(pAbc->pGia, ¶ms); - } else { - pTemp = applyeSLIMIncremental(pAbc->pGia, ¶ms, nruns, deepsynTimeout); - } - + pTemp = applyeSLIM(pAbc->pGia, ¶ms); + Abc_FrameUpdateGia( pAbc, pTemp ); return 0; usage: - Abc_Print( -2, "usage: &eslim [-RTIDSPAV ] [-ch]\n" ); + Abc_Print( -2, "usage: &eslim [-DIMPRSTVZ ] [-dfhns]\n" ); Abc_Print( -2, "\t circuit minimization using exact synthesis and the SAT-based local improvement method (SLIM)\n" ); - Abc_Print( -2, "\t-D : the timeout in seconds for the individual deepsyn runs [default = %d]\n", deepsynTimeout ); + Abc_Print( -2, "\t-D : the timeout in seconds for the individual deepsyn runs [default = %d]\n", params.timeout_inprocessing ); Abc_Print( -2, "\t-I : the maximal number of iterations (0 = no limit) for the individual eSLIM runs [default = %d]\n", params.iterations ); + Abc_Print( -2, "\t-M : the synthesis mode to use [default = %d]\n", params.mode ); Abc_Print( -2, "\t-P : the probability of expanding a node [default = %.2f]\n", params.expansion_probability ); - Abc_Print( -2, "\t-R : the number of runs of eSLIM + Inprocessing [default = %d]\n", nruns ); + Abc_Print( -2, "\t-R : the number of runs of eSLIM + Inprocessing [default = %d]\n", params.nruns ); Abc_Print( -2, "\t-S : the maximal size of considered subcircuits [default = %d]\n", params.subcircuit_size_bound ); Abc_Print( -2, "\t-T : the timeout in seconds for the individual eSLIM runs [default = %d]\n", params.timeout ); - Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", params.verbose); + Abc_Print( -2, "\t-V : the verbosity level [default = %d]\n", params.verbosity_level); Abc_Print( -2, "\t-Z : use a fixed seed\n", params.seed); + Abc_Print( -2, "\t-d : toggle inprocessing with deepsyn\n"); Abc_Print( -2, "\t-f : toggle using subcircuits with forbidden pairs\n"); Abc_Print( -2, "\t-h : print the command usage\n"); - Abc_Print( -2, "\t-n : extended normality processing\n"); - Abc_Print( -2, "\t-o : single run of eSLIM without inprocessing\n"); - Abc_Print( -2, "\t-s : fill subcircuits\n"); + Abc_Print( -2, "\t-n : toggle extended normality processing\n"); + Abc_Print( -2, "\t-s : toggle fill subcircuits\n"); Abc_Print( -2, "\t\n" ); Abc_Print( -2, "\t This command was contributed by Franz-Xaver Reichl from University of Freiburg.\n" ); return 1; diff --git a/src/opt/eslim/eSLIM.cpp b/src/opt/eslim/eSLIM.cpp index 142531090..24200e6e2 100644 --- a/src/opt/eslim/eSLIM.cpp +++ b/src/opt/eslim/eSLIM.cpp @@ -46,7 +46,7 @@ eSLIM::eSLIMConfig getCfg(const eSLIM_ParamStruct* params) { config.strash_intervall = params->strash_intervall; config.nselection_trials = params->nselection_trials; config.seed = params->seed; - config.verbose = params->verbose; + config.verbosity_level = params->verbosity_level; config.expansion_probability = params->expansion_probability; return config; } @@ -58,15 +58,18 @@ void seteSLIMParams(eSLIM_ParamStruct* params) { params->apply_strash = 1; params->fix_seed = 0; params->trial_limit_active = 1; + params->apply_inprocessing = 1; params->timeout = 1620; + params->timeout_inprocessing = 180; params->iterations = 0; params->subcircuit_size_bound = 6; params->strash_intervall = 100; params->nselection_trials = 100; + params->nruns = 1; params->mode = 0; params->seed = 0; - params->verbose = 0; - params->expansion_probability = 0.4; + params->verbosity_level = 1; + params->expansion_probability = 0.4; } Gia_Man_t* selectApproach(Gia_Man_t* pGia, eSLIM::eSLIMConfig params, eSLIM::eSLIMLog& log, int approach, bool allow_forbidden_pairs) { @@ -83,6 +86,12 @@ Gia_Man_t* selectApproach(Gia_Man_t* pGia, eSLIM::eSLIMConfig params, eSLIM::eSL } else { return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); }; + case 2: + if (allow_forbidden_pairs) { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + } else { + return eSLIM::eSLIM_Man::applyeSLIM(pGia, params, log); + }; default: std::cerr << "eSLIM -- Invalid mode given\n"; assert (false && "Invalid approach selected"); @@ -90,89 +99,113 @@ Gia_Man_t* selectApproach(Gia_Man_t* pGia, eSLIM::eSLIMConfig params, eSLIM::eSL } } -Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params) { - eSLIM::eSLIMConfig config = getCfg(params); - int initial_size = Gia_ManAndNum(pGia); - Gia_Man_t * temp = Gia_ManDup(pGia); - eSLIM::eSLIMLog log(params->subcircuit_size_bound); - Gia_Man_t* result = selectApproach(temp, config, log, params->mode, params->forbidden_pairs); - if (params->verbose > 0) { - std::cout << "#Iterations with forbidden pairs: " << log.subcircuits_with_forbidden_pairs << "\n"; - int new_size = initial_size - Gia_ManAndNum(result); - std::cout << "#reduced gates: " << new_size << "\n"; +Gia_Man_t* runInprocessing(Gia_Man_t * pGia, const eSLIM_ParamStruct* params, unsigned int it) { + Gia_Man_t * tmp = Gia_ManDeepSyn( pGia, 1, ABC_INFINITY, params->timeout_inprocessing, 0, params->seed + it, 0, 0); + if ( Gia_ManAndNum(pGia) > Gia_ManAndNum(tmp) ) { + Gia_ManStop( pGia ); + pGia = tmp; + } else { + Gia_ManStop( tmp ); } - return result; - + return pGia; } -Gia_Man_t* applyeSLIMIncremental(Gia_Man_t* pGia, const eSLIM_ParamStruct* params, unsigned int restarts, unsigned int deepsynTimeout) { +void printSetting(const eSLIM_ParamStruct* params) { + std::cout << "Apply eSLIM (timeout: " << params->timeout << ") "; + if (params->apply_inprocessing) { + std::cout << "+ deepsyn (timeout: " << params->timeout_inprocessing << ") "; + } + std::cout << params->nruns << " times.\n"; + if (params->iterations > 0) { + std::cout << "Stop eSLIM runs after " << params->iterations << " iterations.\n"; + } + std::cout << "Consider subcircuits with up to " << params->subcircuit_size_bound << " gates.\n"; + printf("When expanding subcircuits, select gates with a probability of %.2f %%.\n", 100 * params->expansion_probability); + if (params->forbidden_pairs) { + std::cout << "Consider subcircuits containing gates, which are connected outside of the subcircuit.\n"; + } + if (params->mode == 0) { + std::cout << "Use an incremental SAT encoding for exact synthesis and the SAT solver CaDiCaL.\n"; + } else { + std::cout << "Use a one-shot SAT encoding for exact synthesis and the SAT solver Kissat.\n"; + } +} + +Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params) { eSLIM::eSLIMConfig config = getCfg(params); - config.verbose = params->verbose > 1; + config.verbosity_level = params->verbosity_level; int eSLIM_reductions = 0; int deepsyn_reductions = 0; Gia_Man_t * pThis = Gia_ManDup(pGia); - Gia_Man_t * tmp; eSLIM::eSLIMLog log(params->subcircuit_size_bound); int initial_size = Gia_ManAndNum(pThis); - if (params->verbose > 0) { + if (params->verbosity_level > 0) { + printSetting(params); std::cout << "Initial size: " << initial_size << "\n"; } - - for (unsigned int i = 0; i <= restarts; i++) { + for (unsigned int i = 0; i < params->nruns; i++) { if (config.fix_seed) { config.seed = params->seed + i; } - int size_iteration_start = Gia_ManAndNum(pThis); + if (params->verbosity_level > 0) { + std::cout << "Start eslim run " << i + 1 << "\n"; + } pThis = selectApproach(pThis, config, log, params->mode, params->forbidden_pairs); int size_eslim = Gia_ManAndNum(pThis); eSLIM_reductions += size_iteration_start - size_eslim; - if (params->verbose > 0) { - std::cout << "Size eSLIM it-" << i << " : " << size_eslim << "\n"; - } - tmp = Gia_ManDeepSyn( pThis, 1, ABC_INFINITY, deepsynTimeout, 0, params->seed + i, 0, 0); - int size_deepsyn = Gia_ManAndNum(tmp); - - if ( Gia_ManAndNum(pThis) > Gia_ManAndNum(tmp) ) { - Gia_ManStop( pThis ); - pThis = tmp; - deepsyn_reductions += size_eslim - size_deepsyn; - } else { - Gia_ManStop( tmp ); + if (params->apply_inprocessing) { + if (params->verbosity_level > 0) { + std::cout << "Start inprocessing run " << i + 1 << "\n"; + } + pThis = runInprocessing(pThis, params, i); + if (params->verbosity_level > 0) { + std::cout << "Inprocessing: Initial size: " << size_eslim << " final size: " << Gia_ManAndNum(pThis) << "\n"; + } + deepsyn_reductions += size_eslim - Gia_ManAndNum(pThis); } } + if (params->verbosity_level > 0) { + int final_size = Gia_ManAndNum(pThis); + std::cout << "Final size: " << final_size << "\n"; + int total_reductions = eSLIM_reductions + deepsyn_reductions; + double reduction_ratio = 100 * static_cast(total_reductions) / initial_size; + printf("Total reduction: %d (%.2f %%)\n", total_reductions, reduction_ratio); + if (params->apply_inprocessing) { + std::cout << "#Gates reduced by eSLIM: " << eSLIM_reductions << " "; + std::cout << "#Gates reduced by deepsyn: " << deepsyn_reductions << "\n"; + } + } - if (params->verbose > 0) { - std::cout << "#Gates reduced by eSLIM: " << eSLIM_reductions << "\n"; - std::cout << "#Gates reduced by deepsyn: " << deepsyn_reductions << "\n"; + if (params->verbosity_level > 1) { std::cout << "Total #iterations: " << log.iteration_count << "\n"; std::cout << "Total relation generation time (s): " << log.relation_generation_time << "\n"; std::cout << "Total synthesis time (s): " << log.synthesis_time << "\n"; std::cout << "#Iterations with forbidden pairs: " << log.subcircuits_with_forbidden_pairs << "\n"; - + } + if (params->verbosity_level > 2) { for (int i = 2; i < log.nof_analyzed_circuits_per_size.size(); i++) { int replaced = log.nof_replaced_circuits_per_size.size() > i ? log.nof_replaced_circuits_per_size[i] : 0; int reduced = log.nof_reduced_circuits_per_size.size() > i ? log.nof_reduced_circuits_per_size[i] : 0; std::cout << "#gates: " << i << " - #analysed: " << log.nof_analyzed_circuits_per_size[i] << " - #replaced: " << replaced << " - #reduced: " << reduced << "\n"; } - } - - if (params->verbose > 1) { - for (int i = 0; i < log.nof_sat_calls_per_size.size(); i++) { - if (log.nof_sat_calls_per_size[i] == 0) { - std::cout << "#gates: " << i << " - avg. sat time: -\n"; - } else { - std::cout << "#gates: " << i << " - avg. sat time: " << static_cast(log.cummulative_sat_runtimes_per_size[i]) / (1000 * log.nof_sat_calls_per_size[i]) << " sec\n"; + if (params->mode == 0) { + for (int i = 0; i < log.nof_sat_calls_per_size.size(); i++) { + if (log.nof_sat_calls_per_size[i] == 0) { + std::cout << "#gates: " << i << " - avg. sat time: -\n"; + } else { + std::cout << "#gates: " << i << " - avg. sat time: " << static_cast(log.cummulative_sat_runtimes_per_size[i]) / (1000 * log.nof_sat_calls_per_size[i]) << " sec\n"; + } } - } - for (int i = 0; i < log.nof_unsat_calls_per_size.size(); i++) { - if (log.nof_unsat_calls_per_size[i] == 0) { - std::cout << "#gates: " << i << " - avg. unsat time: -\n"; - } else { - std::cout << "#gates: " << i << " - avg. unsat time: " << static_cast(log.cummulative_unsat_runtimes_per_size[i]) / (1000* log.nof_unsat_calls_per_size[i]) << " sec\n"; + for (int i = 0; i < log.nof_unsat_calls_per_size.size(); i++) { + if (log.nof_unsat_calls_per_size[i] == 0) { + std::cout << "#gates: " << i << " - avg. unsat time: -\n"; + } else { + std::cout << "#gates: " << i << " - avg. unsat time: " << static_cast(log.cummulative_unsat_runtimes_per_size[i]) / (1000* log.nof_unsat_calls_per_size[i]) << " sec\n"; + } } } } diff --git a/src/opt/eslim/eSLIM.h b/src/opt/eslim/eSLIM.h index 1d4bc2175..857e32f47 100644 --- a/src/opt/eslim/eSLIM.h +++ b/src/opt/eslim/eSLIM.h @@ -30,21 +30,25 @@ ABC_NAMESPACE_HEADER_START struct eSLIM_ParamStruct_ { int forbidden_pairs; // Allow forbidden pairs in the selected subcircuits int extended_normality_processing; // Additional checks for non normal subcircuits - double expansion_probability; // the probability that a node is added to the subcircuit int fill_subcircuits; // If a subcircuit has fewer than subcircuit_size_bound gates, try to fill it with rejected gates. int apply_strash; int fix_seed; int trial_limit_active; + int apply_inprocessing; unsigned int timeout; // available time in seconds (soft limit) + unsigned int timeout_inprocessing; unsigned int iterations; // maximal number of iterations. No limit if 0 unsigned int subcircuit_size_bound; // upper bound for the subcircuit sizes unsigned int strash_intervall; unsigned int nselection_trials; + unsigned int nruns; + + double expansion_probability; // the probability that a node is added to the subcircuit int mode; // 0: Cadical Incremental, 1: Kissat Oneshot int seed; - int verbose; + int verbosity_level; }; diff --git a/src/opt/eslim/eSLIMMan.hpp b/src/opt/eslim/eSLIMMan.hpp index 5a6718099..22114dd09 100644 --- a/src/opt/eslim/eSLIMMan.hpp +++ b/src/opt/eslim/eSLIMMan.hpp @@ -54,10 +54,6 @@ namespace eSLIM { void findReplacement(); Mini_Aig_t* findMinimumAig(const Subcircuit& subcir); - Abc_RData_t* generateRelation(const Subcircuit& subcir); - Vec_Int_t* generateRelationPatterns(const Subcircuit& subcir); - Abc_RData_t* constructABCRelationRepresentation(int nof_inputs, int nof_outputs, Vec_Int_t * patterns); - Vec_Wrd_t* getSimsIn(Abc_RData_t* relation); Vec_Wrd_t* getSimsOut(Abc_RData_t* relation); word getAllFalseBehaviour(const Subcircuit& subcir); diff --git a/src/opt/eslim/eSLIMMan.tpp b/src/opt/eslim/eSLIMMan.tpp index ae12e2bb7..8eb46db5c 100644 --- a/src/opt/eslim/eSLIMMan.tpp +++ b/src/opt/eslim/eSLIMMan.tpp @@ -32,7 +32,6 @@ ABC_NAMESPACE_HEADER_START - Vec_Int_t* Gia_ManGenIoCombs( Gia_Man_t * pGia, Vec_Int_t * vInsOuts, int nIns, int fVerbose ); Mini_Aig_t * Mini_AigDupCompl( Mini_Aig_t * p, int ComplIns, int ComplOuts ); int Exa6_ManFindPolar( word First, int nOuts ); Vec_Wrd_t * Exa6_ManTransformInputs( Vec_Wrd_t * vIns ); @@ -47,13 +46,11 @@ namespace eSLIM { Gia_Man_t* eSLIM_Man::applyeSLIM(Gia_Man_t * p, const eSLIMConfig& cfg, eSLIMLog& log) { eSLIM_Man eslim(p, cfg, log); eslim.minimize(); - if (cfg.verbose > 0) { - std::cout << "Relation generation time: " << log.relation_generation_time - eslim.relation_generation_time << "\n"; - std::cout << "Synthesis time: " << log.synthesis_time - eslim.synthesis_time << "\n"; - } return eslim.getCircuit(); } + + template eSLIM_Man::eSLIM_Man(Gia_Man_t * pGia, const eSLIMConfig& cfg, eSLIMLog& log) : gia_man(pGia), cfg(cfg), log(log), @@ -71,6 +68,7 @@ namespace eSLIM { abctime nTimeToStop = clkStart + cfg.timeout * CLOCKS_PER_SEC; unsigned int iteration = 0; unsigned int iterMax = cfg.iterations ? cfg.iterations - 1 : UINT_MAX; + int current_size = Gia_ManAndNum(gia_man); while (Abc_Clock() <= nTimeToStop && iteration <= iterMax && !stopeSLIM) { iteration++; findReplacement(); @@ -84,59 +82,26 @@ namespace eSLIM { gia_man = Gia_ManRehash( pTemp, 0 ); Gia_ManStop( pTemp ); } - } - log.iteration_count += iteration; - - if (cfg.verbose) { - printf( "Time %8.2f sec\n", (float)1.0*(Abc_Clock() - clkStart)/CLOCKS_PER_SEC ); - std::cout << "#Iterations: " << iteration << "\n"; - } - } - - template - Abc_RData_t* eSLIM_Man::generateRelation(const Subcircuit& subcir) { - int nof_outputs = Vec_IntSize(subcir.io) - subcir.nof_inputs; - assert(Vec_IntSize(subcir.io) <= 32); - abctime relation_generation_start = Abc_Clock(); - Vec_Int_t* relation_patterns_masks = generateRelationPatterns(subcir); - log.relation_generation_time += (double)1.0*(Abc_Clock() - relation_generation_start)/CLOCKS_PER_SEC; - Abc_RData_t* relation = constructABCRelationRepresentation(subcir.nof_inputs, nof_outputs, relation_patterns_masks); - Vec_IntFree(relation_patterns_masks); - return relation; - } - - template - Vec_Int_t* eSLIM_Man::generateRelationPatterns(const Subcircuit& subcir) { - Vec_Int_t * vRes = RelationGenerator::computeRelation(gia_man, subcir); - if ( vRes == NULL ) { - return nullptr; - } - return vRes; - } - - template - Abc_RData_t* eSLIM_Man::constructABCRelationRepresentation(int nof_inputs, int nof_outputs, Vec_Int_t * patterns) { - int i, mask; - int nof_vars = nof_inputs + nof_outputs; - Abc_RData_t* p = Abc_RDataStart( nof_inputs, nof_outputs, Vec_IntSize(patterns) ); - Vec_IntForEachEntry( patterns, mask, i ) { - for ( int k = 0; k < nof_vars; k++ ) { - if ( (mask >> (nof_vars-1-k)) & 1 ) { - if ( k < nof_inputs ) { - Abc_RDataSetIn( p, k, i ); - } else { - Abc_RDataSetOut( p, 2*(k-nof_inputs)+1, i ); - } - } else { - if ( k >= nof_inputs ) { - Abc_RDataSetOut( p, 2*(k-nof_inputs), i ); - } + if (cfg.verbosity_level > 0) { + int sz = Gia_ManAndNum(gia_man); + if (sz < current_size) { + current_size = sz; + printf("\rIteration %8d : #and = %7d elapsed time = %7.2f sec\n", iteration, sz, (float)1.0*(Abc_Clock() - clkStart)/CLOCKS_PER_SEC); + } else { + printf("\rIteration %8d", iteration); + fflush(stdout); } } } - Abc_RData_t* p2 = Abc_RData2Rel(p); - Abc_RDataStop(p); - return p2; + log.iteration_count += iteration; + if (cfg.verbosity_level > 0) { + int sz = Gia_ManAndNum(gia_man); + printf("\r#Iterations %8d #and = %7d elapsed time = %7.2f sec\n", iteration, sz, (float)1.0*(Abc_Clock() - clkStart)/CLOCKS_PER_SEC); + if (cfg.verbosity_level > 1) { + printf("Relation generation time: %.2f sec\n", log.relation_generation_time - relation_generation_time); + printf("Synthesis time: %.2f sec\n", log.synthesis_time - synthesis_time); + } + } } template @@ -190,15 +155,18 @@ namespace eSLIM { if (subcir.forbidden_pairs.size() > 0) { log.subcircuits_with_forbidden_pairs++; } + + abctime relation_generation_start = Abc_Clock(); + Abc_RData_t* relation = RelationGenerator::computeRelation(gia_man, subcir); + log.relation_generation_time += (double)1.0*(Abc_Clock() - relation_generation_start)/CLOCKS_PER_SEC; - Abc_RData_t* relation = generateRelation(subcir); int nDivs = 0; int nOuts = relation->nOuts; int nVars = relation->nIns; if ( nVars == 0 ) { return nullptr; } - assert (nVars <= 8); //Assertion from original ABC code + // assert (nVars <= 8); Vec_Wrd_t* vSimsDiv = getSimsIn(relation); Vec_Wrd_t* vSimsOut = getSimsOut(relation); diff --git a/src/opt/eslim/relationGeneration.hpp b/src/opt/eslim/relationGeneration.hpp index 2d29fe8ef..28d8dc512 100644 --- a/src/opt/eslim/relationGeneration.hpp +++ b/src/opt/eslim/relationGeneration.hpp @@ -28,6 +28,8 @@ #include "misc/util/abc_namespaces.h" #include #include "aig/gia/gia.h" +#include "misc/util/utilTruth.h" // ioResub.h depends on utilTruth.h +#include "base/io/ioResub.h" #include "utils.hpp" // #include "satInterfaces.hpp" @@ -41,8 +43,8 @@ namespace eSLIM { class RelationGenerator { public: - static Vec_Int_t* computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir); - + static Abc_RData_t* computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir); + private: Gia_Man_t* pGia; const Subcircuit& subcir; @@ -51,6 +53,12 @@ namespace eSLIM { void setup(); Vec_Int_t* getRelation(); + static Abc_RData_t* constructABCRelationRepresentation(Vec_Int_t * patterns, int nof_inputs, int nof_outputs); + // Reimplementation with disabled prints + // We do not want to modify code in other parts of ABC + static Abc_RData_t * Abc_RData2Rel( Abc_RData_t * p ); + + friend Derived; }; @@ -85,10 +93,90 @@ namespace eSLIM { } template - inline Vec_Int_t* RelationGenerator::computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir) { + inline Abc_RData_t* RelationGenerator::computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir) { T generator(gia_man, subcir); generator.setup(); - return generator.getRelation(); + Vec_Int_t* relation_patterns_masks = generator.getRelation(); + if ( relation_patterns_masks == NULL ) { + return nullptr; + } + int nof_inputs = subcir.nof_inputs; + int nof_outputs = Vec_IntSize(subcir.io) - subcir.nof_inputs; + Abc_RData_t* r = constructABCRelationRepresentation(relation_patterns_masks, nof_inputs, nof_outputs); + Vec_IntFree(relation_patterns_masks); + return r; + } + + template + inline Abc_RData_t* RelationGenerator::constructABCRelationRepresentation(Vec_Int_t * patterns, int nof_inputs, int nof_outputs) { + int i, mask; + int nof_vars = nof_inputs + nof_outputs; + Abc_RData_t* p = Abc_RDataStart( nof_inputs, nof_outputs, Vec_IntSize(patterns) ); + Vec_IntForEachEntry( patterns, mask, i ) { + for ( int k = 0; k < nof_vars; k++ ) { + if ( (mask >> (nof_vars-1-k)) & 1 ) { + if ( k < nof_inputs ) { + Abc_RDataSetIn( p, k, i ); + } else { + Abc_RDataSetOut( p, 2*(k-nof_inputs)+1, i ); + } + } else { + if ( k >= nof_inputs ) { + Abc_RDataSetOut( p, 2*(k-nof_inputs), i ); + } + } + } + } + Abc_RData_t* p2 = Abc_RData2Rel(p); + Abc_RDataStop(p); + return p2; + } + + template + inline Abc_RData_t * RelationGenerator::Abc_RData2Rel( Abc_RData_t * p ) { + assert( p->nIns < 64 ); + assert( p->nOuts < 32 ); + int w; + Vec_Wrd_t * vSimsIn2 = Vec_WrdStart( 64*p->nSimWords ); + Vec_Wrd_t * vSimsOut2 = Vec_WrdStart( 64*p->nSimWords ); + for ( w = 0; w < p->nIns; w++ ) + Abc_TtCopy( Vec_WrdEntryP(vSimsIn2, w*p->nSimWords), Vec_WrdEntryP(p->vSimsIn, w*p->nSimWords), p->nSimWords, 0 ); + for ( w = 0; w < p->nOuts; w++ ) + Abc_TtCopy( Vec_WrdEntryP(vSimsOut2, w*p->nSimWords), Vec_WrdEntryP(p->vSimsOut, (2*w+1)*p->nSimWords), p->nSimWords, 0 ); + Vec_Wrd_t * vTransIn = Vec_WrdStart( 64*p->nSimWords ); + Vec_Wrd_t * vTransOut = Vec_WrdStart( 64*p->nSimWords ); + Extra_BitMatrixTransposeP( vSimsIn2, p->nSimWords, vTransIn, 1 ); + Extra_BitMatrixTransposeP( vSimsOut2, p->nSimWords, vTransOut, 1 ); + Vec_WrdShrink( vTransIn, p->nPats ); + Vec_WrdShrink( vTransOut, p->nPats ); + Vec_Wrd_t * vTransInCopy = Vec_WrdDup(vTransIn); + Vec_WrdUniqify( vTransInCopy ); + // if ( Vec_WrdSize(vTransInCopy) == p->nPats ) + // printf( "This resub problem is not a relation.\n" ); + // create the relation + Abc_RData_t * pNew = Abc_RDataStart( p->nIns, 1 << (p->nOuts-1), Vec_WrdSize(vTransInCopy) ); + pNew->nOuts = p->nOuts; + int i, k, n, iLine = 0; word Entry, Entry2; + Vec_WrdForEachEntry( vTransInCopy, Entry, i ) { + for ( n = 0; n < p->nIns; n++ ) + if ( (Entry >> n) & 1 ) + Abc_InfoSetBit( (unsigned *)Vec_WrdEntryP(pNew->vSimsIn, n*pNew->nSimWords), iLine ); + Vec_WrdForEachEntry( vTransIn, Entry2, k ) { + if ( Entry != Entry2 ) + continue; + Entry2 = Vec_WrdEntry( vTransOut, k ); + assert( Entry2 < (1 << p->nOuts) ); + Abc_InfoSetBit( (unsigned *)Vec_WrdEntryP(pNew->vSimsOut, Entry2*pNew->nSimWords), iLine ); + } + iLine++; + } + assert( iLine == pNew->nPats ); + Vec_WrdFree( vTransOut ); + Vec_WrdFree( vTransInCopy ); + Vec_WrdFree( vTransIn ); + Vec_WrdFree( vSimsIn2 ); + Vec_WrdFree( vSimsOut2 ); + return pNew; } template diff --git a/src/opt/eslim/selectionStrategy.hpp b/src/opt/eslim/selectionStrategy.hpp index b4f0ccf80..29650a5d7 100644 --- a/src/opt/eslim/selectionStrategy.hpp +++ b/src/opt/eslim/selectionStrategy.hpp @@ -104,7 +104,7 @@ namespace eSLIM { template SelectionStrategy::SelectionStrategy(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log) - : gia_man(gia_man), cfg(cfg), log(log), rng(std::random_device()()) { + : gia_man(gia_man), cfg(cfg), log(log), rng(std::random_device()()), bdist(cfg.expansion_probability) { } template diff --git a/src/opt/eslim/selectionStrategy.tpp b/src/opt/eslim/selectionStrategy.tpp index ba150d624..94f656a5b 100644 --- a/src/opt/eslim/selectionStrategy.tpp +++ b/src/opt/eslim/selectionStrategy.tpp @@ -45,9 +45,11 @@ namespace eSLIM { template bool SelectionStrategy::filterSubcircuit(const Subcircuit& subcir) { - if (subcir.nof_inputs > 8) { + // if (subcir.nof_inputs > 8) { + if (subcir.nof_inputs > 10) { return false; } + // ABC internally requires that the subcircuit has not more than 6 outputs (e.g. generateMinterm) if (Vec_IntSize(subcir.io)-subcir.nof_inputs > 6) { return false; } diff --git a/src/opt/eslim/synthesisEngine.tpp b/src/opt/eslim/synthesisEngine.tpp index cc1d3d610..6a8485f7f 100644 --- a/src/opt/eslim/synthesisEngine.tpp +++ b/src/opt/eslim/synthesisEngine.tpp @@ -19,6 +19,12 @@ ***********************************************************************/ #include +#ifdef WIN32 + #include + #define unlink _unlink +#else + #include +#endif #include "misc/util/utilTruth.h" @@ -613,6 +619,7 @@ namespace eSLIM { return nullptr; } Vec_Int_t * vRes = Exa4_ManParse( pFileNameOut ); + unlink( pFileNameIn ); return vRes; } diff --git a/src/opt/eslim/utils.hpp b/src/opt/eslim/utils.hpp index bcf2262c1..fb942c417 100644 --- a/src/opt/eslim/utils.hpp +++ b/src/opt/eslim/utils.hpp @@ -55,7 +55,7 @@ namespace eSLIM { int minimum_dynamic_timeout_sample_size = 50; double dynamic_timeout_buffer_factor = 1.4; - int verbose = 0; + int verbosity_level = 0; }; struct eSLIMLog { From 96c28881a868f3dad1e73caa6df5df7e11347e37 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 1 Apr 2025 19:03:17 -0700 Subject: [PATCH 36/42] Bug fix in LUT cascade. --- src/misc/util/utilBSet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc/util/utilBSet.c b/src/misc/util/utilBSet.c index b331c29df..27496ddfe 100644 --- a/src/misc/util/utilBSet.c +++ b/src/misc/util/utilBSet.c @@ -877,7 +877,7 @@ int Abc_SharedEvalBest( Abc_BSEval_t * p, word * pTruth, int nVars, int nCVars, int MyuCur, Myu = Abc_TtGetCMInt( pTruth, nVars, nFVars, p->vCounts, p->vTable, p->vStore, p->vUsed, pPat ); int nRailsCur = Abc_Base2Log( Myu ); Vec_Int_t * vLevel; assert( Myu == MyuMin && nRailsCur > nRails ); - int i, k, iSet, iStart, nSharedMax = nVars - nCVars - nFVars - 1, nRailsMin = 100; + int i, k, iSet, iStart, nSharedMax = nVars - nFVars - nRails, nRailsMin = 100; Vec_WecForEachLevelStartStop( p->vSets, vLevel, i, 1, nSharedMax ) { Vec_IntForEachEntryDouble( vLevel, iSet, iStart, k ) { if ( iSet & CVarMask ) From 5c604949afc1e4a4fd0bb701f5f4e506529be452 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 5 Apr 2025 16:37:49 -0700 Subject: [PATCH 37/42] Enable dumping of the resulting permutation of internal nodes in "permute". --- src/base/abci/abc.c | 50 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index c3c31267c..6eb020726 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -26186,7 +26186,7 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) extern Abc_Ntk_t * Abc_NtkRestrashRandom( Abc_Ntk_t * pNtk ); extern void Abc_NtkPermutePiUsingFanout( Abc_Ntk_t * pNtk ); Abc_Ntk_t * pNtk = pAbc->pNtkCur, * pNtkRes = NULL; - char * pFlopPermFile = NULL, * pInPermFile = NULL, * pOutPermFile = NULL; + char * pFlopPermFile = NULL, * pInPermFile = NULL, * pOutPermFile = NULL, * pMapPermFile = NULL; int fInputs = 1; int fOutputs = 1; int fFlops = 1; @@ -26195,7 +26195,7 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) int Seed = -1; int c; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "SIOFiofnxh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "SIOFMiofnxh" ) ) != EOF ) { switch ( c ) { @@ -26237,6 +26237,15 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) pFlopPermFile = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'M': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by a file name.\n" ); + goto usage; + } + pMapPermFile = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'i': fInputs ^= 1; break; @@ -26281,8 +26290,40 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "To permute nodes, the network should be structurally hashed.\n" ); return 1; } - if ( fNodes ) + if ( fNodes ) { pNtkRes = Abc_NtkRestrashRandom( pNtk ); + if ( pMapPermFile ) { + if ( Abc_NtkObjNumMax(pNtkRes) != Abc_NtkObjNumMax(pNtk) ) { + printf( "Cannot output 1-to-1 node mapping because the networks have different node counts.\n" ); + return 1; + } + FILE * pFile = fopen( pMapPermFile, "wb" ); + if ( pFile == NULL ) { + printf( "Cannot open output file \"%s\" to dump the permutation of internal nodes.\n", pMapPermFile ); + return 1; + } + Abc_Obj_t * pObj; int i, iNode, Counter = 0; + int StartOld = Abc_NtkObjNumMax(pNtk) - Abc_NtkNodeNum(pNtk); + int StartNew = Abc_NtkObjNumMax(pNtkRes) - Abc_NtkNodeNum(pNtkRes); + Abc_NtkForEachNode( pNtk, pObj, i ) { + if ( Counter++ != i - StartOld ) { + printf( "Cannot output 1-to-1 node mapping because node order is non-standard.\n" ); + fclose( pFile ); + return 1; + } + iNode = pObj->pCopy->Id - StartNew; + if ( iNode < 0 || iNode >= Abc_NtkNodeNum(pNtkRes) ) { + printf( "Cannot output 1-to-1 node mapping because node IDs are out of order.\n" ); + fclose( pFile ); + return 1; + } + fprintf( pFile, "%d ", iNode+1 ); + } + fprintf( pFile, "\n" ); + fclose( pFile ); + printf( "Finished dumping the permutation of internal nodes into file \"%s\".\n", pMapPermFile ); + } + } else pNtkRes = Abc_NtkDup( pNtk ); if ( pNtkRes == NULL ) @@ -26295,7 +26336,7 @@ int Abc_CommandPermute( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: permute [-S num] [-iofnxh] [-I filename] [-O filename] [-F filename]\n" ); + Abc_Print( -2, "usage: permute [-S num] [-iofnxh] [-I filename] [-O filename] [-F filename] [-M filename]\n" ); Abc_Print( -2, "\t performs random permutation of inputs/outputs/flops\n" ); Abc_Print( -2, "\t-S num : the random seed to generate permutations (0 <= num < INT_MAX) [default = %d]\n", Seed ); Abc_Print( -2, "\t-i : toggle permuting primary inputs [default = %s]\n", fInputs? "yes": "no" ); @@ -26307,6 +26348,7 @@ usage: Abc_Print( -2, "\t-I : (optional) file with the input permutation\n" ); Abc_Print( -2, "\t-O : (optional) file with the output permutation\n" ); Abc_Print( -2, "\t-F : (optional) file with the flop permutation\n" ); + Abc_Print( -2, "\t-M : (optional) file with the resulting permutation of internal nodes\n" ); return 1; } From 3f479dc84f9afc0b23d1866badb4d1a2fb7b4fb9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 5 Apr 2025 22:39:59 -0700 Subject: [PATCH 38/42] Bug fixes in LUT cascade. --- src/misc/util/utilBSet.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/misc/util/utilBSet.c b/src/misc/util/utilBSet.c index 27496ddfe..a50a8079f 100644 --- a/src/misc/util/utilBSet.c +++ b/src/misc/util/utilBSet.c @@ -50,10 +50,9 @@ struct Abc_BSEval_t_ Vec_Wrd_t * vStore; // cofactors Vec_Wec_t * vSets; // sets Vec_Wrd_t * vCofs; // cofactors + word * pPat; // patterns }; -#define MAX_PAT_WORD_SIZE 1024 // 64 cofs * 16 words - //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// @@ -199,7 +198,7 @@ int Abc_TtGetCMCount( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_ return Abc_TtGetCM4( p, nVars, Vec_IntArray(vCounts), vUsed ); if ( nFVars == 5 ) return Abc_TtGetCM5( p, nVars, vTable, vStore, vUsed ); - if ( nFVars >= 6 && nFVars <= 10 ) + if ( nFVars >= 6 ) return Abc_TtGetCM6( p, nVars, nFVars, vTable, vStore, vUsed ); assert( 0 ); return 0; @@ -347,7 +346,7 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In { int nMintsBS = 1 << (nVars - nFVars); int nWordsBS = Abc_TtWordNum(nVars - nFVars); - assert( nMintsBS * nWordsBS <= MAX_PAT_WORD_SIZE ); + //assert( nMintsBS * nWordsBS <= MAX_PAT_WORD_SIZE ); memset( pPat, 0, 8 * nMintsBS * nWordsBS ); int nMyu = 0; if ( nFVars == 1 ) @@ -360,7 +359,7 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In nMyu = Abc_TtGetCM4Pat( p, nVars, Vec_IntArray(vCounts), vUsed, pPat ); else if ( nFVars == 5 ) nMyu = Abc_TtGetCM5Pat( p, nVars, vTable, vStore, vUsed, pPat ); - else if ( nFVars >= 6 && nFVars <= 10 ) + else if ( nFVars >= 6 ) nMyu = Abc_TtGetCM6Pat( p, nVars, nFVars, vTable, vStore, vUsed, pPat ); else assert( 0 ); return nMyu; @@ -368,12 +367,11 @@ int Abc_TtGetCMInt( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_In int Abc_TtGetCMPat( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_Int_t * vTable, Vec_Wrd_t * vStore, Vec_Int_t * vUsed ) { - word pPat[MAX_PAT_WORD_SIZE]; - int nRails, nMyu = Abc_TtGetCMInt( p, nVars, nFVars, vCounts, vTable, vStore, vUsed, pPat ); + int nRails, nMyu = Abc_TtGetCMInt( p, nVars, nFVars, vCounts, vTable, vStore, vUsed, NULL ); if ( nMyu <= 2 ) nRails = 1; else - nRails = Abc_TtCheck1Shared( pPat, nVars, nFVars, nMyu ); + nRails = Abc_TtCheck1Shared( NULL, nVars, nFVars, nMyu ); return nRails; } int Abc_TtGetCM( word * p, int nVars, int nFVars, Vec_Int_t * vCounts, Vec_Int_t * vTable, Vec_Wrd_t * vStore, Vec_Int_t * vUsed, int fShared ) @@ -569,7 +567,8 @@ void Abc_BSEvalFree( Abc_BSEval_t * p ) Vec_IntFree( p->vUsed ); Vec_WrdFree( p->vStore ); Vec_WecFreeP( &p->vSets ); - Vec_WrdFreeP( &p->vCofs ); + Vec_WrdFreeP( &p->vCofs ); + ABC_FREE( p->pPat ); ABC_FREE( p ); } void Abc_BSEvalOneTest( word * pT, int nVars, int nBVars, int fVerbose ) @@ -622,11 +621,11 @@ int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int n //printf( "\n" ); } if ( 0 ) { - word pPat[MAX_PAT_WORD_SIZE]; + //word pPat[MAX_PAT_WORD_SIZE]; int nRails = 1, Shared = 0; if ( CostThis > (1 << nRails) ) { extern int Abc_SharedEvalBest( Abc_BSEval_t * p, word * pTruth, int nVars, int nCVars, int nFVars, int MyuMin, int nRails, int fVerbose, int * pSetShared, word * pPat ); - int nRailsMin = Abc_SharedEvalBest( p, pIn, nVars, nCVars, nFVars, CostThis, nRails, 0, &Shared, pPat ); + int nRailsMin = Abc_SharedEvalBest( p, pIn, nVars, nCVars, nFVars, CostThis, nRails, 0, &Shared, p->pPat ); printf( " RailMin = %d. Shared = %2d. ", nRailsMin, Shared ); } } @@ -829,7 +828,7 @@ static inline int Abc_BSEvalCountUnique( word * pISets, int nISets, int nBSWords static inline int Abc_BSEvalCountUniqueMax( word * pISets, int nISets, int nBSWords, word * pCofs, int nOnes, int nISetsMaxHave ) { int m, nMints = (1 << nOnes), CountMax = 0; - assert( nOnes > 0 && nOnes < 5 ); + //assert( nOnes > 0 && nOnes < 5 ); for ( m = 0; m < nMints; m++ ) { int Count = Abc_BSEvalCountUnique( pISets, nISets, nBSWords, pCofs + m * nBSWords ); @@ -924,7 +923,6 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR word * pBest = ABC_ALLOC( word, Abc_TtWordNum(nVars) ); Abc_TtCopy( pTruth, pFunc, Abc_TtWordNum(nVars), 0 ); int i, nVarsCur = nVars, nOutVars = 0; - word pPat[MAX_PAT_WORD_SIZE]; while ( nVarsCur > nLutSize ) { int pPerm[32] = {0}; @@ -934,6 +932,10 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR Vec_WecFreeP( &p->vSets ); Vec_WrdFreeP( &p->vCofs ); p->vCofs = Abc_BSEvalCreateCofactorSets( nLutSize, &p->vSets ); + if ( p->nBVars < nLutSize ) { + ABC_FREE( p->pPat ); + p->pPat = ABC_ALLOC( word, (1 << nLutSize)*Abc_TtWordNum(nLutSize) ); + } } p->vPairs = Abc_GenChasePairs( nVarsCur, nLutSize ); p->nVars = nVarsCur; @@ -942,7 +944,7 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR int MyuMin = Abc_BSEvalBest( p, pTruth, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, fVerbose, pPerm, 0 ); int Shared = 0, nRailsMin = Abc_Base2Log( MyuMin ); if ( nRailsMin > nRails ) - nRailsMin = Abc_SharedEvalBest( p, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, MyuMin, nRails, fVerbose, &Shared, pPat ); + nRailsMin = Abc_SharedEvalBest( p, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, MyuMin, nRails, fVerbose, &Shared, p->pPat ); if ( nRailsMin > nRails ) { Vec_WrdFreeP( &vRes ); break; @@ -998,13 +1000,17 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int Vec_WecFreeP( &p->vSets ); Vec_WrdFreeP( &p->vCofs ); p->vCofs = Abc_BSEvalCreateCofactorSets( nLutSize, &p->vSets ); + if ( p->nBVars < nLutSize ) { + ABC_FREE( p->pPat ); + p->pPat = ABC_ALLOC( word, (1 << nLutSize)*Abc_TtWordNum(nLutSize) ); + } p->nBVars = nLutSize; } int v, nWords = Abc_TtWordNum(nVars); word * pCopy = ABC_ALLOC( word, nWords ); Abc_TtCopy( pCopy, pTruth, nWords, 0 ); - word pPat[MAX_PAT_WORD_SIZE]; + //word pPat[MAX_PAT_WORD_SIZE]; int pPermBest[32] = {0}; word * pBest = ABC_ALLOC( word, nWords ); @@ -1021,7 +1027,7 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int int Shared = 0, nRailsMin = Abc_Base2Log( MyuMin ); if ( nRailsMin > nRails ) { - nRailsMin = Abc_SharedEvalBest( p, pBest, nVars, nRVars, nVars-nLutSize, MyuMin, nRails, 0, &Shared, pPat ); + nRailsMin = Abc_SharedEvalBest( p, pBest, nVars, nRVars, nVars-nLutSize, MyuMin, nRails, 0, &Shared, p->pPat ); MyuMin = 1 << nRailsMin; } From 1b6b5539228ddc392ef54ff31686d78807750fbc Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sat, 5 Apr 2025 22:40:24 -0700 Subject: [PATCH 39/42] New commands for truth table file processing. --- src/base/abci/abc.c | 138 +++++++++++++++++++++++++++++++++++++++-- src/base/abci/abcCas.c | 126 +++++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+), 5 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6eb020726..6e3bf2413 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -141,6 +141,8 @@ static int Abc_CommandTestDec ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandTestNpn ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandTestRPO ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandTestTruth ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandTestSupp ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandTestRand ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunSat ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunEco ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandRunGen ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -955,6 +957,8 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Synthesis", "testnpn", Abc_CommandTestNpn, 0 ); Cmd_CommandAdd( pAbc, "LogiCS", "testrpo", Abc_CommandTestRPO, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "testtruth", Abc_CommandTestTruth, 0 ); + Cmd_CommandAdd( pAbc, "Synthesis", "testsupp", Abc_CommandTestSupp, 0 ); + Cmd_CommandAdd( pAbc, "Synthesis", "testrand", Abc_CommandTestRand, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "runsat", Abc_CommandRunSat, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "runeco", Abc_CommandRunEco, 0 ); Cmd_CommandAdd( pAbc, "Synthesis", "rungen", Abc_CommandRunGen, 0 ); @@ -7267,6 +7271,130 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandTestSupp( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Abc_NtkSuppMinFile( char * pFileName ); + int c, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF ) + { + switch ( c ) + { + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( argc != globalUtilOptind + 1 ) + { + Abc_Print( 1,"Input file is not given.\n" ); + return 0; + } + Abc_NtkSuppMinFile( argv[globalUtilOptind] ); + return 0; + +usage: + Abc_Print( -2, "usage: testsupp [-vh] \n" ); + Abc_Print( -2, "\t reads truth tables from file and support-minimizes them\n" ); + Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : file to read the truth tables from\n"); + return 1; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandTestRand( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Abc_NtkRandFile( char * pFileName, int nVars, int nFuncs, int nMints ); + int c, nVars = 0, nFuncs = 0, nMints = 0, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "NFMvh" ) ) != EOF ) + { + switch ( c ) + { + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); + goto usage; + } + nVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nVars < 0 ) + goto usage; + break; + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by an integer.\n" ); + goto usage; + } + nFuncs = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'M': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" ); + goto usage; + } + nMints = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( argc != globalUtilOptind + 1 ) + { + Abc_Print( 1,"Input file is not given.\n" ); + return 0; + } + Abc_NtkRandFile( argv[globalUtilOptind], nVars, nFuncs, nMints ); + return 0; + +usage: + Abc_Print( -2, "usage: testrand [-NFMvh] \n" ); + Abc_Print( -2, "\t generates truth tables and writes them into a file\n" ); + Abc_Print( -2, "\t-N : the number of input variables [default = %d]\n", nVars ); + Abc_Print( -2, "\t-F : the number of random functions to generate [default = %d]\n", nFuncs ); + Abc_Print( -2, "\t-M : the number of positive minterms in the random function [default = %d]\n", nMints ); + Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : file to write the truth tables to\n"); + return 1; +} + /**Function************************************************************* Synopsis [] @@ -10297,7 +10425,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "INKTSRMiaocgvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "INKTSFMiaocgvh" ) ) != EOF ) { switch ( c ) { @@ -10354,10 +10482,10 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->pSymStr = argv[globalUtilOptind]; globalUtilOptind++; break; - case 'R': + case 'F': if ( globalUtilOptind >= argc ) { - Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" ); + Abc_Print( -1, "Command line switch \"-F\" should be followed by an integer.\n" ); goto usage; } pPars->nRandFuncs = atoi(argv[globalUtilOptind]); @@ -10439,13 +10567,13 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutexact [-INKTRM ] [-S string] [-iaocgvh] \n" ); + Abc_Print( -2, "usage: lutexact [-INKTFM ] [-S string] [-iaocgvh] \n" ); Abc_Print( -2, "\t exact synthesis of I-input function using N K-input gates\n" ); Abc_Print( -2, "\t-I : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-N : the number of K-input nodes [default = %d]\n", pPars->nNodes ); Abc_Print( -2, "\t-K : the number of node fanins [default = %d]\n", pPars->nLutSize ); Abc_Print( -2, "\t-T : the runtime limit in seconds [default = %d]\n", pPars->RuntimeLim ); - Abc_Print( -2, "\t-R : the number of random functions to try [default = unused]\n" ); + Abc_Print( -2, "\t-F : the number of random functions to try [default = unused]\n" ); Abc_Print( -2, "\t-M : the number of positive minterms in the random function [default = unused]\n" ); Abc_Print( -2, "\t-S : charasteristic string of a symmetric function [default = %d]\n", pPars->pSymStr ); Abc_Print( -2, "\t-i : toggle using incremental solving [default = %s]\n", pPars->fUseIncr ? "yes" : "no" ); diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 612de7e64..4aadaf8f0 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -1231,6 +1231,132 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int n Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Vec_WrdWriteTruthHex( char * pFileName, Vec_Wrd_t * vTruths, int nVars ) +{ + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) { printf("Cannot open file \"%s\" for reading.\n", pFileName); return; } + int i, nWords = Abc_TtWordNum(nVars), nFuncs = Vec_WrdSize(vTruths)/nWords; + assert( nFuncs * nWords == Vec_WrdSize(vTruths) ); + for ( i = 0; i < nFuncs; i++ ) + Abc_TtPrintHexRev( pFile, Vec_WrdEntryP(vTruths, i*nWords), nVars ), fprintf( pFile, "\n" ); + fclose( pFile ); +} +void Abc_NtkSuppMinFile( char * pFileName ) +{ + int fError = 0, nFileSize = Gia_FileSize( pFileName ); + FILE * pFile = fopen( pFileName, "rb" ); + if ( pFile == NULL ) { printf("Cannot open file \"%s\" for reading.\n", pFileName); return; } + Vec_Wrd_t ** pvTruths = ABC_CALLOC( Vec_Wrd_t *, 32 ); + char * pToken, * pLine = ABC_ALLOC( char, nFileSize ); + word * pTruth = ABC_ALLOC( word, nFileSize/16 ); + int Len, nVars = -1, nWords = -1, nFuncs = 0, nSuppSums[2] = {0}; + for ( int i = 0; fgets(pLine, nFileSize, pFile); i++ ) { + pToken = strtok(pLine, " ,\n\r\r"); + if ( pToken == NULL ) + continue; + if ( pToken[0] == '0' && pToken[1] == 'x' ) + pToken += 2; + Len = strlen(pToken); + nVars = Abc_Base2Log(Len); + if ( Len != (1 << nVars) ) { + printf( "The number of hex characters (%d) in the truth table listed in line %d is not a degree of 2.\n", Len, i ); + fError = 1; + break; + } + nVars += 2; + if ( !Abc_TtReadHex( pTruth, pToken ) ) { + printf( "Line %d has truth table that cannot be read correctly (%s).\n", i, pToken ); + fError = 1; + break; + } + nSuppSums[0] += nVars; + Abc_TtMinimumBase( pTruth, NULL, nVars, &nVars ); + nSuppSums[1] += nVars; + if ( pvTruths[nVars] == NULL ) + pvTruths[nVars] = Vec_WrdAlloc( 10000 ); + nWords = Abc_TtWordNum(nVars); + for ( int w = 0; w < nWords; w++ ) + Vec_WrdPush( pvTruths[nVars], pTruth[w] ); + nFuncs++; + } + ABC_FREE( pTruth ); + ABC_FREE( pLine ); + fclose( pFile ); + if ( fError ) { + for ( nVars = 0; nVars < 32; nVars++ ) + if ( pvTruths[nVars] ) + Vec_WrdFreeP( &pvTruths[nVars] ); + ABC_FREE( pvTruths ); + return; + } + // dump the resulting truth tables + printf( "Read and support-minimized %d functions. Total support reduction %d -> %d (%.2f %%).\n", + nFuncs, nSuppSums[0], nSuppSums[1], 100.0*(nSuppSums[0]-nSuppSums[1])/Abc_MaxInt(nSuppSums[0], 1) ); + printf( "The resulting function statistics:\n" ); + for ( nVars = 0; nVars < 32; nVars++ ) { + if ( pvTruths[nVars] == NULL ) + continue; + char pFileName2[1000]; + sprintf( pFileName2, "%s_%02d.txt", Extra_FileNameGeneric(pFileName), nVars ); + Vec_WrdWriteTruthHex( pFileName2, pvTruths[nVars], nVars ); + printf( "Support size %2d : Dumped %6d truth tables into file \"%s\".\n", + nVars, Vec_WrdSize(pvTruths[nVars])/Abc_TtWordNum(nVars), pFileName2 ); + Vec_WrdFreeP( &pvTruths[nVars] ); + } + ABC_FREE( pvTruths ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Abc_NtkRandFile( char * pFileName, int nVars, int nFuncs, int nMints ) +{ + int i, k, nWords = Abc_TtWordNum(nVars); + Vec_Wrd_t * vTruths = Vec_WrdStart( nWords * nFuncs ); + Abc_Random(1); + for ( i = 0; i < nFuncs; i++ ) { + word * pTruth = Vec_WrdEntryP(vTruths, i*nWords); + if ( nMints == 0 ) + for ( k = 0; k < nWords; k++ ) + pTruth[k] = Abc_RandomW(0); + else { + for ( k = 0; k < nMints; k++ ) { + int iMint = 0; + do iMint = Abc_Random(0) % (1 << nVars); + while ( Abc_TtGetBit(pTruth, iMint) ); + Abc_TtSetBit( pTruth, iMint ); + } + } + } + Vec_WrdWriteTruthHex( pFileName, vTruths, nVars ); + if ( nMints ) + printf( "Generated %d random %d-variable functions with %d positive minterms and dumped them into file \"%s\".\n", + nFuncs, nVars, nMints, pFileName ); + else + printf( "Generated %d random %d-variable functions and dumped them into file \"%s\".\n", + nFuncs, nVars, pFileName ); + Vec_WrdFree( vTruths ); +} + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// From c0be439b454fcd3300e6651f6aae5f4e2274e4ba Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 6 Apr 2025 00:14:02 -0700 Subject: [PATCH 40/42] Performance improvements. --- src/base/abci/abc.c | 2 +- src/base/abci/abcCas.c | 90 +++++++++++++++++++++++----------------- src/misc/util/utilBSet.c | 27 ++++++++---- 3 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 6e3bf2413..86266a25d 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -9059,7 +9059,7 @@ int Abc_CommandLutCasDec( Abc_Frame_t * pAbc, int argc, char ** argv ) extern Abc_Ntk_t * Abc_NtkLutCascade2( Abc_Ntk_t * pNtk, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, char * pGuide ); extern void Abc_NtkLutCascadeFile( char * pFileName, int nVarNum, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ); Abc_Ntk_t * pNtk = Abc_FrameReadNtk(pAbc), * pNtkRes; char * pGuide = NULL, * pFileName = NULL; - int c, nVarNum = -1, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 1, fGen = 0, fVerbose = 0, fVeryVerbose = 0; + int c, nVarNum = -1, nLutSize = 6, nStages = 8, nRails = 1, nShared = 2, nIters = 10, fGen = 0, fVerbose = 0, fVeryVerbose = 0; Extra_UtilGetoptReset(); while ( ( c = Extra_UtilGetopt( argc, argv, "KMRSINFgvwh" ) ) != EOF ) { diff --git a/src/base/abci/abcCas.c b/src/base/abci/abcCas.c index 4aadaf8f0..4d34cce68 100644 --- a/src/base/abci/abcCas.c +++ b/src/base/abci/abcCas.c @@ -621,46 +621,51 @@ Abc_Ntk_t * Abc_NtkLutCascade2( Abc_Ntk_t * pNtk, int nLutSize, int nLuts, int n { extern Gia_Man_t * Abc_NtkStrashToGia( Abc_Ntk_t * pNtk ); extern word * Abc_LutCascade2( word * p, int nVars, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose ); - Gia_Man_t * pGia = Abc_NtkStrashToGia( pNtk ); - word * pTruth1 = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, 0) ); int nWords = Abc_TtWordNum(Abc_NtkCiNum(pNtk)); word * pCopy = ABC_ALLOC( word, nWords ); - Abc_TtCopy( pCopy, pTruth1, nWords, 0 ); + Gia_Man_t * pGia = Abc_NtkStrashToGia( pNtk ); + Abc_Ntk_t * pNew = NULL; + Abc_Random(1); + for ( int Iter = 0; Iter < nIters; Iter++ ) { + word * pTruth1 = Gia_ObjComputeTruthTable( pGia, Gia_ManCo(pGia, 0) ); + Abc_TtCopy( pCopy, pTruth1, nWords, 0 ); - int nVars = -1; - Vec_Int_t * vVarIDs = Vec_IntStartNatural( Abc_NtkCiNum(pNtk) ); - Abc_TtMinimumBase( pTruth1, Vec_IntArray(vVarIDs), Abc_NtkCiNum(pNtk), &nVars ); - Vec_IntShrink( vVarIDs, nVars ); - if ( fVerbose ) { - if ( Abc_NtkCiNum(pNtk) != nVars ) - printf( "The support of the function is reduced from %d to %d variables.\n", Abc_NtkCiNum(pNtk), nVars ); - printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs", nVars, nRails, nLutSize ); - if ( pGuide ) - printf( " using structural info: %s", pGuide ); - printf( ".\n" ); - } - - word * pLuts = Abc_LutCascadeDec( pGuide, pTruth1, Abc_NtkCiNum(pNtk), vVarIDs, nRails, nLutSize, fVerbose ); - Abc_Ntk_t * pNew = pLuts ? Abc_NtkLutCascadeFromLuts( pLuts, Abc_NtkCiNum(pNtk), pNtk, nLutSize, fVerbose ) : NULL; - Vec_IntFree( vVarIDs ); - - if ( pLuts ) { - if ( fVerbose ) - Abc_LutCascadePrint( pLuts ); - word * pTruth2 = Abc_LutCascadeTruth( pLuts, Abc_NtkCiNum(pNtk) ); - if ( !Abc_TtEqual(pCopy, pTruth2, nWords) ) { - printf( "Verification FAILED.\n" ); - printf("Function before: "); Abc_TtPrintHexRev( stdout, pCopy, Abc_NtkCiNum(pNtk) ); printf( "\n" ); - printf("Function after: "); Abc_TtPrintHexRev( stdout, pTruth2, Abc_NtkCiNum(pNtk) ); printf( "\n" ); + int nVars = -1; + Vec_Int_t * vVarIDs = Vec_IntStartNatural( Abc_NtkCiNum(pNtk) ); + Abc_TtMinimumBase( pTruth1, Vec_IntArray(vVarIDs), Abc_NtkCiNum(pNtk), &nVars ); + Vec_IntShrink( vVarIDs, nVars ); + if ( fVerbose ) { + if ( Abc_NtkCiNum(pNtk) != nVars ) + printf( "The support of the function is reduced from %d to %d variables.\n", Abc_NtkCiNum(pNtk), nVars ); + printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs", nVars, nRails, nLutSize ); + if ( pGuide ) + printf( " using structural info: %s", pGuide ); + printf( ".\n" ); } - else if ( fVerbose ) - printf( "Verification passed.\n" ); - ABC_FREE( pLuts ); - ABC_FREE( pTruth2 ); + + word * pLuts = Abc_LutCascadeDec( pGuide, pTruth1, Abc_NtkCiNum(pNtk), vVarIDs, nRails, nLutSize, fVerbose ); + pNew = pLuts ? Abc_NtkLutCascadeFromLuts( pLuts, Abc_NtkCiNum(pNtk), pNtk, nLutSize, fVerbose ) : NULL; + Vec_IntFree( vVarIDs ); + + if ( pLuts ) { + if ( fVerbose ) + Abc_LutCascadePrint( pLuts ); + word * pTruth2 = Abc_LutCascadeTruth( pLuts, Abc_NtkCiNum(pNtk) ); + if ( !Abc_TtEqual(pCopy, pTruth2, nWords) ) { + printf( "Verification FAILED.\n" ); + printf("Function before: "); Abc_TtPrintHexRev( stdout, pCopy, Abc_NtkCiNum(pNtk) ); printf( "\n" ); + printf("Function after: "); Abc_TtPrintHexRev( stdout, pTruth2, Abc_NtkCiNum(pNtk) ); printf( "\n" ); + } + else if ( fVerbose ) + printf( "Verification passed.\n" ); + ABC_FREE( pLuts ); + ABC_FREE( pTruth2 ); + break; + } + //ABC_FREE( pTruth1 ); } - Gia_ManStop( pGia ); ABC_FREE( pCopy ); - //ABC_FREE( pTruth1 ); + Gia_ManStop( pGia ); return pNew; } Abc_Ntk_t * Abc_NtkLutCascadeGen( int nLutSize, int nStages, int nRails, int nShared, int fVerbose ) @@ -1154,7 +1159,7 @@ Vec_Wrd_t * Abc_NtkLutCasReadTruths( char * pFileName, int nVarsOrig ) void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int nLuts, int nRails, int nIters, int fVerbose, int fVeryVerbose ) { abctime clkStart = Abc_Clock(); - int i, Sum = 0, nWords = Abc_TtWordNum(nVarsOrig); + int i, Sum = 0, nTotalLuts = 0, nWords = Abc_TtWordNum(nVarsOrig); Vec_Wrd_t * vTruths = NULL; if ( strstr(pFileName, ".txt") ) vTruths = Abc_NtkLutCasReadTruths( pFileName, nVarsOrig ); @@ -1172,7 +1177,8 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int n printf( "Considering %d functions having %d variables from file \"%s\".\n", nFuncs, nVarsOrig, pFileName ); word * pCopy = ABC_ALLOC( word, nWords ); - int LutStats[100] = {0}; + int Iter = 0, LutStats[100] = {0}; + Abc_Random(1); for ( i = 0; i < nFuncs; i++ ) { word * pTruth = Vec_WrdEntryP( vTruths, i*nWords ); @@ -1195,15 +1201,22 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int n printf( "The support of the function is reduced from %d to %d variables.\n", nVarsOrig, nVars ); printf( "Decomposing %d-var function into %d-rail cascade of %d-LUTs.\n", nVars, nRails, nLutSize ); } - + word * pLuts = Abc_LutCascadeDec( NULL, pTruth, nVarsOrig, vVarIDs, nRails, nLutSize, fVeryVerbose ); Vec_IntFree( vVarIDs ); if ( pLuts == NULL ) { + if ( ++Iter < nIters ) { + i--; + continue; + } + Iter = 0; if ( fVerbose || fVeryVerbose ) printf( "Not decomposable.\n" ); continue; } + Iter = 0; Sum++; + nTotalLuts += Abc_LutCascadeCount(pLuts); LutStats[Abc_LutCascadeCount(pLuts)]++; word * pTruth2 = Abc_LutCascadeTruth( pLuts, nVarsOrig ); if ( fVeryVerbose ) @@ -1227,7 +1240,8 @@ void Abc_NtkLutCascadeFile( char * pFileName, int nVarsOrig, int nLutSize, int n if ( LutStats[i] ) printf( " %d LUT6 : Function count = %8d (%6.2f %%)\n", i, LutStats[i], 100.0*LutStats[i]/nFuncs ); printf( "Non-decomp : Function count = %8d (%6.2f %%)\n", nFuncs-Sum, 100.0*(nFuncs-Sum)/Abc_MaxInt(1, nFuncs) ); - printf( "Finished %d functions (speed = %.2f functions / second). ", nFuncs, 1.0*nFuncs/(((double)(Abc_Clock() - clkStart))/((double)CLOCKS_PER_SEC)) ); + printf( "Finished %d functions (%.2f LUTs / function; %.2f functions / sec). ", + nFuncs, 1.0*nTotalLuts/Sum, 1.0*nFuncs/(((double)(Abc_Clock() - clkStart))/((double)CLOCKS_PER_SEC)) ); Abc_PrintTime( 0, "Total time", Abc_Clock() - clkStart ); } diff --git a/src/misc/util/utilBSet.c b/src/misc/util/utilBSet.c index a50a8079f..6f4111eb9 100644 --- a/src/misc/util/utilBSet.c +++ b/src/misc/util/utilBSet.c @@ -589,7 +589,7 @@ void Abc_BSEvalOneTest( word * pT, int nVars, int nBVars, int fVerbose ) int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int nCVars, int nFVars, int fVerbose, int * pPermBest, int fShared ) { int i, k, Var0, Var1, Pla2Var[32], Var2Pla[32]; - int nPermVars = nVars-nCVars; + int nPermVars = nVars-nCVars, Count = 0; assert( p->nVars == nPermVars && p->nBVars == nVars-nFVars ); for ( i = 0; i < nVars; i++ ) Pla2Var[i] = Var2Pla[i] = i; @@ -605,6 +605,11 @@ int Abc_BSEvalBest( Abc_BSEval_t * p, word * pIn, word * pBest, int nVars, int n CostBest = CostThis; if ( pBest ) Abc_TtCopy( pBest, pIn, Abc_Truth6WordNum(nVars), 0 ); if ( pPermBest ) memcpy( pPermBest, Pla2Var, sizeof(int)*nVars ); + Count = 1; + } + else if ( CostBest == CostThis && (Abc_Random(0) % ++Count) == 0 ) { + if ( pBest ) Abc_TtCopy( pBest, pIn, Abc_Truth6WordNum(nVars), 0 ); + if ( pPermBest ) memcpy( pPermBest, Pla2Var, sizeof(int)*nVars ); } if ( fVerbose ) { @@ -922,7 +927,7 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR word * pTruth = ABC_ALLOC( word, Abc_TtWordNum(nVars) ); word * pBest = ABC_ALLOC( word, Abc_TtWordNum(nVars) ); Abc_TtCopy( pTruth, pFunc, Abc_TtWordNum(nVars), 0 ); - int i, nVarsCur = nVars, nOutVars = 0; + int i, r, nVarsCur = nVars, nOutVars = 0; while ( nVarsCur > nLutSize ) { int pPerm[32] = {0}; @@ -943,8 +948,12 @@ word * Abc_LutCascade2( word * pFunc, int nVars, int nLutSize, int nLuts, int nR } int MyuMin = Abc_BSEvalBest( p, pTruth, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, fVerbose, pPerm, 0 ); int Shared = 0, nRailsMin = Abc_Base2Log( MyuMin ); - if ( nRailsMin > nRails ) - nRailsMin = Abc_SharedEvalBest( p, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, MyuMin, nRails, fVerbose, &Shared, p->pPat ); + for ( r = 1; r <= nRails && nRailsMin > r; r++ ) { + int nRailsMinNew = Abc_SharedEvalBest( p, pBest, nVarsCur, nOutVars, nVarsCur-nLutSize, MyuMin, nRails, fVerbose, &Shared, p->pPat ); + if ( nRailsMinNew < 100 ) + nRailsMin = nRailsMinNew; + } + MyuMin = 1 << nRailsMin; if ( nRailsMin > nRails ) { Vec_WrdFreeP( &vRes ); break; @@ -1007,7 +1016,7 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int p->nBVars = nLutSize; } - int v, nWords = Abc_TtWordNum(nVars); + int v, r, nWords = Abc_TtWordNum(nVars); word * pCopy = ABC_ALLOC( word, nWords ); Abc_TtCopy( pCopy, pTruth, nWords, 0 ); //word pPat[MAX_PAT_WORD_SIZE]; @@ -1026,10 +1035,12 @@ word Abc_TtFindBVarsSVars( word * pTruth, int nVars, int nRVars, int nRails, int } int Shared = 0, nRailsMin = Abc_Base2Log( MyuMin ); - if ( nRailsMin > nRails ) { - nRailsMin = Abc_SharedEvalBest( p, pBest, nVars, nRVars, nVars-nLutSize, MyuMin, nRails, 0, &Shared, p->pPat ); - MyuMin = 1 << nRailsMin; + for ( r = 1; r <= nRails && nRailsMin > r; r++ ) { + int nRailsMinNew = Abc_SharedEvalBest( p, pBest, nVars, nRVars, nVars-nLutSize, MyuMin, r, 0, &Shared, p->pPat ); + if ( nRailsMinNew < 100 ) + nRailsMin = nRailsMinNew; } + MyuMin = 1 << nRailsMin; ABC_FREE( pCopy ); ABC_FREE( pBest ); From 27f2429d764d057c2e8cdc882332aa1583cee028 Mon Sep 17 00:00:00 2001 From: MyskYko Date: Sun, 6 Apr 2025 15:46:02 -0700 Subject: [PATCH 41/42] update rrr --- src/aig/gia/gia.h | 2 +- src/aig/gia/giaRrr.cpp | 11 +- src/base/abci/abc.c | 44 ++- src/opt/rrr/rrr.h | 38 ++- src/opt/rrr/rrrAndNetwork.h | 138 ++++++++- src/opt/rrr/rrrBddMspfAnalyzer.h | 2 +- src/opt/rrr/rrrLevelBasePartitioner.h | 293 +++++++++++++++++++ src/opt/rrr/rrrOptimizer.h | 388 +++++++++++++++++++++++--- src/opt/rrr/rrrParameter.h | 11 +- src/opt/rrr/rrrPartitioner.h | 277 +++++++++--------- src/opt/rrr/rrrSatSolver.h | 2 +- src/opt/rrr/rrrScheduler.h | 145 +++++----- src/opt/rrr/rrrSimulator.h | 58 +++- src/opt/rrr/rrrUtils.h | 242 +++++++++++++--- 14 files changed, 1337 insertions(+), 314 deletions(-) create mode 100644 src/opt/rrr/rrrLevelBasePartitioner.h diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index b950da4be..273c530ec 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -1808,7 +1808,7 @@ extern Gia_Man_t * Gia_ManTransductionBdd( Gia_Man_t * pGia, int nType, extern Gia_Man_t * Gia_ManTransductionTt( Gia_Man_t * pGia, int nType, int fMspf, int nRandom, int nSortType, int nPiShuffle, int nParameter, int fLevel, Gia_Man_t * pExdc, int fNewLine, int nVerbose ); /*=== giaRrr.cpp ===========================================================*/ -extern Gia_Man_t * Gia_ManRrr( Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nDistance, int nRestarts, int nThreads, int nWindowSize, int fDeterministic ); +extern Gia_Man_t * Gia_ManRrr( Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nPartitionType, int nDistance, int nJobs, int nThreads, int nPartitionSize, int nPartitionSizeMin, int fDeterministic, int nParallelPartitions, int fOptOnInsert, int fGreedy ); /*=== giaCTas.c ===========================================================*/ typedef struct Tas_Man_t_ Tas_Man_t; diff --git a/src/aig/gia/giaRrr.cpp b/src/aig/gia/giaRrr.cpp index df3b91e60..1eccd4dc2 100644 --- a/src/aig/gia/giaRrr.cpp +++ b/src/aig/gia/giaRrr.cpp @@ -5,7 +5,7 @@ ABC_NAMESPACE_IMPL_START -Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nDistance, int nRestarts, int nThreads, int nWindowSize, int fDeterministic) { +Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int nSchedulerVerbose, int nPartitionerVerbose, int nOptimizerVerbose, int nAnalyzerVerbose, int nSimulatorVerbose, int nSatSolverVerbose, int fUseBddCspf, int fUseBddMspf, int nConflictLimit, int nSortType, int nOptimizerFlow, int nSchedulerFlow, int nPartitionType, int nDistance, int nJobs, int nThreads, int nPartitionSize, int nPartitionSizeMin, int fDeterministic, int nParallelPartitions, int fOptOnInsert, int fGreedy) { rrr::AndNetwork ntk; ntk.Read(pGia, rrr::GiaReader); rrr::Parameter Par; @@ -24,11 +24,16 @@ Gia_Man_t *Gia_ManRrr(Gia_Man_t *pGia, int iSeed, int nWords, int nTimeout, int Par.nSortType = nSortType; Par.nOptimizerFlow = nOptimizerFlow; Par.nSchedulerFlow = nSchedulerFlow; + Par.nPartitionType = nPartitionType; Par.nDistance = nDistance; - Par.nRestarts = nRestarts; + Par.nJobs = nJobs; Par.nThreads = nThreads; - Par.nWindowSize = nWindowSize; + Par.nPartitionSize = nPartitionSize; + Par.nPartitionSizeMin = nPartitionSizeMin; Par.fDeterministic = fDeterministic; + Par.nParallelPartitions = nParallelPartitions; + Par.fOptOnInsert = fOptOnInsert; + Par.fGreedy = fGreedy; rrr::Perform(&ntk, &Par); Gia_Man_t *pNew = rrr::CreateGia(&ntk); return pNew; diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 4bf22bd88..2875b3a1b 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -45457,9 +45457,9 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) { Gia_Man_t *pNew; int c; - int iSeed = 0, nWords = 10, nTimeout = 0, nSchedulerVerbose = 1, nPartitionerVerbose = 0, nOptimizerVerbose = 0, nAnalyzerVerbose = 0, nSimulatorVerbose = 0, nSatSolverVerbose = 0, fUseBddCspf = 0, fUseBddMspf = 0, nConflictLimit = 0, nSortType = 12, nOptimizerFlow = 0, nSchedulerFlow = 0, nDistance = 0, nRestarts = 0, nThreads = 1, nWindowSize = 0, fDeterministic = 1; + int iSeed = 0, nWords = 10, nTimeout = 0, nSchedulerVerbose = 1, nPartitionerVerbose = 0, nOptimizerVerbose = 0, nAnalyzerVerbose = 0, nSimulatorVerbose = 0, nSatSolverVerbose = 0, fUseBddCspf = 0, fUseBddMspf = 0, nConflictLimit = 0, nSortType = -1, nOptimizerFlow = 0, nSchedulerFlow = 0, nPartitionType = 0, nDistance = 0, nJobs = 1, nThreads = 1, nPartitionSize = 0, nPartitionSizeMin = 0, fDeterministic = 1, nParallelPartitions = 1, fOptOnInsert = 0, fGreedy = 1; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "XYNJKDRWTCGVPOAQSabdh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "XYZNJKLBDRWTCGVPOAQSabdegh" ) ) != EOF ) { switch ( c ) { @@ -45471,8 +45471,12 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) nSchedulerFlow = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; + case 'Z': + nPartitionType = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; case 'N': - nRestarts = atoi(argv[globalUtilOptind]); + nJobs = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; case 'J': @@ -45480,7 +45484,15 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) globalUtilOptind++; break; case 'K': - nWindowSize = atoi(argv[globalUtilOptind]); + nPartitionSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'L': + nPartitionSizeMin = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + break; + case 'B': + nParallelPartitions = atoi(argv[globalUtilOptind]); globalUtilOptind++; break; case 'D': @@ -45540,6 +45552,12 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'd': fDeterministic ^= 1; break; + case 'e': + fOptOnInsert ^= 1; + break; + case 'g': + fGreedy ^= 1; + break; case 'h': goto usage; default: @@ -45558,32 +45576,38 @@ int Abc_CommandAbc9Rrr( Abc_Frame_t * pAbc, int argc, char ** argv ) return 1; } - pNew = Gia_ManRrr( pAbc->pGia, iSeed, nWords, nTimeout, nSchedulerVerbose, nPartitionerVerbose, nOptimizerVerbose, nAnalyzerVerbose, nSimulatorVerbose, nSatSolverVerbose, fUseBddCspf, fUseBddMspf, nConflictLimit, nSortType, nOptimizerFlow, nSchedulerFlow, nDistance, nRestarts, nThreads, nWindowSize, fDeterministic ); + pNew = Gia_ManRrr( pAbc->pGia, iSeed, nWords, nTimeout, nSchedulerVerbose, nPartitionerVerbose, nOptimizerVerbose, nAnalyzerVerbose, nSimulatorVerbose, nSatSolverVerbose, fUseBddCspf, fUseBddMspf, nConflictLimit, nSortType, nOptimizerFlow, nSchedulerFlow, nPartitionType, nDistance, nJobs, nThreads, nPartitionSize, nPartitionSizeMin, fDeterministic, nParallelPartitions, fOptOnInsert, fGreedy ); Abc_FrameUpdateGia( pAbc, pNew ); return 0; usage: - Abc_Print( -2, "usage: rrr [-XYNJKDRWTCGVPOAQS num] [-abdh]\n" ); + Abc_Print( -2, "usage: rrr [-XYZNJKLBDRWTCGVPOAQS num] [-abdegh]\n" ); Abc_Print( -2, "\t perform optimization\n" ); Abc_Print( -2, "\t-X num : method [default = %d]\n", nOptimizerFlow ); Abc_Print( -2, "\t 0: single-add resub\n" ); Abc_Print( -2, "\t 1: multi-add resub\n" ); Abc_Print( -2, "\t 2: repeat 0 and 1\n" ); + Abc_Print( -2, "\t 3: random one meaningful resub\n" ); Abc_Print( -2, "\t-Y num : flow [default = %d]\n", nSchedulerFlow ); Abc_Print( -2, "\t 0: apply method once\n" ); Abc_Print( -2, "\t 1: iterate like transtoch\n" ); Abc_Print( -2, "\t 2: iterate like deepsyn\n" ); - Abc_Print( -2, "\t-N num : number of restarts or windows [default = %d]\n", nRestarts ); + Abc_Print( -2, "\t-Z num : partition [default = %d]\n", nPartitionType ); + Abc_Print( -2, "\t 0: distance base\n" ); + Abc_Print( -2, "\t 1: level base\n" ); + Abc_Print( -2, "\t-N num : number of jobs to create by restarting or partitioning [default = %d]\n", nJobs ); Abc_Print( -2, "\t-J num : number of threads [default = %d]\n", nThreads ); - Abc_Print( -2, "\t-K num : window size (0 = no partitioning) [default = %d]\n", nWindowSize ); + Abc_Print( -2, "\t-K num : partition size (0 = no partitioning) [default = %d]\n", nPartitionSize ); + Abc_Print( -2, "\t-K num : minimum partition size [default = %d]\n", nPartitionSizeMin ); + Abc_Print( -2, "\t-B num : max number of partitions in parallel [default = %d]\n", nParallelPartitions ); Abc_Print( -2, "\t-D num : distance between nodes (0 = no limit) [default = %d]\n", nDistance ); Abc_Print( -2, "\t-R num : random number generator seed [default = %d]\n", iSeed ); Abc_Print( -2, "\t-W num : number of simulation words [default = %d]\n", nWords ); Abc_Print( -2, "\t-T num : timeout in seconds (0 = no timeout) [default = %d]\n", nTimeout ); Abc_Print( -2, "\t-C num : conflict limit (0 = no limit) [default = %d]\n", nConflictLimit ); - Abc_Print( -2, "\t-G num : fanin cost function [default = %d]\n", nSortType ); + Abc_Print( -2, "\t-G num : fanin cost function (-1 = random) [default = %d]\n", nSortType ); Abc_Print( -2, "\t-V num : scheduler verbosity level [default = %d]\n", nSchedulerVerbose ); Abc_Print( -2, "\t-P num : partitioner verbosity level [default = %d]\n", nPartitionerVerbose ); Abc_Print( -2, "\t-O num : optimizer verbosity level [default = %d]\n", nOptimizerVerbose ); @@ -45593,6 +45617,8 @@ usage: Abc_Print( -2, "\t-a : use BDD-based analyzer (CSPF) [default = %s]\n", fUseBddCspf? "yes": "no" ); Abc_Print( -2, "\t-b : use BDD-based analyzer (MSPF) [default = %s]\n", fUseBddMspf? "yes": "no" ); Abc_Print( -2, "\t-d : ensure deterministic execution [default = %s]\n", fDeterministic? "yes": "no" ); + Abc_Print( -2, "\t-e : apply c2rs; dc2 after importing changes of partitions [default = %s]\n", fOptOnInsert? "yes": "no" ); + Abc_Print( -2, "\t-g : discard changes that increased the cost [default = %s]\n", fGreedy? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); return 1; } diff --git a/src/opt/rrr/rrr.h b/src/opt/rrr/rrr.h index f737b7ffc..c08d562ae 100644 --- a/src/opt/rrr/rrr.h +++ b/src/opt/rrr/rrr.h @@ -8,6 +8,8 @@ #include "rrrAnalyzer.h" #include "rrrSatSolver.h" #include "rrrSimulator.h" +#include "rrrPartitioner.h" +#include "rrrLevelBasePartitioner.h" ABC_NAMESPACE_CXX_HEADER_START @@ -16,15 +18,33 @@ namespace rrr { template void Perform(Ntk *pNtk, Parameter const *pPar) { assert(!pPar->fUseBddCspf || !pPar->fUseBddMspf); - if(pPar->fUseBddCspf) { - Scheduler>> sch(pNtk, pPar); - sch.Run(); - } else if(pPar->fUseBddMspf) { - Scheduler>> sch(pNtk, pPar); - sch.Run(); - } else { - Scheduler, rrr::SatSolver>>> sch(pNtk, pPar); - sch.Run(); + switch(pPar->nPartitionType) { + case 0: + if(pPar->fUseBddCspf) { + Scheduler>, Partitioner> sch(pNtk, pPar); + sch.Run(); + } else if(pPar->fUseBddMspf) { + Scheduler>, Partitioner> sch(pNtk, pPar); + sch.Run(); + } else { + Scheduler, SatSolver>>, Partitioner> sch(pNtk, pPar); + sch.Run(); + } + break; + case 1: + if(pPar->fUseBddCspf) { + Scheduler>, LevelBasePartitioner> sch(pNtk, pPar); + sch.Run(); + } else if(pPar->fUseBddMspf) { + Scheduler>, LevelBasePartitioner> sch(pNtk, pPar); + sch.Run(); + } else { + Scheduler, SatSolver>>, LevelBasePartitioner> sch(pNtk, pPar); + sch.Run(); + } + break; + default: + assert(0); } } diff --git a/src/opt/rrr/rrrAndNetwork.h b/src/opt/rrr/rrrAndNetwork.h index 00afd2386..f39bbdc4d 100644 --- a/src/opt/rrr/rrrAndNetwork.h +++ b/src/opt/rrr/rrrAndNetwork.h @@ -54,7 +54,7 @@ namespace rrr { void SortInts(itr it); unsigned StartTraversal(int n = 1); void EndTraversal(); - void ForEachTfiRec(int id, std::function const &f); + void ForEachTfiRec(int id, std::function const &func); void TakenAction(Action const &action) const; public: @@ -102,13 +102,15 @@ namespace rrr { int FindFanin(int id, int fi) const; bool IsReconvergent(int id); std::vector GetNeighbors(int id, bool fPis, int nHops); - template