mirror of https://github.com/YosysHQ/abc.git
Merge remote-tracking branch 'upstream/master' into yosys-experimental
This commit is contained in:
commit
ada8fb2e87
54
abclib.dsp
54
abclib.dsp
|
|
@ -4194,6 +4194,26 @@ SOURCE=.\src\opt\sbd\sbdWin.c
|
|||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\areaEngine.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\areaEngine.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\cadicalSolver.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\delayEngine.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\delayEngine.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\eSLIM.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
@ -4202,6 +4222,14 @@ SOURCE=.\src\opt\eslim\eSLIM.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\eslimCirMan.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\eslimCirMan.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\eSLIMMan.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
@ -4214,11 +4242,31 @@ SOURCE=.\src\opt\eslim\relationGeneration.hpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\satInterfaces.hpp
|
||||
SOURCE=.\src\opt\eslim\relationSynthesiser.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\selectionStrategy.hpp
|
||||
SOURCE=.\src\opt\eslim\relationSynthesiser.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\selectionStrategies.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\subcircuit.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\subcircuit.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\synthesisEngines.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\tabooList.hpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
|
|
@ -4226,7 +4274,7 @@ SOURCE=.\src\opt\eslim\utils.hpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\opt\eslim\synthesisEngine.hpp
|
||||
SOURCE=.\src\opt\eslim\windowMan.hpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Group
|
||||
|
|
|
|||
|
|
@ -580,6 +580,7 @@ static int Abc_CommandAbc9GroupProve ( Abc_Frame_t * pAbc, int argc, cha
|
|||
static int Abc_CommandAbc9MultiProve ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9SplitProve ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9SProve ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9SProve2 ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9SplitSat ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Bmc ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9SBmc ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
|
@ -665,6 +666,7 @@ static int Abc_CommandAbc9Divide ( 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 );
|
||||
static int Abc_CommandAbc9elSLIM ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
||||
static int Abc_CommandAbc9CatBtor ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
||||
|
|
@ -685,7 +687,9 @@ extern void Extra_BitMatrixTransposeP( Vec_Wrd_t * vSimsIn, int nWordsIn, Vec_Wr
|
|||
typedef struct Wlc_Ntk_t_ Wlc_Ntk_t;
|
||||
typedef struct Wlc_BstPar_t_ Wlc_BstPar_t;
|
||||
extern Gia_Man_t * Wlc_NtkBitBlast( Wlc_Ntk_t * p, Wlc_BstPar_t * pPars );
|
||||
extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent );
|
||||
extern int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile );
|
||||
extern int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, int * pnTimeOut2, int * pnTimeOut3, int * pfUseUif );
|
||||
extern int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent );
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
|
|
@ -1422,7 +1426,8 @@ void Abc_Init( Abc_Frame_t * pAbc )
|
|||
Cmd_CommandAdd( pAbc, "ABC9", "&gprove", Abc_CommandAbc9GroupProve, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&mprove", Abc_CommandAbc9MultiProve, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&splitprove", Abc_CommandAbc9SplitProve, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&sprove", Abc_CommandAbc9SProve, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&sprove", Abc_CommandAbc9SProve, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&sprove2", Abc_CommandAbc9SProve2, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&splitsat", Abc_CommandAbc9SplitSat, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&bmc", Abc_CommandAbc9Bmc, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&bmcs", Abc_CommandAbc9SBmc, 0 );
|
||||
|
|
@ -1514,6 +1519,7 @@ void Abc_Init( Abc_Frame_t * pAbc )
|
|||
Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 );
|
||||
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&eslim", Abc_CommandAbc9eSLIM, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "elslim", Abc_CommandAbc9elSLIM, 0 );
|
||||
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&catbtor", Abc_CommandAbc9CatBtor, 0 );
|
||||
{
|
||||
|
|
@ -51568,9 +51574,10 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
{
|
||||
Gia_Man_t * pGiaUse = pAbc->pGia, * pGiaTemp = NULL;
|
||||
Wlc_Ntk_t * pWlc = (Wlc_Ntk_t *)pAbc->pAbcWlc;
|
||||
char * pReplayFile = NULL;
|
||||
int c, nProcs = 6, nProcsNew = 0, nTimeOut = 3, nTimeOut2 = 10, nTimeOut3 = 100, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWusvwh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "PTUWRusvwh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -51619,6 +51626,15 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
if ( nTimeOut3 <= 0 )
|
||||
goto usage;
|
||||
break;
|
||||
case 'R':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-R\" should be followed by a file name.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pReplayFile = argv[globalUtilOptind];
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'u':
|
||||
fUseUif ^= 1;
|
||||
break;
|
||||
|
|
@ -51673,19 +51689,20 @@ int Abc_CommandAbc9SProve( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Gia_ManStop( pGiaUse );
|
||||
return 1;
|
||||
}
|
||||
pAbc->Status = Cec_GiaProveTest( pGiaUse, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif, pWlc, fVerbose, fVeryVerbose, fSilent );
|
||||
pAbc->Status = Cec_GiaProveTest( pGiaUse, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile );
|
||||
Abc_FrameReplaceCex( pAbc, &pGiaUse->pCexSeq );
|
||||
if ( fUseUif )
|
||||
Gia_ManStop( pGiaUse );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &sprove [-PTUW num] [-usvwh]\n" );
|
||||
Abc_Print( -2, "usage: &sprove [-PTUW num] [-R file] [-usvwh]\n" );
|
||||
Abc_Print( -2, "\t proves CEC problem by case-splitting\n" );
|
||||
Abc_Print( -2, "\t-P num : the number of concurrent processes (1 <= num <= 6) [default = %d]\n", nProcs );
|
||||
Abc_Print( -2, "\t-T num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut );
|
||||
Abc_Print( -2, "\t-U num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut2 );
|
||||
Abc_Print( -2, "\t-W num : runtime limit in seconds per subproblem [default = %d]\n", nTimeOut3 );
|
||||
Abc_Print( -2, "\t-R str : dump replay/trace file for later execution by &sprove2\n" );
|
||||
Abc_Print( -2, "\t-u : enable concurrent UFAR on word-level design (uses internal %%blast + &miter -x)\n" );
|
||||
Abc_Print( -2, "\t-s : enable silent computation (no reporting) [default = %s]\n", fSilent? "yes": "no" );
|
||||
Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" );
|
||||
|
|
@ -51694,6 +51711,109 @@ usage:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int Abc_CommandAbc9SProve2( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
Gia_Man_t * pGiaUse = pAbc->pGia, * pGiaTemp = NULL;
|
||||
Wlc_Ntk_t * pWlc = (Wlc_Ntk_t *)pAbc->pAbcWlc;
|
||||
char * pTraceFile = NULL;
|
||||
int c, nProcs = 0, nTimeOut = 0, nTimeOut2 = 0, nTimeOut3 = 0, fUseUif = 0, fVerbose = 0, fVeryVerbose = 0, fSilent = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "svwh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 's':
|
||||
fSilent ^= 1;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'w':
|
||||
fVeryVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command &sprove2 expects a replay file name.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pTraceFile = argv[globalUtilOptind];
|
||||
globalUtilOptind++;
|
||||
if ( globalUtilOptind != argc )
|
||||
goto usage;
|
||||
if ( !Cec_GiaReplayReadParams( pTraceFile, &nProcs, &nTimeOut, &nTimeOut2, &nTimeOut3, &fUseUif ) )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): Cannot read replay file \"%s\".\n", pTraceFile );
|
||||
return 1;
|
||||
}
|
||||
if ( fUseUif )
|
||||
{
|
||||
pGiaUse = NULL;
|
||||
if ( pWlc == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): Replay requires word-level design for UIF mode.\n" );
|
||||
return 1;
|
||||
}
|
||||
pGiaTemp = Wlc_NtkBitBlast( pWlc, NULL );
|
||||
if ( pGiaTemp == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): Word-level bit-blasting has failed.\n" );
|
||||
return 1;
|
||||
}
|
||||
if ( (Gia_ManPoNum(pGiaTemp) & 1) == 1 )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): Internal \"&miter -x\" requires even number of bit-level outputs.\n" );
|
||||
Gia_ManStop( pGiaTemp );
|
||||
return 1;
|
||||
}
|
||||
pGiaUse = Gia_ManTransformMiter2( pGiaTemp );
|
||||
Gia_ManStop( pGiaTemp );
|
||||
pGiaTemp = NULL;
|
||||
}
|
||||
if ( pGiaUse == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): There is no AIG.\n" );
|
||||
return 1;
|
||||
}
|
||||
if ( Gia_ManRegNum(pGiaUse) == 0 )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9SProve2(): The problem is combinational.\n" );
|
||||
if ( fUseUif )
|
||||
Gia_ManStop( pGiaUse );
|
||||
return 1;
|
||||
}
|
||||
pAbc->Status = Cec_GiaReplayTest( pGiaUse, pWlc, pTraceFile, fVerbose, fVeryVerbose, fSilent );
|
||||
Abc_FrameReplaceCex( pAbc, &pGiaUse->pCexSeq );
|
||||
if ( fUseUif )
|
||||
Gia_ManStop( pGiaUse );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &sprove2 <trace_file> [-svwh]\n" );
|
||||
Abc_Print( -2, "\t replays &sprove strategy stored in the given trace file\n" );
|
||||
Abc_Print( -2, "\t-s : enable silent computation (no reporting) [default = %s]\n", fSilent? "yes": "no" );
|
||||
Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-w : toggle printing more verbose information [default = %s]\n", fVeryVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
@ -59873,18 +59993,43 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
|||
int c;
|
||||
Gia_Man_t * pTemp;
|
||||
seteSLIMParams(¶ms);
|
||||
params.aig = 1;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "DIMPRSTVZdfhns" ) ) != EOF ) {
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "CDIPRSTVWXZcfhistx" ) ) != EOF ) {
|
||||
switch ( c ) {
|
||||
case 'C':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-C\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.approximate_relation = 1;
|
||||
params.relation_tfo_bound = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.relation_tfo_bound < 0 )
|
||||
goto usage;
|
||||
if (globalUtilOptind < argc) {
|
||||
char *next;
|
||||
int tfi_bound = strtol (argv[globalUtilOptind], &next, 10);
|
||||
if (argv[globalUtilOptind] != next && *next == '\0') {
|
||||
params.generate_relation_with_tfi_limit = 1;
|
||||
params.relation_tfi_bound = tfi_bound;
|
||||
globalUtilOptind++;
|
||||
if (params.relation_tfi_bound < 0) {
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-D\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.timeout_inprocessing = atoi(argv[globalUtilOptind]);
|
||||
params.synthesis_approach = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.timeout_inprocessing < 1 )
|
||||
if ( params.synthesis_approach < 0 || params.synthesis_approach > 2)
|
||||
goto usage;
|
||||
break;
|
||||
case 'I':
|
||||
|
|
@ -59898,17 +60043,6 @@ 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 )
|
||||
{
|
||||
|
|
@ -59937,9 +60071,9 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
|||
Abc_Print( -1, "Command line switch \"-S\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.subcircuit_size_bound = atoi(argv[globalUtilOptind]);
|
||||
params.subcircuit_max_size = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.subcircuit_size_bound < 2 )
|
||||
if ( params.subcircuit_max_size < 2 )
|
||||
goto usage;
|
||||
break;
|
||||
case 'T':
|
||||
|
|
@ -59964,6 +60098,32 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
|||
if ( params.verbosity_level < 0 || params.verbosity_level > 3 )
|
||||
goto usage;
|
||||
break;
|
||||
case 'W':
|
||||
if ( globalUtilOptind >= argc + 1)
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-W\" should be followed by two integers.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.nWindows = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if (params.nWindows < 0)
|
||||
goto usage;
|
||||
params.window_size = atoi(argv[globalUtilOptind]);
|
||||
if (params.window_size <= 0)
|
||||
goto usage;
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'X':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-X\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.additional_gates = atoi(argv[globalUtilOptind]);
|
||||
if ( params.additional_gates < 0 )
|
||||
goto usage;
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'Z':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
|
|
@ -59974,24 +60134,34 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
|||
params.seed = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'd' :
|
||||
params.apply_inprocessing ^= 1;
|
||||
case 'c' :
|
||||
params.criticial_path_selection_bias ^= 1;
|
||||
break;
|
||||
case 'f' :
|
||||
params.forbidden_pairs ^= 1;
|
||||
params.forward_search ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
case 'n' :
|
||||
params.extended_normality_processing ^= 1;
|
||||
case 'i' :
|
||||
params.apply_inprocessing ^= 1;
|
||||
break;
|
||||
case 's' :
|
||||
params.fill_subcircuits ^= 1;
|
||||
break;
|
||||
case 't' :
|
||||
params.use_taboo_list ^= 1;
|
||||
break;
|
||||
case 'x' :
|
||||
params.aig = 0;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if (params.nWindows > 0 && params.synthesis_approach != 0) {
|
||||
Abc_Print( -1, "Windows can only be used with area minimization\n" );
|
||||
return 1;
|
||||
}
|
||||
if ( pAbc->pGia == NULL ) {
|
||||
Abc_Print( -1, "Abc_CommandAbc9Test(): There is no AIG.\n" );
|
||||
return 1;
|
||||
|
|
@ -60002,26 +60172,265 @@ int Abc_CommandAbc9eSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
|||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
return 0;
|
||||
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &eslim [-DIMPRSTVZ <num>] [-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 <num> : the timeout in seconds for the individual deepsyn runs [default = %d]\n", params.timeout_inprocessing );
|
||||
Abc_Print( -2, "usage: &eslim [-CDIPRSTVWXZ <num>] [-cfhistx]\n" );
|
||||
Abc_Print( -2, "\t circuit optimization using exact synthesis and the SAT-based local improvement method (SLIM)\n" );
|
||||
Abc_Print( -2, "\t-C <num> : approximate Boolean relations by only considering the frist C levels in the cone \n");
|
||||
Abc_Print( -2, "\t-D <num> : the delay mode to use [default = %d]\n", params.synthesis_approach );
|
||||
Abc_Print( -2, "\t-I <num> : the maximal number of iterations (0 = no limit) for the individual eSLIM runs [default = %d]\n", params.iterations );
|
||||
Abc_Print( -2, "\t-M <num> : the synthesis mode to use [default = %d]\n", params.mode );
|
||||
Abc_Print( -2, "\t-P <num> : the probability of expanding a node [default = %.2f]\n", params.expansion_probability );
|
||||
Abc_Print( -2, "\t-R <num> : the number of runs of eSLIM + Inprocessing [default = %d]\n", params.nruns );
|
||||
Abc_Print( -2, "\t-S <num> : the maximal size of considered subcircuits [default = %d]\n", params.subcircuit_size_bound );
|
||||
Abc_Print( -2, "\t-S <num> : the maximal size of considered subcircuits [default = %d]\n", params.subcircuit_max_size );
|
||||
Abc_Print( -2, "\t-T <num> : the timeout in seconds for the individual eSLIM runs [default = %d]\n", params.timeout );
|
||||
Abc_Print( -2, "\t-V <num> : the verbosity level [default = %d]\n", params.verbosity_level);
|
||||
Abc_Print( -2, "\t-W <num> <num> : Use m windows of size n [default = %d, %d]\n", params.nWindows, params.window_size);
|
||||
Abc_Print( -2, "\t-X <num> : the maximal number of additional gates that may be used for depth optimization [default = %d]\n", params.additional_gates);
|
||||
Abc_Print( -2, "\t-Z <num> : 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-c : toggle bias for selection of nodes on the crictical path\n");
|
||||
Abc_Print( -2, "\t-f : toggle forward expansion of root nodes\n");
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
Abc_Print( -2, "\t-n : toggle extended normality processing\n");
|
||||
Abc_Print( -2, "\t-i : toggle inprocessing\n");
|
||||
Abc_Print( -2, "\t-s : toggle fill subcircuits\n");
|
||||
Abc_Print( -2, "\t-t : toggle use taboo list\n");
|
||||
Abc_Print( -2, "\t-x : allow xor-gates\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;
|
||||
|
||||
}
|
||||
|
||||
int Abc_CommandAbc9elSLIM( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
||||
extern void seteSLIMParams(eSLIM_ParamStruct* params);
|
||||
extern Abc_Ntk_t* applyelSLIM(Abc_Ntk_t * pGia, const eSLIM_ParamStruct* params);
|
||||
|
||||
eSLIM_ParamStruct params;
|
||||
Abc_Ntk_t* pNtk, *pNtknew;
|
||||
int c;
|
||||
seteSLIMParams(¶ms);
|
||||
Extra_UtilGetoptReset();
|
||||
params.subcircuit_max_size = 4;
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "CDGIPRSTVWXZfhist" ) ) != EOF ) {
|
||||
switch ( c ) {
|
||||
case 'C':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-C\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.approximate_relation = 1;
|
||||
params.relation_tfo_bound = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.relation_tfo_bound < 0 )
|
||||
goto usage;
|
||||
if (globalUtilOptind < argc) {
|
||||
char *next;
|
||||
int tfi_bound = strtol (argv[globalUtilOptind], &next, 10);
|
||||
if (argv[globalUtilOptind] != next && *next == '\0') {
|
||||
params.generate_relation_with_tfi_limit = 1;
|
||||
params.relation_tfi_bound = tfi_bound;
|
||||
globalUtilOptind++;
|
||||
if (params.relation_tfi_bound < 0) {
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-D\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.synthesis_approach = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.synthesis_approach < 0 || params.synthesis_approach > 2)
|
||||
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 'G':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-G\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.gate_size = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.gate_size < 1 || params.gate_size > 6 )
|
||||
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 || params.expansion_probability > 1)
|
||||
goto usage;
|
||||
break;
|
||||
case 'R':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-R\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.nruns = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.nruns < 1 )
|
||||
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_max_size = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.subcircuit_max_size < 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.verbosity_level = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if ( params.verbosity_level < 0 || params.verbosity_level > 3 )
|
||||
goto usage;
|
||||
break;
|
||||
case 'W':
|
||||
if ( globalUtilOptind >= argc + 1)
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-W\" should be followed by two integers.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.nWindows = atoi(argv[globalUtilOptind]);
|
||||
globalUtilOptind++;
|
||||
if (params.nWindows < 0)
|
||||
goto usage;
|
||||
params.window_size = atoi(argv[globalUtilOptind]);
|
||||
if (params.window_size <= 0)
|
||||
goto usage;
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'X':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-X\" should be followed by an integer.\n" );
|
||||
goto usage;
|
||||
}
|
||||
params.additional_gates = atoi(argv[globalUtilOptind]);
|
||||
if ( params.additional_gates < 0 )
|
||||
goto usage;
|
||||
globalUtilOptind++;
|
||||
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 'c' :
|
||||
params.criticial_path_selection_bias ^= 1;
|
||||
break;
|
||||
case 'f' :
|
||||
params.forward_search ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
case 'i' :
|
||||
params.apply_inprocessing ^= 1;
|
||||
break;
|
||||
case 's' :
|
||||
params.fill_subcircuits ^= 1;
|
||||
break;
|
||||
case 't' :
|
||||
params.use_taboo_list ^= 1;
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
pNtk = Abc_FrameReadNtk(pAbc);
|
||||
if ( pNtk == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Empty network.\n" );
|
||||
return 1;
|
||||
}
|
||||
if ( !Abc_NtkIsLogic(pNtk) )
|
||||
{
|
||||
Abc_Print( -1, "This command can only be applied to a logic network.\n" );
|
||||
return 1;
|
||||
}
|
||||
if (!Abc_NtkHasSop(pNtk)) {
|
||||
Abc_NtkToSop( pNtk, -1, ABC_INFINITY );
|
||||
}
|
||||
|
||||
|
||||
params.aig = 0;
|
||||
pNtknew = applyelSLIM(pNtk, ¶ms);
|
||||
Abc_FrameReplaceCurrentNetwork( pAbc, pNtknew );
|
||||
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: elslim [-CDGIPRSTVWXZ <num>] [-cfhist]\n" );
|
||||
Abc_Print( -2, "\t Lut optimization using exact synthesis and the SAT-based local improvement method (SLIM)\n" );
|
||||
Abc_Print( -2, "\t-C <num> : approximate Boolean relations by only considering the frist C levels in the cone \n");
|
||||
Abc_Print( -2, "\t-D <num> : the delay mode to use [default = %d]\n", params.synthesis_approach );
|
||||
Abc_Print( -2, "\t-G <num> : the maximal number of fanins gates may use (at most 6) [default = %d]\n", params.gate_size );
|
||||
Abc_Print( -2, "\t-I <num> : the maximal number of iterations (0 = no limit) for the individual eSLIM runs [default = %d]\n", params.iterations );
|
||||
Abc_Print( -2, "\t-P <num> : the probability of expanding a node [default = %.2f]\n", params.expansion_probability );
|
||||
Abc_Print( -2, "\t-R <num> : the number of runs of eSLIM + Inprocessing [default = %d]\n", params.nruns );
|
||||
Abc_Print( -2, "\t-S <num> : the maximal size of considered subcircuits [default = %d]\n", params.subcircuit_max_size );
|
||||
Abc_Print( -2, "\t-T <num> : the timeout in seconds for the individual eSLIM runs [default = %d]\n", params.timeout );
|
||||
Abc_Print( -2, "\t-V <num> : the verbosity level [default = %d]\n", params.verbosity_level);
|
||||
Abc_Print( -2, "\t-W <num> <num> : Use m windows of size n [default = %d, %d]\n", params.nWindows, params.window_size);
|
||||
Abc_Print( -2, "\t-X <num> : the maximal number of additional gates that may be used for depth optimization [default = %d]\n", params.additional_gates);
|
||||
Abc_Print( -2, "\t-Z <num> : use a fixed seed\n", params.seed);
|
||||
Abc_Print( -2, "\t-c : toggle bias for selection of nodes on the crictical path\n");
|
||||
Abc_Print( -2, "\t-f : toggle forward expansion of root nodes\n");
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
Abc_Print( -2, "\t-i : toggle inprocessing\n");
|
||||
Abc_Print( -2, "\t-s : toggle fill subcircuits\n");
|
||||
Abc_Print( -2, "\t-t : toggle use taboo list\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;
|
||||
|
||||
}
|
||||
|
||||
int Abc_CommandAbc9CatBtor( Abc_Frame_t * pAbc, int argc, char ** argv ) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [areaEngine.cpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Implementation of area based SAT encoding.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "areaEngine.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
namespace eSLIM {
|
||||
|
||||
AreaEngine::AreaEngine(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: RelationSynthesiser(relation, subcir, subcir.nodes.size(), cfg, log) {
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
input_index_map[subcir.inputs[i]] = i;
|
||||
}
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
output_index_map[subcir.outputs[i]] = i;
|
||||
}
|
||||
if (subcir.forbidden_pairs.size() > 0) {
|
||||
setupCycleConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
eSLIMCirMan AreaEngine::synthesiseMinimumSizeCircuit(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
AreaEngine synth(relation, subcir, cfg, log);
|
||||
std::vector<bool> last_model;
|
||||
int replacement_size = 0;
|
||||
for (int i = synth.max_size; i>=0; i--) {
|
||||
double timeout = synth.getDynamicTimeout(i);
|
||||
int status = synth.checkSize(i, timeout);
|
||||
if (status == 10) {
|
||||
last_model = synth.solver.getModel();
|
||||
i = synth.getSizeFromActivationVars(last_model);
|
||||
replacement_size = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (last_model.empty()) {
|
||||
// no replacement found
|
||||
return eSLIMCirMan(0);
|
||||
} else {
|
||||
return synth.getReplacement(last_model, replacement_size);
|
||||
}
|
||||
}
|
||||
|
||||
int AreaEngine::checkSize(unsigned int size) {
|
||||
return checkSize(size, 0);
|
||||
}
|
||||
|
||||
int AreaEngine::checkSize(unsigned int size, double timeout) {
|
||||
std::vector<int> assumptions = getSizeAssumption(size);
|
||||
int status = timeout == 0 ? solver.solve(assumptions) : solver.solve(timeout, assumptions);
|
||||
logRun(status, size);
|
||||
return status;
|
||||
}
|
||||
|
||||
void AreaEngine::setupCycleConstraints() {
|
||||
assert (!subcir.forbidden_pairs.empty());
|
||||
setupConnectionVariables();
|
||||
if (subcir.forbidden_pairs.size() > 1) {
|
||||
connectionVariablesForCombinedCycles();
|
||||
}
|
||||
addCycleConstraints();
|
||||
}
|
||||
|
||||
void AreaEngine::addCycleConstraints() {
|
||||
for (auto const& [outp, inputs] : subcir.forbidden_pairs) {
|
||||
for (int inp : inputs) {
|
||||
int output_idx = output_index_map.at(outp);
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
solver.addClause({-gate_activation_variables[i], -gate_output_variables[i][output_idx], -connection_variables.at(inp)[i + subcir.inputs.size()]});
|
||||
}
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
solver.addClause({-gate_output_variables[max_size + i][output_idx], -connection_variables.at(inp)[i]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AreaEngine::setupConnectionVariables() {
|
||||
for (auto const& [out, inputs] : subcir.forbidden_pairs) {
|
||||
for (int in : inputs) {
|
||||
if (connection_variables.find(in) == connection_variables.end()) {
|
||||
connection_variables[in] = getNewVariableVector(max_size + subcir.inputs.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [input_var, connection_vars] : connection_variables) {
|
||||
int input_idx = input_index_map.at(input_var);
|
||||
// An input is connected to itself
|
||||
solver.addClause({connection_vars[input_idx]});
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
int activation_variable = gate_activation_variables[i];
|
||||
for (int j = 0; j < subcir.inputs.size(); j++) {
|
||||
// if gate i uses input j and input j is connected to input_var then also gate i is connected to input_var
|
||||
solver.addClause({-activation_variable, -selection_variables[i][j], -connection_vars[j], connection_vars[subcir.inputs.size() + i]});
|
||||
}
|
||||
for (int j = 0; j < i; j++) {
|
||||
// if gate i uses gate j and gate j is connected to input_var then also gate i is connected to input_var
|
||||
solver.addClause({-activation_variable, -selection_variables[i][subcir.inputs.size() + j], -connection_vars[subcir.inputs.size() + j], connection_vars[subcir.inputs.size() + i]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AreaEngine::connectionVariablesForCombinedCycles() {
|
||||
assert (subcir.forbidden_pairs.size() > 1);
|
||||
// Inputs are assigned to the outputs on which they depend
|
||||
std::unordered_map<int, std::unordered_set<int>> inputs_per_output;
|
||||
// Inputs in pairs
|
||||
std::unordered_set<int> inputs_in_pairs;
|
||||
for (auto const& [outp, inputs] : subcir.forbidden_pairs) {
|
||||
for (int inp : inputs) {
|
||||
if (inputs_per_output.find(outp) == inputs_per_output.end()) {
|
||||
inputs_per_output[outp] = {inp};
|
||||
} else {
|
||||
inputs_per_output[outp].insert(inp);
|
||||
}
|
||||
inputs_in_pairs.insert(inp);
|
||||
}
|
||||
}
|
||||
for (const auto& [ov, inp] : inputs_per_output) {
|
||||
for (int iv : inputs_in_pairs) {
|
||||
if (inp.find(iv) == inp.end()) {
|
||||
for (int k : inputs_per_output.at(ov)) {
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
// Input k depends on output ov.
|
||||
// If gate i represents output ov and gate i is connected to iv then also gate k is connected to iv.
|
||||
solver.addClause({-gate_activation_variables[i], -gate_output_variables[i][output_index_map.at(ov)],
|
||||
-connection_variables.at(iv)[subcir.inputs.size() + i], connection_variables.at(iv)[input_index_map.at(k)]});
|
||||
}
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
// Input k depends on output ov.
|
||||
// If input i represents output ov and input i is connected to iv then gate k shall be connected to iv too.
|
||||
solver.addClause({-gate_output_variables[max_size + i][output_index_map.at(ov)], -connection_variables.at(iv)[i], connection_variables.at(iv)[input_index_map.at(k)]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [areaEngine.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Implementation of area based SAT encoding.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__AREAENGINE_hpp
|
||||
#define ABC__OPT__ESLIM__AREAENGINE_hpp
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#include "relationSynthesiser.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class AreaEngine : private RelationSynthesiser {
|
||||
|
||||
public:
|
||||
static eSLIMCirMan synthesiseMinimumSizeCircuit(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<int, std::vector<int>> connection_variables;
|
||||
std::unordered_map<int,int> input_index_map;
|
||||
std::unordered_map<int,int> output_index_map;
|
||||
|
||||
AreaEngine(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
int checkSize(unsigned int size, double timeout);
|
||||
int checkSize(unsigned int size);
|
||||
|
||||
void setupCycleConstraints();
|
||||
void setupConnectionVariables();
|
||||
// If we have multiple cyclic pairs, different pairs may form form a cycle together
|
||||
// Assume we have two different pairs (x,y) and (a,b) in potential_cycles.
|
||||
// It can be the case that x is connected to b and a is connected to y.
|
||||
// To rule out cycles of this kind we make use of the following idea:
|
||||
// If (x,y) is in self.potential_cycles then there is a path from x to y that is not part of the current subcircuit.
|
||||
// Now if b is connected to x, this means that y is also connected to b.
|
||||
// Thus, all gates that use y as an input are connected to b.
|
||||
void connectionVariablesForCombinedCycles();
|
||||
void addCycleConstraints();
|
||||
};
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [cadicalSolver.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Interface for Cadical SAT solver.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__SATINTERFACE_h
|
||||
#define ABC__OPT__ESLIM__SATINTERFACE_h
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#include "sat/cadical/cadical.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class CadicalSolver {
|
||||
public:
|
||||
~CadicalSolver();
|
||||
void addClause(const std::vector<int>& clause);
|
||||
void addClause(std::vector<int>&& clause);
|
||||
void addCombinedClause(const std::vector<int>& cl1, const std::vector<int>& cl2, const std::vector<int>& cl3);
|
||||
void assume(const std::vector<int>& assumptions);
|
||||
int solve(double timeout, const std::vector<int>& assumptions);
|
||||
int solve(const std::vector<int>& assumptions);
|
||||
int solve(double timeout);
|
||||
int solve();
|
||||
std::vector<int> getFailed(const std::vector<int>& assumptions);
|
||||
bool isFailed(int lit);
|
||||
std::vector<int> getValues(const std::vector<int>& variables);
|
||||
bool getValue(int var);
|
||||
std::vector<bool> getModel();
|
||||
double getRunTime() const;
|
||||
|
||||
private:
|
||||
void assumeAll(const std::vector<int>& assumptions);
|
||||
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<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
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<double> elapsed_seconds = current_time - start;
|
||||
return elapsed_seconds.count() > max_runtime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline CadicalSolver::~CadicalSolver()=default;
|
||||
|
||||
inline void CadicalSolver::addClause(const std::vector<int>& clause) {
|
||||
for (auto& l: clause) {
|
||||
solver.add(l);
|
||||
}
|
||||
solver.add(0);
|
||||
}
|
||||
|
||||
inline void CadicalSolver::addClause(std::vector<int>&& clause) {
|
||||
for (auto& l: clause) {
|
||||
solver.add(l);
|
||||
}
|
||||
solver.add(0);
|
||||
}
|
||||
|
||||
inline void CadicalSolver::addCombinedClause(const std::vector<int>& cl1, const std::vector<int>& cl2, const std::vector<int>& cl3) {
|
||||
for (auto& l: cl1) {
|
||||
solver.add(l);
|
||||
}
|
||||
for (auto& l: cl2) {
|
||||
solver.add(l);
|
||||
}
|
||||
for (auto& l: cl3) {
|
||||
solver.add(l);
|
||||
}
|
||||
solver.add(0);
|
||||
}
|
||||
|
||||
inline void CadicalSolver::assume(const std::vector<int>& assumptions) {
|
||||
for (auto& l: assumptions) {
|
||||
solver.assume(l);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void CadicalSolver::assumeAll(const std::vector<int>& assumptions) {
|
||||
solver.reset_assumptions();
|
||||
assume(assumptions);
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve(double timeout, const std::vector<int>& assumptions) {
|
||||
assumeAll(assumptions);
|
||||
std::chrono::time_point<std::chrono::steady_clock> 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::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
if (solver.state() == CaDiCaL::INVALID) {
|
||||
std::cerr<<"Solver is in invalid state"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
solver.disconnect_terminator();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve(const std::vector<int>& assumptions) {
|
||||
assumeAll(assumptions);
|
||||
std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
|
||||
int status = solver.solve();
|
||||
last_runtime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve(double timeout) {
|
||||
std::chrono::time_point<std::chrono::steady_clock> 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::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
if (solver.state() == CaDiCaL::INVALID) {
|
||||
std::cerr<<"Solver is in invalid state"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
solver.disconnect_terminator();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve() {
|
||||
std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
|
||||
int status = solver.solve();
|
||||
last_runtime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline double CadicalSolver::getRunTime() const {
|
||||
return last_runtime;
|
||||
}
|
||||
|
||||
inline std::vector<int> CadicalSolver::getFailed(const std::vector<int>& assumptions) {
|
||||
std::vector<int> failed_literals;
|
||||
for (auto& l: assumptions) {
|
||||
if (solver.failed(l)) {
|
||||
failed_literals.push_back(l);
|
||||
}
|
||||
}
|
||||
return failed_literals;
|
||||
}
|
||||
|
||||
inline bool CadicalSolver::isFailed(int lit) {
|
||||
return solver.failed(lit);
|
||||
}
|
||||
|
||||
inline std::vector<int> CadicalSolver::getValues(const std::vector<int>& variables) {
|
||||
std::vector<int> assignment;
|
||||
for (auto& v: variables) {
|
||||
assignment.push_back(val(v));
|
||||
}
|
||||
return assignment;
|
||||
}
|
||||
|
||||
inline bool CadicalSolver::getValue(int var) {
|
||||
return val(var) > 0;
|
||||
}
|
||||
|
||||
inline std::vector<bool> CadicalSolver::getModel() {
|
||||
std::vector<bool> assignment;
|
||||
assignment.push_back(false);
|
||||
for (int v = 1; v <= solver.vars(); v++) {
|
||||
assignment.push_back(val(v) > 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [delayEngine.cpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Implementation of delay based SAT encoding.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "delayEngine.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
namespace eSLIM {
|
||||
|
||||
DelayEngine::DelayEngine( const Relation& relation, const Subcircuit& subcir, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: RelationSynthesiser(relation, subcir, max_size, cfg, log) {
|
||||
assert (subcir.forbidden_pairs.empty());
|
||||
symmetry_selector = getNewVariable();
|
||||
symmetry_selector_assignment = symmetry_selector;
|
||||
std::set<int> unique_ats_set (subcir.arrival_times.begin(), subcir.arrival_times.end());
|
||||
unique_arrival_times = std::vector<int> (unique_ats_set.begin(), unique_ats_set.end());
|
||||
for (int i : subcir.arrival_times) {
|
||||
auto it = unique_ats_set.find(i);
|
||||
int idx = std::distance(unique_ats_set.begin(), it);
|
||||
inputid2uniqueid.push_back(idx);
|
||||
}
|
||||
setupVariables();
|
||||
constrainDelayVariables();
|
||||
setupDelayConstraints();
|
||||
max_delay = delay_selectors.begin()->first;
|
||||
}
|
||||
|
||||
// do not enfore activation variables -> a minimum nof gates might forbid a realization with a certain depth.
|
||||
eSLIMCirMan DelayEngine::synthesizeMinimumDelayCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
DelayEngine synth(relation, subcir, max_size, cfg, log);
|
||||
std::vector<bool> last_model = synth.reduceDelay(max_size, delay);
|
||||
if (last_model.empty()) {
|
||||
// no replacement found
|
||||
return eSLIMCirMan(0);
|
||||
} else {
|
||||
int replacement_size = synth.getSizeFromActivationVars(last_model);
|
||||
return synth.getReplacement(last_model, replacement_size);
|
||||
}
|
||||
}
|
||||
|
||||
eSLIMCirMan DelayEngine::synthesizeMinimumDelayAreaCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
DelayEngine synth(relation, subcir, max_size, cfg, log);
|
||||
std::vector<bool> last_model = synth.reduceDelay(max_size, delay);
|
||||
if (last_model.empty()) {
|
||||
// We could not even find a replacement with the same delay as the original circuit (timeout)
|
||||
// Hence, it is unlikely that we find a circuit that has the same delay but fewer gates
|
||||
return eSLIMCirMan(0);
|
||||
}
|
||||
int replacement_size = synth.getSizeFromActivationVars(last_model);
|
||||
int replacement_delay = synth.getDelayFromDelayVariables(last_model);
|
||||
std::vector<bool> model = synth.reduceArea(replacement_delay, replacement_size - 1);
|
||||
if (model.size() > 0) {
|
||||
replacement_size = synth.getSizeFromActivationVars(model);
|
||||
std::swap(last_model, model);
|
||||
}
|
||||
return synth.getReplacement(last_model, replacement_size);
|
||||
}
|
||||
|
||||
eSLIMCirMan DelayEngine::synthesizeMinimumAreaDelayCircuit(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
DelayEngine synth(relation, subcir, subcir.nodes.size(), cfg, log);
|
||||
std::vector<bool> last_model = synth.reduceArea(synth.max_delay, subcir.nodes.size());
|
||||
if (last_model.empty()) {
|
||||
// We could not even find a replacement with the same area as the original circuit (timeout)
|
||||
// Hence, it is unlikely that we find a circuit that has the same area and a causes a smaller delay
|
||||
return eSLIMCirMan(0);
|
||||
}
|
||||
int replacement_size = synth.getSizeFromActivationVars(last_model);
|
||||
int replacement_delay = synth.getDelayFromDelayVariables(last_model);
|
||||
assert (replacement_delay > 0);
|
||||
std::vector<bool> model = synth.reduceDelay(replacement_size, replacement_delay - 1);
|
||||
if (model.size() > 0) {
|
||||
replacement_size = synth.getSizeFromActivationVars(model);
|
||||
std::swap(last_model, model);
|
||||
}
|
||||
return synth.getReplacement(last_model, replacement_size);
|
||||
}
|
||||
|
||||
eSLIMCirMan DelayEngine::synthesizeMinimumAreaDelayConstraintCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
DelayEngine synth(relation, subcir, subcir.nodes.size(), cfg, log);
|
||||
std::vector<bool> last_model = synth.reduceArea(delay, subcir.nodes.size());
|
||||
if (last_model.empty()) {
|
||||
return eSLIMCirMan(0);
|
||||
} else {
|
||||
int replacement_size = synth.getSizeFromActivationVars(last_model);
|
||||
return synth.getReplacement(last_model, replacement_size);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<bool> DelayEngine::reduceArea(unsigned int max_delay, unsigned int initial_area) {
|
||||
std::vector<bool> last_model;
|
||||
for (int i = initial_area; i>=0; i--) {
|
||||
double timeout = getDynamicTimeout(i);
|
||||
int status = existsReplacement(i, max_delay, timeout);
|
||||
if (status == 10) {
|
||||
last_model = solver.getModel();
|
||||
i = getSizeFromActivationVars(last_model); // it is possible that more than one gate is reduced in an iteration
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return last_model;
|
||||
}
|
||||
|
||||
std::vector<bool> DelayEngine::reduceDelay(unsigned int max_size, unsigned int initial_delay) {
|
||||
assert (delay_selectors.find(initial_delay) != delay_selectors.end());
|
||||
std::vector<bool> last_model;
|
||||
for( auto it = delay_selectors.find(initial_delay); it != delay_selectors.end(); ++it ) {
|
||||
int d = it->first;
|
||||
double timeout = getDynamicTimeout(max_size);
|
||||
int status = existsReplacement(max_size, d, timeout);
|
||||
if (status == 10) {
|
||||
last_model = solver.getModel();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return last_model;
|
||||
}
|
||||
|
||||
std::vector<int> DelayEngine::getAssumptions(unsigned int delay) {
|
||||
std::vector<int> assumptions;
|
||||
for (auto const& [d, ds] : delay_selectors) {
|
||||
if (d > delay) {
|
||||
assumptions.push_back(-ds);
|
||||
}
|
||||
}
|
||||
return assumptions;
|
||||
}
|
||||
|
||||
std::vector<int> DelayEngine::getAssumptions(unsigned int size, unsigned int delay) {
|
||||
std::vector<int> assumptions = getAssumptions(delay);
|
||||
std::vector<int> area_assumptions = getSizeAssumption(size);
|
||||
assumptions.insert(assumptions.end(), area_assumptions.begin(), area_assumptions.end());
|
||||
return assumptions;
|
||||
}
|
||||
|
||||
unsigned int DelayEngine::getDelayFromDelayVariables(const std::vector<bool>& model) {
|
||||
unsigned int delay = 0;
|
||||
for (auto const& [d, dvars] : delays2delay_variables) {
|
||||
for (int v : dvars) {
|
||||
if (model[v]) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
int DelayEngine::existsReplacement(unsigned int delay, double timeout) {
|
||||
std::vector<int> assumptions = getAssumptions(delay);
|
||||
int status = timeout == 0 ? solver.solve(assumptions) : solver.solve(timeout, assumptions);
|
||||
unsigned int size = status == 10 ? getSizeFromActivationVars() : max_size;
|
||||
logRun(status, size);
|
||||
return status;
|
||||
}
|
||||
|
||||
int DelayEngine::existsReplacement(unsigned int size, unsigned int delay, double timeout) {
|
||||
std::vector<int> assumptions = getAssumptions(size, delay);
|
||||
int status = timeout == 0 ? solver.solve(assumptions) : solver.solve(timeout, assumptions);
|
||||
logRun(status, size);
|
||||
return status;
|
||||
}
|
||||
|
||||
void DelayEngine::setupVariables() {
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
std::vector<std::vector<int>> dvars;
|
||||
for (int j = 0; j < unique_arrival_times.size(); j++) {
|
||||
dvars.push_back(getNewVariableVector(i + 1));
|
||||
}
|
||||
delay_variables.push_back(dvars);
|
||||
}
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
std::vector<std::vector<int>> dvars;
|
||||
for (int j = 0; j < unique_arrival_times.size(); j++) {
|
||||
dvars.push_back(getNewVariableVector(max_size + 1));
|
||||
}
|
||||
output_delays.push_back(dvars);
|
||||
}
|
||||
}
|
||||
|
||||
int DelayEngine::getDelaySelector(int delay) {
|
||||
if (delay_selectors.find(delay) == delay_selectors.end()) {
|
||||
delay_selectors[delay] = getNewVariable();
|
||||
}
|
||||
return delay_selectors[delay];
|
||||
}
|
||||
|
||||
|
||||
void DelayEngine::constrainDelayVariables() {
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
int activation_variable = gate_activation_variables[i];
|
||||
for (int j = 0; j < subcir.inputs.size(); j++) {
|
||||
solver.addClause({-activation_variable, -selection_variables[i][j], delay_variables[i][inputid2uniqueid[j]][0]});
|
||||
}
|
||||
for (int j = 0; j < unique_arrival_times.size(); j++) {
|
||||
for (int k = 0; k < i; k++) {
|
||||
int node_id = subcir.inputs.size() + k;
|
||||
for (int l = 0; l <= k; l++) {
|
||||
solver.addClause({-activation_variable, -selection_variables[i][node_id], -delay_variables[k][j][l], delay_variables[i][j][l+1]});
|
||||
}
|
||||
solver.addClause({-activation_variable, -delay_variables[i][j][k+1], delay_variables[i][j][k]});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
for (int j = 0; j < subcir.inputs.size(); j++) {
|
||||
solver.addClause({-gate_output_variables[max_size + j][i], output_delays[i][inputid2uniqueid[j]][0]});
|
||||
}
|
||||
for (int j = 0; j < unique_arrival_times.size(); j++) {
|
||||
for (int k = 0; k < max_size; k++) {
|
||||
solver.addClause({-output_delays[i][j][k+1], output_delays[i][j][k]});
|
||||
for (int l = 0; l <= k; l++) {
|
||||
solver.addClause({-gate_output_variables[k][i], -delay_variables[k][j][l], output_delays[i][j][l+1]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DelayEngine::setupDelayConstraints() {
|
||||
for (int i = 0; i < unique_arrival_times.size(); i++) {
|
||||
for (int o = 0; o < subcir.outputs.size(); o++) {
|
||||
for (int d = 0; d <= max_size; d++) {
|
||||
int delay = unique_arrival_times[i] + subcir.remaining_times[o] + d;
|
||||
int ds = getDelaySelector(delay);
|
||||
solver.addClause({ds, -output_delays[o][i][d]});
|
||||
|
||||
delays2delay_variables[delay].push_back(output_delays[o][i][d]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [delayEngine.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Implementation of delay based SAT encoding.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__DELAYENGINE_hpp
|
||||
#define ABC__OPT__ESLIM__DELAYENGINE_hpp
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#include "relationSynthesiser.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class DelayEngine : public RelationSynthesiser {
|
||||
|
||||
public:
|
||||
// Find a replacement with at most max_size gates that yields minimum delay
|
||||
static eSLIMCirMan synthesizeMinimumDelayCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
// Find a replacement with at most max_size gates that yields minimum delay. Among these circuits find one of minimum size
|
||||
static eSLIMCirMan synthesizeMinimumDelayAreaCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
// First minimize area, then minimize delay
|
||||
static eSLIMCirMan synthesizeMinimumAreaDelayCircuit(const Relation& relation, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
// Find a smaller replacement that must not increase delay
|
||||
static eSLIMCirMan synthesizeMinimumAreaDelayConstraintCircuit(const Relation& relation, const Subcircuit& subcir, unsigned int delay, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<int> unique_arrival_times;
|
||||
std::vector<int> inputid2uniqueid;
|
||||
unsigned int max_delay;
|
||||
int symmetry_selector;
|
||||
int symmetry_selector_assignment;
|
||||
// Indicate the length of the longest paths from inputs to gates
|
||||
std::vector<std::vector<std::vector<int>>> delay_variables;
|
||||
std::vector<std::vector<std::vector<int>>> output_delays;
|
||||
|
||||
std::map<int, int, std::greater<int>> delay_selectors;
|
||||
std::map<int, std::vector<int>, std::greater<int>> delays2delay_variables;
|
||||
|
||||
DelayEngine(const Relation& relation, const Subcircuit& subcir, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
int existsReplacement(unsigned int size, unsigned int delay, double timeout);
|
||||
int existsReplacement(unsigned int delay, double timeout);
|
||||
std::vector<int> getAssumptions(unsigned int delay);
|
||||
std::vector<int> getAssumptions(unsigned int size, unsigned int delay);
|
||||
void setupVariables();
|
||||
|
||||
unsigned int getDelayFromDelayVariables(const std::vector<bool>& model);
|
||||
|
||||
std::vector<bool> reduceArea(unsigned int max_delay, unsigned int initial_area);
|
||||
std::vector<bool> reduceDelay(unsigned int max_size, unsigned int initial_delay);
|
||||
|
||||
int getDelaySelector(int delay);
|
||||
void setupDelayConstraints();
|
||||
void constrainDelayVariables();
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -12,204 +12,611 @@
|
|||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
#include "utils.hpp"
|
||||
#include "eSLIMMan.hpp"
|
||||
#include "relationGeneration.hpp"
|
||||
#include "selectionStrategy.hpp"
|
||||
#include "selectionStrategies.hpp"
|
||||
#include "windowMan.hpp"
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
#include "opt/mfs/mfs.h"
|
||||
#include "base/main/main.h"
|
||||
|
||||
#include "eSLIM.h"
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "synthesisEngines.hpp"
|
||||
#include "selectionStrategies.hpp"
|
||||
|
||||
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 fChoices, int fVerbose );
|
||||
int Abc_NtkMfs( Abc_Ntk_t * pNtk, Mfs_Par_t * pPars );
|
||||
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.subcircuit_max_size = params->subcircuit_max_size;
|
||||
config.additional_gates = params->additional_gates;
|
||||
config.strash_intervall = params->strash_intervall;
|
||||
config.nselection_trials = params->nselection_trials;
|
||||
config.seed = params->seed;
|
||||
config.verbosity_level = params->verbosity_level;
|
||||
config.expansion_probability = params->expansion_probability;
|
||||
config.approximate_relation = params->approximate_relation;
|
||||
config.relation_tfo_bound = params->relation_tfo_bound;
|
||||
config.generate_relation_with_tfi_limit = params->generate_relation_with_tfi_limit;
|
||||
config.relation_tfi_bound = params->relation_tfi_bound;
|
||||
config.nwindows = params->nWindows;
|
||||
config.window_size = params->window_size;
|
||||
|
||||
config.aig = params->aig;
|
||||
config.gate_size = params->gate_size;
|
||||
|
||||
if (params->use_taboo_list) {
|
||||
config.apply_strash = false;
|
||||
}
|
||||
|
||||
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->apply_inprocessing = 1;
|
||||
params->timeout = 1620;
|
||||
params->timeout_inprocessing = 180;
|
||||
params->synthesis_approach = 0;
|
||||
params->seed = 0;
|
||||
params->verbosity_level = 1;
|
||||
params->use_taboo_list = 0;
|
||||
params->forward_search = 0;
|
||||
|
||||
params->nWindows = 0;
|
||||
params->window_size = 500;
|
||||
|
||||
params->criticial_path_selection_bias = 0;
|
||||
|
||||
params->timeout = 1800;
|
||||
params->iterations = 0;
|
||||
params->subcircuit_size_bound = 6;
|
||||
params->subcircuit_max_size = 6;
|
||||
params->additional_gates = 0;
|
||||
params->strash_intervall = 100;
|
||||
params->nselection_trials = 100;
|
||||
params->nruns = 1;
|
||||
params->mode = 0;
|
||||
params->seed = 0;
|
||||
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) {
|
||||
switch (approach) {
|
||||
case 0 :
|
||||
if (allow_forbidden_pairs) {
|
||||
return eSLIM::eSLIM_Man<eSLIM::CadicalEngine, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSFP>::applyeSLIM(pGia, params, log);
|
||||
} else {
|
||||
return eSLIM::eSLIM_Man<eSLIM::CadicalEngine, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSnoFP>::applyeSLIM(pGia, params, log);
|
||||
};
|
||||
case 1:
|
||||
if (allow_forbidden_pairs) {
|
||||
return eSLIM::eSLIM_Man<eSLIM::KissatOneShot, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSFP>::applyeSLIM(pGia, params, log);
|
||||
} else {
|
||||
return eSLIM::eSLIM_Man<eSLIM::KissatOneShot, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSnoFP>::applyeSLIM(pGia, params, log);
|
||||
};
|
||||
case 2:
|
||||
if (allow_forbidden_pairs) {
|
||||
return eSLIM::eSLIM_Man<eSLIM::KissatCmdOneShot, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSFP>::applyeSLIM(pGia, params, log);
|
||||
} else {
|
||||
return eSLIM::eSLIM_Man<eSLIM::KissatCmdOneShot, eSLIM::RelationGeneratorABC, eSLIM::randomizedBFSnoFP>::applyeSLIM(pGia, params, log);
|
||||
};
|
||||
default:
|
||||
std::cerr << "eSLIM -- Invalid mode given\n";
|
||||
assert (false && "Invalid approach selected");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
params->expansion_probability = 0.5;
|
||||
params->approximate_relation = 0;
|
||||
params->relation_tfo_bound = 0;
|
||||
params->generate_relation_with_tfi_limit = 0;
|
||||
params->relation_tfi_bound = 0;
|
||||
|
||||
params->aig = 1;
|
||||
params->gate_size = 2;
|
||||
}
|
||||
|
||||
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, 0);
|
||||
if ( Gia_ManAndNum(pGia) > Gia_ManAndNum(tmp) ) {
|
||||
Gia_ManStop( pGia );
|
||||
pGia = tmp;
|
||||
} else {
|
||||
namespace eSLIM {
|
||||
|
||||
class DeepsynInprocessor {
|
||||
public:
|
||||
DeepsynInprocessor(eSLIMConfig& config);
|
||||
void setTimeout(int timeout) {this->timeout = timeout;}
|
||||
void runInprocessing(eSLIMCirMan& es_man);
|
||||
private:
|
||||
eSLIMConfig& config;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
class MfsInprocessor {
|
||||
public:
|
||||
MfsInprocessor(eSLIMConfig& config) {}
|
||||
void runInprocessing(eSLIMCirMan& es_man);
|
||||
};
|
||||
|
||||
class EmptyInprocessor {
|
||||
public:
|
||||
EmptyInprocessor(eSLIMConfig& config) {}
|
||||
void runInprocessing(eSLIMCirMan& es_man) {}
|
||||
};
|
||||
|
||||
template <bool IncreaseSize>
|
||||
class DelayInprocessor {
|
||||
public:
|
||||
DelayInprocessor(eSLIMConfig& config);
|
||||
void setTimeout(int timeout) {this->timeout = timeout;}
|
||||
void runInprocessing(eSLIMCirMan& es_man);
|
||||
private:
|
||||
eSLIMConfig& config;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
class Resyn2Inprocessor {
|
||||
public:
|
||||
Resyn2Inprocessor(eSLIMConfig& config);
|
||||
void runInprocessing(eSLIMCirMan& es_man);
|
||||
private:
|
||||
// eSLIMConfig& config;
|
||||
};
|
||||
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
class eSLIMRun {
|
||||
|
||||
public:
|
||||
static Gia_Man_t* runeSLIM(Gia_Man_t* cir, const eSLIM_ParamStruct* params);
|
||||
static Abc_Ntk_t * runeSLIM(Abc_Ntk_t * cir, const eSLIM_ParamStruct* params);
|
||||
static Abc_Ntk_t * runeSLIMCells(Abc_Ntk_t * cir, const eSLIM_ParamStruct* params);
|
||||
|
||||
private:
|
||||
eSLIMCirMan es_man;
|
||||
eSLIMConfig config;
|
||||
eSLIMLog log;
|
||||
Inprocessor inprocessor;
|
||||
|
||||
int initial_area;
|
||||
int initial_delay;
|
||||
|
||||
int area_change_eslim = 0;
|
||||
int area_change_inprocessing = 0;
|
||||
|
||||
int delay_change_eslim = 0;
|
||||
int delay_change_inprocessing = 0;
|
||||
|
||||
int nruns = 0;
|
||||
|
||||
eSLIMRun(Gia_Man_t* cir, const eSLIM_ParamStruct* params);
|
||||
eSLIMRun(Abc_Ntk_t* cir, const eSLIM_ParamStruct* params, bool simplify);
|
||||
|
||||
void setUpInprocessor();
|
||||
void runInprocessing();
|
||||
|
||||
void printSettings();
|
||||
void printLog();
|
||||
|
||||
void run();
|
||||
};
|
||||
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
eSLIMRun<Approach, Inprocessor>::eSLIMRun(Abc_Ntk_t* cir, const eSLIM_ParamStruct* params, bool simplify_circuit)
|
||||
: es_man(cir, simplify_circuit), config(getCfg(params)), log(params->subcircuit_max_size), inprocessor(config) {
|
||||
nruns = params->nruns;
|
||||
config.aig = false;
|
||||
config.apply_strash = false;
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
eSLIMRun<Approach, Inprocessor>::eSLIMRun(Gia_Man_t* cir, const eSLIM_ParamStruct* params)
|
||||
: es_man(cir), config(getCfg(params)), log(params->subcircuit_max_size), inprocessor(config) {
|
||||
nruns = params->nruns;
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
Gia_Man_t* eSLIMRun<Approach, Inprocessor>::runeSLIM(Gia_Man_t* cir, const eSLIM_ParamStruct* params) {
|
||||
|
||||
eSLIMRun<Approach, Inprocessor> eslim_run(cir, params);
|
||||
// It seems like the variables are freed by abc during preprocessing. Thus,we copy them
|
||||
char* name = Abc_UtilStrsav( cir->pName );
|
||||
char* spec = Abc_UtilStrsav( cir->pSpec );
|
||||
eslim_run.run();
|
||||
Gia_Man_t* gia_res = eslim_run.es_man.eSLIMCirManToGia();
|
||||
gia_res->pName = name;
|
||||
gia_res->pSpec = spec;
|
||||
return gia_res;
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
Abc_Ntk_t* eSLIMRun<Approach, Inprocessor>::runeSLIM(Abc_Ntk_t* cir, const eSLIM_ParamStruct* params) {
|
||||
bool simplify_circuit = true;
|
||||
eSLIMRun<Approach, Inprocessor> eslim_run(cir, params, simplify_circuit);
|
||||
eslim_run.config.aig = false;
|
||||
eslim_run.config.apply_strash = false;
|
||||
eslim_run.run();
|
||||
Abc_Ntk_t* ntk_res = eslim_run.es_man.eSLIMCirManToNtk();
|
||||
ntk_res->pName = Extra_UtilStrsav(cir->pName);
|
||||
ntk_res->pSpec = Extra_UtilStrsav(cir->pSpec);
|
||||
return ntk_res;
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
Abc_Ntk_t * eSLIMRun<Approach, Inprocessor>::runeSLIMCells(Abc_Ntk_t * cir, const eSLIM_ParamStruct* params) {
|
||||
bool simplify_circuit = false;
|
||||
eSLIMRun<Approach, Inprocessor> eslim_run(cir, params, simplify_circuit);
|
||||
eslim_run.config.aig = false;
|
||||
eslim_run.config.apply_strash = false;
|
||||
eslim_run.run();
|
||||
Abc_Ntk_t* ntk_res = eslim_run.es_man.eSLIMCirManToMappedNtk();
|
||||
if (!ntk_res) {
|
||||
return ntk_res;
|
||||
}
|
||||
ntk_res->pName = Extra_UtilStrsav(cir->pName);
|
||||
ntk_res->pSpec = Extra_UtilStrsav(cir->pSpec);
|
||||
return ntk_res;
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
void eSLIMRun<Approach, Inprocessor>::run() {
|
||||
if constexpr ( std::is_same_v<DeepsynInprocessor, Inprocessor> || std::is_same_v<DelayInprocessor<true>, Inprocessor> || std::is_same_v<DelayInprocessor<false>, Inprocessor> ) {
|
||||
int time_out_inprocessing;
|
||||
if constexpr ( std::is_same_v<DeepsynInprocessor, Inprocessor> ) {
|
||||
time_out_inprocessing = config.timeout * 0.1;
|
||||
} else {
|
||||
time_out_inprocessing = config.timeout * 0.02;
|
||||
}
|
||||
config.timeout -= time_out_inprocessing;
|
||||
inprocessor.setTimeout(time_out_inprocessing);
|
||||
}
|
||||
|
||||
initial_area = es_man.getNofGates();
|
||||
initial_delay = es_man.getDepth();
|
||||
printSettings();
|
||||
for (int i = 0; i < nruns; i++) {
|
||||
|
||||
int size_iteration_start = es_man.getNofGates();
|
||||
int delay_iteration_start = es_man.getDepth();
|
||||
if (config.verbosity_level > 0) {
|
||||
std::cout << "Start eslim run " << i + 1 << "\n";
|
||||
}
|
||||
Approach::applyeSLIM(es_man, config, log);
|
||||
int size_eslim = es_man.getNofGates();
|
||||
int delay_eslim = es_man.getDepth();
|
||||
area_change_eslim += size_eslim - size_iteration_start;
|
||||
delay_change_eslim += delay_eslim - delay_iteration_start;
|
||||
if (config.verbosity_level > 0) {
|
||||
std::cout << "eslim -- size: " << size_eslim << " delay: " << delay_eslim << "\n";
|
||||
}
|
||||
runInprocessing();
|
||||
if constexpr ( !std::is_same_v<EmptyInprocessor, Inprocessor> ) {
|
||||
int size_inprocessing = es_man.getNofGates();
|
||||
int delay_inprocessing = es_man.getDepth();
|
||||
area_change_inprocessing += size_inprocessing - size_eslim;
|
||||
delay_change_inprocessing += delay_inprocessing - delay_eslim;
|
||||
if (config.verbosity_level > 0) {
|
||||
std::cout << "inprocessing -- size: " << size_inprocessing << " delay: " << delay_inprocessing << "\n";
|
||||
}
|
||||
}
|
||||
if (config.fix_seed) {
|
||||
config.seed++;
|
||||
}
|
||||
}
|
||||
printLog();
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
void eSLIMRun<Approach, Inprocessor>::printSettings() {
|
||||
std::cout << "Apply eSLIM (timeout: " << config.timeout << ") ";
|
||||
std::cout << nruns << " times.\n";
|
||||
if constexpr ( !std::is_same_v<EmptyInprocessor, Inprocessor> ) {
|
||||
std::cout << "Apply inprocessing\n";
|
||||
}
|
||||
if (config.iterations > 0) {
|
||||
std::cout << "Stop eSLIM runs after " << config.iterations << " iterations.\n";
|
||||
}
|
||||
std::cout << "Consider subcircuits with up to " << config.subcircuit_max_size << " gates.\n";
|
||||
printf("When expanding subcircuits, select gates with a probability of %.2f %%.\n", 100 * config.expansion_probability);
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
void eSLIMRun<Approach, Inprocessor>::printLog() {
|
||||
if (config.verbosity_level > 0) {
|
||||
int size = es_man.getNofGates();
|
||||
int delay = es_man.getDepth();
|
||||
int total_area_change = area_change_eslim + area_change_inprocessing;
|
||||
int total_delay_change = delay_change_eslim + delay_change_inprocessing;
|
||||
std::cout << "Final size: " << size << " change: " << total_area_change << "\n";
|
||||
std::cout << "Final depth: " << delay << " change: " << total_delay_change << "\n";
|
||||
|
||||
|
||||
if constexpr ( !std::is_same_v<EmptyInprocessor, Inprocessor> ) {
|
||||
|
||||
if (area_change_eslim <= 0) {
|
||||
std::cout << "#Gates reduced by eSLIM: " << -area_change_eslim << "\n";
|
||||
} else {
|
||||
std::cout << "#Gates introduced by eSLIM: " << area_change_eslim << "\n";
|
||||
}
|
||||
if (area_change_inprocessing <= 0) {
|
||||
std::cout << "#Gates reduced by inprocessing: " << -area_change_inprocessing << "\n";
|
||||
} else {
|
||||
std::cout << "#Gates introduced by inprocessing: " << area_change_inprocessing << "\n";
|
||||
}
|
||||
if (delay_change_eslim <= 0) {
|
||||
std::cout << "Delay reduction eSLIM: " << -delay_change_eslim << "\n";
|
||||
} else {
|
||||
std::cout << "Delay increase eSLIM: " << delay_change_eslim << "\n";
|
||||
}
|
||||
if (delay_change_inprocessing <= 0) {
|
||||
std::cout << "Delay reduction inprocessing: " << -delay_change_inprocessing << "\n";
|
||||
} else {
|
||||
std::cout << "Delay increase inprocessing: " << delay_change_inprocessing << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (config.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";
|
||||
printf("Relation generation: #SAT-calls: %lu, Total SAT-time: %.2f sec, Max SAT-time: %.4f sec, Avg. SAT-time: %.4f sec\n",
|
||||
log.nof_sat_calls_relation_generation, log.cummulative_sat_runtime_relation_generation, log.max_sat_runtime_relation_generation,
|
||||
log.cummulative_sat_runtime_relation_generation/log.nof_sat_calls_relation_generation);
|
||||
printf("Synthesis: #SAT-calls: %lu, Total SAT-time: %.2f sec, Max SAT-time: %.4f sec, Avg. SAT-time: %.4f sec\n",
|
||||
log.nof_sat_calls_synthesis, log.cummulative_sat_runtime_synthesis / 1000, log.max_sat_runtime_synthesis / 1000,
|
||||
log.cummulative_sat_runtime_synthesis / (log.nof_sat_calls_synthesis*1000));
|
||||
}
|
||||
if (config.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;
|
||||
std::cout << " - avg. relation time: ";
|
||||
if (log.nof_relation_generations_per_size[i] == 0) {
|
||||
std::cout << "-";
|
||||
} else {
|
||||
printf("%.2f sec", static_cast<double>(log.cummulative_relation_generation_times_per_size[i]) / (log.nof_relation_generations_per_size[i]));
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
for (int i = 0; i < log.nof_sat_calls_per_size.size(); i++) {
|
||||
std::cout << "#gates: " << i << " - avg. sat time: ";
|
||||
if (log.nof_sat_calls_per_size[i] == 0) {
|
||||
std::cout << "-";
|
||||
} else {
|
||||
printf("%.2f sec", static_cast<double>(log.cummulative_sat_runtimes_per_size[i]) / (1000 * log.nof_sat_calls_per_size[i]));
|
||||
}
|
||||
std::cout << " / avg. unsat time: ";
|
||||
if (log.nof_unsat_calls_per_size[i] == 0) {
|
||||
std::cout << "-";
|
||||
} else {
|
||||
printf("%.2f sec", static_cast<double>(log.cummulative_unsat_runtimes_per_size[i]) / (1000 * log.nof_unsat_calls_per_size[i]));
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
void eSLIMRun<Approach, Inprocessor>::runInprocessing() {
|
||||
inprocessor.runInprocessing(es_man);
|
||||
}
|
||||
|
||||
template <typename Approach, typename Inprocessor>
|
||||
void setUpInprocessor();
|
||||
|
||||
DeepsynInprocessor::DeepsynInprocessor(eSLIMConfig& config)
|
||||
: config(config) {
|
||||
}
|
||||
|
||||
void DeepsynInprocessor::runInprocessing(eSLIMCirMan& es_man) {
|
||||
Gia_Man_t* pGia = es_man.eSLIMCirManToGia();
|
||||
Gia_Man_t* tmp = Gia_ManDeepSyn( pGia, 1, ABC_INFINITY, timeout, 0, config.seed , 0, 0, 0);
|
||||
if ( Gia_ManAndNum(pGia) > Gia_ManAndNum(tmp) ) {
|
||||
es_man = eSLIMCirMan(tmp);
|
||||
}
|
||||
Gia_ManStop( tmp );
|
||||
Gia_ManStop( pGia );
|
||||
}
|
||||
|
||||
void MfsInprocessor::runInprocessing(eSLIMCirMan& es_man) {
|
||||
Abc_Ntk_t* pNtk = es_man.eSLIMCirManToNtk();
|
||||
int nnodes = Abc_NtkNodeNum(pNtk);
|
||||
Mfs_Par_t Pars, * pPars = &Pars;
|
||||
Abc_NtkMfsParsDefault( pPars );
|
||||
if ( Abc_NtkMfs( pNtk, pPars ) ) {
|
||||
Abc_NtkToSop( pNtk, -1, ABC_INFINITY );
|
||||
if (Abc_NtkNodeNum(pNtk) <= nnodes) {
|
||||
es_man = eSLIMCirMan(pNtk, true);
|
||||
}
|
||||
}
|
||||
Abc_NtkDelete(pNtk);
|
||||
}
|
||||
|
||||
template <bool IncreaseSize>
|
||||
DelayInprocessor<IncreaseSize>::DelayInprocessor(eSLIMConfig& config)
|
||||
: config(config) {
|
||||
}
|
||||
|
||||
template <bool IncreaseSize>
|
||||
void DelayInprocessor<IncreaseSize>::runInprocessing(eSLIMCirMan& es_man) {
|
||||
abctime clkStart = Abc_Clock();
|
||||
abctime nTimeToStop = clkStart + timeout * CLOCKS_PER_SEC;
|
||||
Gia_Man_t* pGia = es_man.eSLIMCirManToGia();
|
||||
int nand = Gia_ManAndNum(pGia);
|
||||
int nlevel = Gia_ManLevelNum(pGia);
|
||||
char * resyn2 = "balance; rewrite; rewrite -z; balance; rewrite -z; balance";
|
||||
char Command[2000];
|
||||
sprintf( Command, "strash; if -g -K 6; %s; if -K 6", resyn2 );
|
||||
bool reset_batch_mode = false ;
|
||||
if ( !Abc_FrameIsBatchMode() ) {
|
||||
reset_batch_mode = true;
|
||||
Abc_FrameSetBatchMode( 1 );
|
||||
}
|
||||
Abc_FrameUpdateGia( Abc_FrameGetGlobalFrame(), pGia );
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), "&put") ) {
|
||||
return;
|
||||
}
|
||||
while (Abc_Clock() <= nTimeToStop) {
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), Command) ) {
|
||||
Abc_Print( 1, "Something did not work out with the command \"%s\".\n", Command );
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), "&get") ) {
|
||||
return;
|
||||
}
|
||||
if (reset_batch_mode) {
|
||||
Abc_FrameSetBatchMode( 0 );
|
||||
}
|
||||
Gia_Man_t* tmp = Abc_FrameReadGia(Abc_FrameGetGlobalFrame());
|
||||
if constexpr (!IncreaseSize) {
|
||||
if (Gia_ManAndNum(tmp) > nand) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Gia_ManLevelNum(tmp) <= nlevel) {
|
||||
es_man = eSLIMCirMan(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
Resyn2Inprocessor::Resyn2Inprocessor(eSLIMConfig& config)
|
||||
// : config(config)
|
||||
{
|
||||
}
|
||||
|
||||
void Resyn2Inprocessor::runInprocessing(eSLIMCirMan& es_man) {
|
||||
Gia_Man_t* pGia = es_man.eSLIMCirManToGia();
|
||||
int nand = Gia_ManAndNum(pGia);
|
||||
int nlevel = Gia_ManLevelNum(pGia);
|
||||
char * resyn2 = "balance; rewrite; rewrite -z; balance; rewrite -z; balance";
|
||||
bool reset_batch_mode = false ;
|
||||
if ( !Abc_FrameIsBatchMode() ) {
|
||||
reset_batch_mode = true;
|
||||
Abc_FrameSetBatchMode( 1 );
|
||||
}
|
||||
Abc_FrameUpdateGia( Abc_FrameGetGlobalFrame(), pGia );
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), "&put") ) {
|
||||
return;
|
||||
}
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), resyn2) ) {
|
||||
Abc_Print( 1, "Something did not work out with the command \"%s\".\n", resyn2 );
|
||||
return;
|
||||
}
|
||||
if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), "&get") ) {
|
||||
return;
|
||||
}
|
||||
if (reset_batch_mode) {
|
||||
Abc_FrameSetBatchMode( 0 );
|
||||
}
|
||||
Gia_Man_t* tmp = Abc_FrameReadGia(Abc_FrameGetGlobalFrame());
|
||||
if (Gia_ManAndNum(tmp) <= nand && Gia_ManLevelNum(tmp) <= nlevel) {
|
||||
es_man = eSLIMCirMan(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Circuitrepresentation, typename Inprocessor, typename Minimizer, typename Approach>
|
||||
Circuitrepresentation* runeSLIM(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
return eSLIMRun<Approach, Inprocessor>::runeSLIM(cir, params);
|
||||
}
|
||||
|
||||
template <typename Circuitrepresentation, typename Inprocessor, typename Minimizer, typename Validator, typename SearchDirection, typename BiasSelector, typename RootSelector>
|
||||
Circuitrepresentation* toggleWindowing(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
if (params->nWindows > 0) {
|
||||
return runeSLIM<Circuitrepresentation, Inprocessor, Minimizer, WindowMan<Minimizer, RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector>>>(cir, params);
|
||||
} else {
|
||||
return runeSLIM<Circuitrepresentation, Inprocessor, Minimizer, eSLIM_Man<Minimizer, RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector>>>(cir, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Circuitrepresentation, typename Inprocessor, typename Minimizer, typename Validator, typename SearchDirection, typename BiasSelector>
|
||||
Circuitrepresentation* setTabooApproach(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
if (params->use_taboo_list) {
|
||||
return toggleWindowing<Circuitrepresentation, Inprocessor, Minimizer, Validator, SearchDirection, BiasSelector, TabooRootSelector>(cir, params);
|
||||
} else {
|
||||
return toggleWindowing<Circuitrepresentation, Inprocessor, Minimizer, Validator, SearchDirection, BiasSelector, BaseRootSelector>(cir, params);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Circuitrepresentation, typename Inprocessor, typename Minimizer, typename Validator, typename SearchDirection>
|
||||
Circuitrepresentation* setBiasApproach(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
if (params->criticial_path_selection_bias) {
|
||||
return toggleWindowing<Circuitrepresentation, Inprocessor, Minimizer, Validator, SearchDirection, CriticalPathBiasSelector, CriticalPathSelector>(cir, params);
|
||||
} else {
|
||||
return setTabooApproach<Circuitrepresentation, Inprocessor, Minimizer, Validator, SearchDirection, NoBiasSelector>(cir, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Circuitrepresentation, typename Inprocessor, typename Minimizer, typename Validator>
|
||||
Circuitrepresentation* setSearchDirection(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
if (params->forward_search) {
|
||||
return setBiasApproach<Circuitrepresentation, Inprocessor, Minimizer, Validator, ForwardSearch>(cir, params);
|
||||
} else {
|
||||
return setBiasApproach<Circuitrepresentation, Inprocessor, Minimizer, Validator, BackwardSearch>(cir, params);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Circuitrepresentation>
|
||||
Circuitrepresentation* setMinimizer(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
switch (params->synthesis_approach) {
|
||||
case 0:
|
||||
if (params->apply_inprocessing) {
|
||||
if constexpr ( std::is_same_v<Gia_Man_t, Circuitrepresentation> ) {
|
||||
return setSearchDirection<Circuitrepresentation, DeepsynInprocessor, AreaMinimizer, SubcircuitValidator>(cir, params);
|
||||
} else {
|
||||
return setSearchDirection<Circuitrepresentation, MfsInprocessor, AreaMinimizer, SubcircuitValidator>(cir, params);
|
||||
}
|
||||
}
|
||||
return setSearchDirection<Circuitrepresentation, EmptyInprocessor, AreaMinimizer, SubcircuitValidator>(cir, params);
|
||||
case 1:
|
||||
if constexpr ( std::is_same_v<Gia_Man_t, Circuitrepresentation> ) {
|
||||
if (params->apply_inprocessing) {
|
||||
return setSearchDirection<Circuitrepresentation, Resyn2Inprocessor, AreaDelayConstraintMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
}
|
||||
}
|
||||
return setSearchDirection<Circuitrepresentation, EmptyInprocessor, AreaDelayConstraintMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
case 2:
|
||||
if constexpr ( std::is_same_v<Gia_Man_t, Circuitrepresentation> ) {
|
||||
if (params->apply_inprocessing) {
|
||||
return setSearchDirection<Circuitrepresentation, DelayInprocessor<false>, AreaDelayMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
}
|
||||
}
|
||||
return setSearchDirection<Circuitrepresentation, EmptyInprocessor, AreaDelayMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
case 3:
|
||||
if constexpr ( std::is_same_v<Gia_Man_t, Circuitrepresentation> ) {
|
||||
if (params->apply_inprocessing) {
|
||||
return setSearchDirection<Circuitrepresentation, DelayInprocessor<false>, DelayMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
}
|
||||
}
|
||||
return setSearchDirection<Circuitrepresentation, EmptyInprocessor, DelayMinimizer, SubcircuitNoFBValidator>(cir, params);
|
||||
default:
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return pGia;
|
||||
}
|
||||
|
||||
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";
|
||||
template <typename Circuitrepresentation>
|
||||
Circuitrepresentation* runeSLIM(Circuitrepresentation * cir, const eSLIM_ParamStruct* params) {
|
||||
// Windowing does currently not support Deleyconstraints/Delayoptimisation
|
||||
if (params->nWindows && params->synthesis_approach != 0) {
|
||||
return NULL;
|
||||
}
|
||||
return eSLIM::setMinimizer(cir, params);
|
||||
}
|
||||
|
||||
|
||||
Gia_Man_t* applyeSLIM(Gia_Man_t * pGia, const eSLIM_ParamStruct* params) {
|
||||
eSLIM::eSLIMConfig config = getCfg(params);
|
||||
config.verbosity_level = params->verbosity_level;
|
||||
|
||||
int eSLIM_reductions = 0;
|
||||
int deepsyn_reductions = 0;
|
||||
|
||||
Gia_Man_t * pThis = Gia_ManDup(pGia);
|
||||
eSLIM::eSLIMLog log(params->subcircuit_size_bound);
|
||||
int initial_size = Gia_ManAndNum(pThis);
|
||||
if (params->verbosity_level > 0) {
|
||||
printSetting(params);
|
||||
std::cout << "Initial size: " << initial_size << "\n";
|
||||
}
|
||||
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->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<double>(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->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->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<double>(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<double>(log.cummulative_unsat_runtimes_per_size[i]) / (1000* log.nof_unsat_calls_per_size[i]) << " sec\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pThis;
|
||||
return runeSLIM(pGia, params);
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
Abc_Ntk_t* applyelSLIM(Abc_Ntk_t * ntk, const eSLIM_ParamStruct* params) {
|
||||
return runeSLIM(ntk, params);
|
||||
}
|
||||
|
||||
Abc_Ntk_t* applyetSLIM(Abc_Ntk_t * ntk, const eSLIM_ParamStruct* params) {
|
||||
return runeSLIM(ntk, params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.h,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
|
|
@ -23,39 +23,52 @@
|
|||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
#include "aig/gia/gia.h"
|
||||
#include "base/abc/abc.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
|
||||
int fill_subcircuits; // If a subcircuit has fewer than subcircuit_size_bound gates, try to fill it with rejected gates.
|
||||
int fill_subcircuits; // If a subcircuit has fewer than subcircuit_max_size gates, try to fill it with rejected gates.
|
||||
int apply_strash;
|
||||
int fix_seed;
|
||||
int trial_limit_active;
|
||||
int apply_inprocessing;
|
||||
|
||||
int synthesis_approach;
|
||||
int seed;
|
||||
int verbosity_level;
|
||||
int approximate_relation;
|
||||
int relation_tfo_bound;
|
||||
int generate_relation_with_tfi_limit;
|
||||
int relation_tfi_bound;
|
||||
int use_taboo_list;
|
||||
int forward_search;
|
||||
int nWindows;
|
||||
int window_size;
|
||||
|
||||
int criticial_path_selection_bias;
|
||||
|
||||
|
||||
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;
|
||||
unsigned int subcircuit_max_size; // upper bound for the subcircuit sizes
|
||||
unsigned int additional_gates; // number of gates that may be introduced to reduce delay
|
||||
|
||||
double expansion_probability; // the probability that a node is added to the subcircuit
|
||||
unsigned int nruns;
|
||||
|
||||
int mode; // 0: Cadical Incremental, 1: Kissat Oneshot
|
||||
int seed;
|
||||
int verbosity_level;
|
||||
unsigned int strash_intervall;
|
||||
unsigned int nselection_trials;
|
||||
|
||||
|
||||
int gate_size;
|
||||
int aig;
|
||||
};
|
||||
|
||||
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_Ntk_t* applyelSLIM(Abc_Ntk_t * ntk, const eSLIM_ParamStruct* params); //LUT-eSLIM
|
||||
|
||||
|
||||
ABC_NAMESPACE_HEADER_END
|
||||
|
|
|
|||
|
|
@ -26,67 +26,51 @@
|
|||
#include <unordered_set>
|
||||
|
||||
#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 "eslimCirMan.hpp"
|
||||
#include "relationGeneration.hpp"
|
||||
#include "selectionStrategies.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "selectionStrategy.hpp"
|
||||
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace eSLIM {
|
||||
|
||||
template<class SynthesisEngine, class RelationEngine, class SelectionEngine>
|
||||
class eSLIM_Man {
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
class eSLIM_Man {
|
||||
public:
|
||||
static Gia_Man_t* applyeSLIM(Gia_Man_t * p, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
static void applyeSLIM(eSLIMCirMan& cir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
private:
|
||||
|
||||
eSLIM_Man(Gia_Man_t * gia_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
Gia_Man_t* getCircuit();
|
||||
eSLIM_Man(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
void optimize();
|
||||
|
||||
void minimize();
|
||||
void findReplacement();
|
||||
Mini_Aig_t* findMinimumAig(const Subcircuit& subcir);
|
||||
eSLIMCirMan computeReplacement(Subcircuit& subcir);
|
||||
eSLIMCirMan synthesiseRelation(Subcircuit& subcir, const Relation& rel);
|
||||
|
||||
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<int, Mini_Aig_t*> reduce( Vec_Wrd_t* vSimsDiv, Vec_Wrd_t* vSimsOut, const std::unordered_map<int, std::unordered_set<int>>& 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<int> processReplacement(Gia_Man_t* gia_man, Gia_Man_t* pNew, const Subcircuit& subcir, Mini_Aig_t* replacement, std::vector<int>&& to_process, std::vector<int>& 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<int>& replacement_values, int fanin_lit);
|
||||
|
||||
Gia_Man_t* gia_man = nullptr;
|
||||
eSLIMCirMan& es_man;
|
||||
SelectionStrategy selection_strategy;
|
||||
const eSLIMConfig& cfg;
|
||||
eSLIMLog& log;
|
||||
SelectionEngine subcircuit_selection;
|
||||
|
||||
|
||||
double relation_generation_time ;
|
||||
double synthesis_time ;
|
||||
|
||||
bool stopeSLIM=false;
|
||||
bool stopeSLIM = false;
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
inline Gia_Man_t* eSLIM_Man<Y, R, S>::getCircuit() {
|
||||
return gia_man;
|
||||
}
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#include "eSLIMMan.tpp"
|
||||
|
|
|
|||
|
|
@ -14,79 +14,60 @@
|
|||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
|
||||
Revision [$Id: eSLIMMan.tpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIMMan.hpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <cassert>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <iostream>
|
||||
#include <climits>
|
||||
|
||||
#include "eSLIMMan.hpp"
|
||||
#include "synthesisEngine.hpp"
|
||||
#include "relationGeneration.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_HEADER_START
|
||||
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
|
||||
#include "synthesisEngines.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace eSLIM {
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
Gia_Man_t* eSLIM_Man<Y, R, S>::applyeSLIM(Gia_Man_t * p, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
eSLIM_Man<Y, R, S> eslim(p, cfg, log);
|
||||
eslim.minimize();
|
||||
return eslim.getCircuit();
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void eSLIM_Man<SynthesisEngine, SelectionStrategy>::applyeSLIM(eSLIMCirMan& cir, const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
eSLIM_Man eslim(cir, cfg, log);
|
||||
eslim.optimize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
eSLIM_Man<Y, R, S>::eSLIM_Man(Gia_Man_t * pGia, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: gia_man(pGia), cfg(cfg), log(log),
|
||||
subcircuit_selection(gia_man, cfg, log) {
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
eSLIM_Man<SynthesisEngine, SelectionStrategy>::eSLIM_Man(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: es_man(es_man), selection_strategy(this->es_man, cfg, log), cfg(cfg), log(log) {
|
||||
if (cfg.fix_seed) {
|
||||
subcircuit_selection.setSeed(cfg.seed);
|
||||
selection_strategy.setSeed(cfg.seed);
|
||||
}
|
||||
relation_generation_time = log.relation_generation_time;
|
||||
synthesis_time = log.synthesis_time;
|
||||
}
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
void eSLIM_Man<Y, R, S>::minimize() {
|
||||
|
||||
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void eSLIM_Man<SynthesisEngine, SelectionStrategy>::optimize() {
|
||||
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;
|
||||
int current_size = Gia_ManAndNum(gia_man);
|
||||
int current_size = es_man.getNofGates();
|
||||
const char* node_type = cfg.aig ? "#and" : "#nd";
|
||||
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_Man_t* pTemp = es_man.eSLIMCirManToGia();
|
||||
Gia_Man_t* gia_man = Gia_ManRehash( pTemp, 0 );
|
||||
Gia_ManStop( pTemp );
|
||||
es_man = eSLIMCirMan(gia_man);
|
||||
Gia_ManStop( gia_man );
|
||||
selection_strategy.reset();
|
||||
}
|
||||
if (cfg.verbosity_level > 0) {
|
||||
int sz = Gia_ManAndNum(gia_man);
|
||||
int sz = es_man.getNofGates();
|
||||
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);
|
||||
printf("\rIteration %8d : %s = %7d elapsed time = %7.2f sec\n", iteration, node_type, sz, (float)1.0*(Abc_Clock() - clkStart)/CLOCKS_PER_SEC);
|
||||
} else {
|
||||
printf("\rIteration %8d", iteration);
|
||||
fflush(stdout);
|
||||
|
|
@ -95,8 +76,8 @@ namespace eSLIM {
|
|||
}
|
||||
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);
|
||||
int sz = es_man.getNofGates();
|
||||
printf("\r#Iterations %8d %s = %7d elapsed time = %7.2f sec\n", iteration, node_type, 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);
|
||||
|
|
@ -104,379 +85,57 @@ namespace eSLIM {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
Vec_Wrd_t* eSLIM_Man<Y, R, S>::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);
|
||||
}
|
||||
}
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
eSLIMCirMan eSLIM_Man<SynthesisEngine, SelectionStrategy>::computeReplacement(Subcircuit& subcir) {
|
||||
abctime relation_generation_start = Abc_Clock();
|
||||
Relation rel = RelationGenerator::computeRelation(es_man, subcir, cfg, log);
|
||||
log.relation_generation_time += (double)1.0*(Abc_Clock() - relation_generation_start)/CLOCKS_PER_SEC;
|
||||
log.cummulative_relation_generation_times_per_size[subcir.nodes.size()] += (double)1.0*(Abc_Clock() - relation_generation_start) / CLOCKS_PER_SEC;
|
||||
log.nof_relation_generations_per_size[subcir.nodes.size()]++;
|
||||
if (!rel.getStatus()) {
|
||||
return eSLIMCirMan(0);
|
||||
}
|
||||
return vSimsDiv;
|
||||
}
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
Vec_Wrd_t* eSLIM_Man<Y, R, S>::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;
|
||||
abctime synthesis_start = Abc_Clock();
|
||||
eSLIMCirMan replacement = synthesiseRelation(subcir, rel);
|
||||
log.synthesis_time += (double)1.0*(Abc_Clock() - synthesis_start)/CLOCKS_PER_SEC;
|
||||
return replacement;
|
||||
}
|
||||
|
||||
template <typename Y, typename R, typename S>
|
||||
void eSLIM_Man<Y, R, S>::findReplacement() {
|
||||
Subcircuit subcir = subcircuit_selection.getSubcircuit();
|
||||
if (!subcircuit_selection.getStatus()) {
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
eSLIMCirMan eSLIM_Man<SynthesisEngine, SelectionStrategy>::synthesiseRelation(Subcircuit& subcir, const Relation& rel) {
|
||||
return SynthesisEngine::optimize(es_man, rel, subcir, cfg, log);
|
||||
}
|
||||
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void eSLIM_Man<SynthesisEngine, SelectionStrategy>::findReplacement() {
|
||||
bool status = true;
|
||||
if constexpr (SelectionStrategy::requiresRemainingTimes() || isDelayEngine<SynthesisEngine>::value) {
|
||||
es_man.setupTimings();
|
||||
}
|
||||
Subcircuit subcir = selection_strategy.getSubcircuit(status);
|
||||
if (!status) {
|
||||
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();
|
||||
}
|
||||
eSLIMCirMan replacement = computeReplacement(subcir);
|
||||
|
||||
// Based on Exa_ManExactSynthesis6Int and Exa_ManExactSynthesis6
|
||||
template <typename Y, typename R, typename S>
|
||||
Mini_Aig_t* eSLIM_Man<Y, R, S>::findMinimumAig(const Subcircuit& subcir) {
|
||||
|
||||
if (subcir.forbidden_pairs.size() > 0) {
|
||||
log.subcircuits_with_forbidden_pairs++;
|
||||
if (log.nof_analyzed_circuits_per_size.size() < subcir.nodes.size() + 1) {
|
||||
log.nof_analyzed_circuits_per_size.resize(subcir.nodes.size() + 1, 0);
|
||||
log.nof_replaced_circuits_per_size.resize(subcir.nodes.size() + 1, 0);
|
||||
log.nof_reduced_circuits_per_size.resize(subcir.nodes.size() + 1, 0);
|
||||
}
|
||||
|
||||
abctime relation_generation_start = Abc_Clock();
|
||||
Abc_RData_t* relation = RelationGenerator<R>::computeRelation(gia_man, subcir);
|
||||
log.relation_generation_time += (double)1.0*(Abc_Clock() - relation_generation_start)/CLOCKS_PER_SEC;
|
||||
|
||||
int nDivs = 0;
|
||||
int nOuts = relation->nOuts;
|
||||
int nVars = relation->nIns;
|
||||
if ( nVars == 0 ) {
|
||||
return nullptr;
|
||||
}
|
||||
// assert (nVars <= 8);
|
||||
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 <typename Y, typename R, typename S>
|
||||
word eSLIM_Man<Y, R, S>::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 <typename Y, typename R, typename S>
|
||||
bool eSLIM_Man<Y, R, S>::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 <typename Y, typename R, typename S>
|
||||
int eSLIM_Man<Y, R, S>::getInsertionLiteral(Gia_Man_t* gia_man, const Subcircuit& subcir, Mini_Aig_t* replacement, const std::vector<int>& 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 <typename Y, typename R, typename S>
|
||||
std::vector<int> eSLIM_Man<Y, R, S>::processReplacement(Gia_Man_t* gia_man, Gia_Man_t* pNew, const Subcircuit& subcir, Mini_Aig_t* replacement, std::vector<int>&& to_process, std::vector<int>& replacement_values) {
|
||||
std::vector<int> 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 <typename Y, typename R, typename S>
|
||||
Vec_Int_t * eSLIM_Man<Y, R, S>::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 <typename Y, typename R, typename S>
|
||||
void eSLIM_Man<Y, R, S>::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<int> to_process_replacement;
|
||||
Mini_AigForEachAnd(replacement, i) {
|
||||
to_process_replacement.push_back(i);
|
||||
}
|
||||
std::vector<int> 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 <typename Y, typename R, typename S>
|
||||
std::pair<int, Mini_Aig_t*> eSLIM_Man<Y, R, S>::reduce(Vec_Wrd_t* vSimsDiv, Vec_Wrd_t* vSimsOut, const std::unordered_map<int, std::unordered_set<int>>& 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 <typename Y, typename R, typename S>
|
||||
double eSLIM_Man<Y, R, S>::getDynamicTimeout(int size) {
|
||||
if (this->log.nof_sat_calls_per_size[size] > cfg.minimum_dynamic_timeout_sample_size) {
|
||||
return std::max(static_cast<double>(cfg.minimum_sat_timeout), static_cast<double>(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 <typename Y, typename R, typename S>
|
||||
Mini_Aig_t* eSLIM_Man<Y, R, S>::computeReplacement(Y& syn_man, int size) {
|
||||
return syn_man.getCircuit(size, getDynamicTimeout(size));
|
||||
log.nof_analyzed_circuits_per_size[subcir.nodes.size()]++;
|
||||
log.subcircuits_with_forbidden_pairs += !subcir.forbidden_pairs.empty();
|
||||
if (replacement.getNofObjs() > 1) { //replacement found
|
||||
log.nof_replaced_circuits_per_size[subcir.nodes.size()]++;
|
||||
log.nof_reduced_circuits_per_size[subcir.nodes.size()] += (replacement.getNofGates() < subcir.nodes.size());
|
||||
es_man.replace(replacement, subcir);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,234 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [eslimCirMan.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Internal circuit representation.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__ESLIMCIRMAN_hpp
|
||||
#define ABC__OPT__ESLIM__ESLIMCIRMAN_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include "aig/gia/gia.h"
|
||||
#include "base/abc/abc.h"
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class Subcircuit;
|
||||
class eSLIMCirMan;
|
||||
class TabooList;
|
||||
template <typename SynthesisEngine, typename SelectionStrategy> class WindowMan;
|
||||
|
||||
// Nodes must not have more than 6 fanins
|
||||
class eSLIMCirObj {
|
||||
|
||||
private:
|
||||
|
||||
// This comparator is used in sets of pointers to nodes.
|
||||
// As the order does not really matter, the comparator could be replaced by comparing addresses.
|
||||
// This would slightly simplify the code as we would not need to change the fanouts of replacement circuits
|
||||
// (unlike to the ids the addresses of the nodes in the replacement do not change during the replacement).
|
||||
// Nevertheless, we use this iterator to make iteration orders more predictable.
|
||||
struct eSLIMObjComp {
|
||||
bool operator()(eSLIMCirObj* a, eSLIMCirObj* b) const {
|
||||
return a->getId() < b->getId();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
eSLIMCirObj(int id, std::vector<eSLIMCirObj*>&& fanins);
|
||||
int getNFanins() const;
|
||||
int getTTLength() const;
|
||||
unsigned int getId() const;
|
||||
|
||||
int node_id;
|
||||
std::vector<eSLIMCirObj*> fanins;
|
||||
std::set<eSLIMCirObj*, eSLIMObjComp> fanouts;
|
||||
ABC_UINT64_T tt; //truth table representing the function
|
||||
int depth = 0; // the step from a input/gate node to an output node is also counted -> depth differs from depths in abc
|
||||
int remaining_time = 0;
|
||||
|
||||
int value1 = 0;
|
||||
|
||||
private:
|
||||
unsigned int id = 0;
|
||||
// set traversal_id
|
||||
unsigned int trav_id = 0;
|
||||
unsigned int inSubcircuit = 0;
|
||||
unsigned int inTFI = 0;
|
||||
unsigned int inTFO = 0;
|
||||
unsigned int isTaboo = 0;
|
||||
|
||||
friend eSLIMCirMan;
|
||||
friend TabooList;
|
||||
};
|
||||
|
||||
class eSLIMCirMan {
|
||||
|
||||
public:
|
||||
|
||||
eSLIMCirMan(int nObjEstimate);
|
||||
eSLIMCirMan(Gia_Man_t * pGia);
|
||||
eSLIMCirMan(Abc_Ntk_t * pNtk, bool simplify);
|
||||
eSLIMCirMan(eSLIMCirMan& es_man, const Subcircuit& scir);
|
||||
|
||||
// normalises the aig
|
||||
// static eSLIMCirMan eSLIMCirManFromGia(Gia_Man_t * pGia);
|
||||
static ABC_UINT64_T negateTT(ABC_UINT64_T tt, unsigned int nfanin);
|
||||
static ABC_UINT64_T ttNegateFanin(ABC_UINT64_T tt, unsigned int fan);
|
||||
static bool ttisnormal(ABC_UINT64_T tt);
|
||||
|
||||
void registerTabooList(TabooList* taboo);
|
||||
void unregisterTabooList();
|
||||
|
||||
void replace(eSLIMCirMan& replacement, const Subcircuit& subcir);
|
||||
|
||||
|
||||
Gia_Man_t* eSLIMCirManToGia();
|
||||
Abc_Ntk_t* eSLIMCirManToNtk();
|
||||
Abc_Ntk_t* eSLIMCirManToMappedNtk();
|
||||
void setupTimings();
|
||||
|
||||
bool isConst(int id) const;
|
||||
bool isPi(int id) const; // or constant node
|
||||
bool isPo(int id) const;
|
||||
bool isGate(int id) const;
|
||||
|
||||
bool isConst(const eSLIMCirObj&) const;
|
||||
bool isPi(const eSLIMCirObj&) const;
|
||||
|
||||
bool isOnCricticalPath(const eSLIMCirObj&) const;
|
||||
|
||||
int getNofObjs() const;
|
||||
int getNofPis() const;
|
||||
int getNofPos() const;
|
||||
int getNofGates() const;
|
||||
|
||||
int getDepth() const;
|
||||
|
||||
const eSLIMCirObj& getObj(int id) const;
|
||||
|
||||
void incrementTraversalId() {traversal_id++;}
|
||||
void setTraversalId(eSLIMCirObj& obj);
|
||||
void setTraversalId(int n);
|
||||
bool isCurrentTraversalId(const eSLIMCirObj& obj) const;
|
||||
bool isCurrentTraversalId(int n) const;
|
||||
|
||||
void setInSubcircuit(eSLIMCirObj& obj);
|
||||
void setInTFI(eSLIMCirObj& obj);
|
||||
void setInTFO(eSLIMCirObj& obj);
|
||||
bool inSubcircuit(const eSLIMCirObj& obj) const;
|
||||
bool inTFI(const eSLIMCirObj& obj) const;
|
||||
bool inTFO(const eSLIMCirObj& obj) const;
|
||||
|
||||
void markSubcircuit(const std::vector<int>& nodes);
|
||||
void markCones(const std::vector<int>& nodes);
|
||||
|
||||
int addPi();
|
||||
int addPo(int fanin, bool negated);
|
||||
int addNode(const std::vector<int>& fanins, ABC_UINT64_T tt);
|
||||
|
||||
void print() const;
|
||||
void print(const Subcircuit& scir) const;
|
||||
eSLIMCirMan duplicate() const;
|
||||
|
||||
private:
|
||||
|
||||
bool isTaboo(const eSLIMCirObj& obj, int taboo_time) const;
|
||||
void setTaboo(eSLIMCirObj& obj);
|
||||
|
||||
eSLIMCirObj* getpObj(int id);
|
||||
const eSLIMCirObj* getpObj(int id) const;
|
||||
|
||||
eSLIMCirObj* getPo(int id);
|
||||
|
||||
static ABC_UINT64_T ttFromGiaObj(Gia_Man_t * pGia, Gia_Obj_t * pObj);
|
||||
static ABC_UINT64_T ttFromNtkObj(Abc_Ntk_t * pNtk, Abc_Obj_t * pObj);
|
||||
|
||||
std::vector<std::unique_ptr<eSLIMCirObj>> replaceInternal(eSLIMCirMan& replacement, const Subcircuit& subcir);
|
||||
void setupMarksForReplacement(eSLIMCirMan& replacement);
|
||||
void clearFanouts(const Subcircuit& subcir);
|
||||
|
||||
void insertSorted(eSLIMCirObj* obj, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
void insertSortedRec( eSLIMCirObj* obj, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
|
||||
void insertSortedRecRep(eSLIMCirObj* obj, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
void processRepFanin( eSLIMCirObj* obj, eSLIMCirObj* fan, int fid, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
void processRepPo( eSLIMCirObj* obj, eSLIMCirObj* fan, int fid, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
void processNonGateRepFanin(eSLIMCirObj* obj, eSLIMCirObj* fan, int fid, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted,
|
||||
eSLIMCirMan& replacement, const std::unordered_map<int,int>& out_map, const std::vector<eSLIMCirObj*>& in_vec);
|
||||
void addFans(eSLIMCirObj* out, eSLIMCirObj* in, int fin_id);
|
||||
|
||||
|
||||
int addGiaGate(Gia_Man_t * pGia, int node_id, std::vector<int>& node_ids, std::vector<bool>& is_node_negated);
|
||||
static ABC_UINT64_T sop2tt(char * pSop);
|
||||
static char* tt2sop(ABC_UINT64_T tt, int nVars, Mem_Flex_t * pMan);
|
||||
|
||||
int insertNtkNodes(Abc_Ntk_t * pNtk, int node_id, std::unordered_map<int,int>& ids, bool simplify);
|
||||
|
||||
int processRedundant(const Subcircuit& subcir);
|
||||
void moveNode(std::vector<std::unique_ptr<eSLIMCirObj>>& vec, std::unique_ptr<eSLIMCirObj>& pobj);
|
||||
void setMarks(eSLIMCirObj& pObj, int id);
|
||||
|
||||
// The nodes vector contains nodes in topological order.
|
||||
// This does not necessarily ensure that if a < b we have lv(a) < lv(b) (lv: the level/depth of the node)
|
||||
// If nodes are sorted according to their levels i.e. a <= b iff lv(a) <= lv(b) then the nodes are also topologically sorted.
|
||||
void applyLevelBasedOrdering();
|
||||
void applyDFSOrdering(const std::vector<int>& po_nodes); // po_nodes must contain the node_id of each primary output
|
||||
void applyDFSOrderingRec(eSLIMCirObj* obj, std::vector<std::unique_ptr<eSLIMCirObj>>& sorted);
|
||||
|
||||
// remove repeated fanins
|
||||
// The Gia representation does not allow repeated fanins.
|
||||
void simplifyDuplicateFanins();
|
||||
ABC_UINT64_T removeInputFromTT(ABC_UINT64_T tt, unsigned int first_occurrence, unsigned int second_occurrence);
|
||||
ABC_UINT64_T compressTT(ABC_UINT64_T tt, unsigned int input);
|
||||
|
||||
unsigned int nof_pis = 0;
|
||||
unsigned int nof_pos = 0;
|
||||
std::vector<std::unique_ptr<eSLIMCirObj>> nodes;
|
||||
unsigned int last_node_id = 0;
|
||||
|
||||
static constexpr int const_false_id = 0;
|
||||
unsigned int traversal_id = 0;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
TabooList* taboo = nullptr;
|
||||
|
||||
friend TabooList;
|
||||
template <typename SynthesisEngine, typename SelectionStrategy> friend class WindowMan;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif
|
||||
|
|
@ -1,2 +1,7 @@
|
|||
SRC += src/opt/eslim/relationGeneration.cpp \
|
||||
src/opt/eslim/eSLIM.cpp
|
||||
SRC += src/opt/eslim/eSLIM.cpp \
|
||||
src/opt/eslim/eslimCirMan.cpp \
|
||||
src/opt/eslim/relationGeneration.cpp \
|
||||
src/opt/eslim/subcircuit.cpp \
|
||||
src/opt/eslim/relationSynthesiser.cpp \
|
||||
src/opt/eslim/areaEngine.cpp \
|
||||
src/opt/eslim/delayEngine.cpp \
|
||||
|
|
|
|||
|
|
@ -6,167 +6,419 @@
|
|||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Procedures for computing Boolean relations.]
|
||||
Synopsis [SAT-based computation of Boolean relations.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: relationGeneration.cpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include "misc/vec/vec.h"
|
||||
#include "sat/cnf/cnf.h"
|
||||
#include "sat/bsat/satSolver.h"
|
||||
#include "misc/util/abc_global.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());
|
||||
Relation::Relation(int nfanins) : output_patterns(1 << nfanins) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
void Relation::addOutputPattern(int inputidx, std::vector<bool>&& pattern) {
|
||||
lines_with_pattern += output_patterns[inputidx].empty();
|
||||
output_patterns[inputidx].push_back(pattern);
|
||||
}
|
||||
|
||||
RelationGenerator::RelationGenerator( const eSLIMCirMan& cir, const Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: cir(cir), subcir(subcir), cfg(cfg), log(log),
|
||||
gate2varref(cir.getNofObjs() - cir.getNofPos()),
|
||||
gate2varcone(cir.getNofObjs() - cir.getNofPos()) {
|
||||
setupEncoding();
|
||||
}
|
||||
|
||||
Relation RelationGenerator::computeRelation(const eSLIMCirMan& cir, const Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
RelationGenerator rgen(cir, subcir, cfg, log);
|
||||
return rgen.getRelation();
|
||||
}
|
||||
|
||||
int RelationGenerator::getNewVar() {
|
||||
return max_var++;
|
||||
}
|
||||
|
||||
void RelationGenerator::setupEncoding() {
|
||||
if (cfg.approximate_relation) {
|
||||
if (cfg.generate_relation_with_tfi_limit) {
|
||||
encodeCircuitApproximativeBoundedTFI();
|
||||
} else {
|
||||
encodeCircuitApproximative();
|
||||
}
|
||||
} else {
|
||||
// encodeCircuitFull();
|
||||
encodeCircuitAffected();
|
||||
}
|
||||
}
|
||||
|
||||
void RelationGenerator::encodeGate(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var) {
|
||||
int bc = popcount(obj.tt);
|
||||
int tt_length = obj.getTTLength();
|
||||
if (bc == 0) {
|
||||
solver.addClause({-var});
|
||||
} else if (bc == tt_length) {
|
||||
solver.addClause({var});
|
||||
} else if (bc == 1) {
|
||||
return getGateEncodingUnique(obj, var, gate2var, true);
|
||||
} else if (bc == tt_length - 1) {
|
||||
return getGateEncodingUnique(obj, var, gate2var, false);
|
||||
} else {
|
||||
return getGateEncodingNaive(obj, var, gate2var);
|
||||
}
|
||||
}
|
||||
|
||||
void RelationGenerator::getGateEncodingUnique(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var, bool unique_bit) {
|
||||
ABC_UINT64_T tt = obj.tt;
|
||||
if (!unique_bit) {
|
||||
tt = eSLIMCirMan::negateTT(tt, obj.getNFanins());
|
||||
}
|
||||
int bit_index = lsb(tt);
|
||||
std::vector<int> clause;
|
||||
int lit = unique_bit ? -var : var;
|
||||
for (int i = 0; i < obj.getNFanins(); i++) {
|
||||
if ((bit_index >> i) & 1 ) {
|
||||
clause.push_back(-gate2var[obj.fanins[i]->node_id]);
|
||||
solver.addClause({gate2var[obj.fanins[i]->node_id], lit});
|
||||
} else {
|
||||
clause.push_back(gate2var[obj.fanins[i]->node_id]);
|
||||
solver.addClause({-gate2var[obj.fanins[i]->node_id], lit});
|
||||
}
|
||||
}
|
||||
clause.push_back(-lit);
|
||||
solver.addClause(clause);
|
||||
}
|
||||
|
||||
void RelationGenerator::getGateEncodingNaive(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var) {
|
||||
int tt_length = obj.getTTLength();
|
||||
int nfans = obj.getNFanins();
|
||||
std::vector<int> clause;
|
||||
clause.reserve(nfans+1);
|
||||
for (int i = 0; i < tt_length; i++) {
|
||||
clause.clear();
|
||||
for (int j = 0; j < nfans; j++) {
|
||||
if ((i >> j) & 1 ) {
|
||||
clause.push_back(-gate2var[obj.fanins[j]->node_id]);
|
||||
} else {
|
||||
clause.push_back(gate2var[obj.fanins[j]->node_id]);
|
||||
}
|
||||
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; }
|
||||
}
|
||||
bool polarity = (obj.tt >> i) & 1;
|
||||
if (polarity) {
|
||||
clause.push_back(var);
|
||||
} else {
|
||||
clause.push_back(-var);
|
||||
}
|
||||
solver.addClause(clause);
|
||||
}
|
||||
// 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 );
|
||||
void RelationGenerator::encodeCircuitAffected() {
|
||||
setupConstantGate();
|
||||
std::vector<int> compare_nodes;
|
||||
for (int i = cir.getNofObjs() - cir.getNofPos(); i < cir.getNofObjs(); i++) {
|
||||
const auto obj = cir.getObj(i);
|
||||
int fid = obj.fanins[0]->node_id;
|
||||
// multiple POs can use the same fanin
|
||||
// if gate2varref[fid] is not 0 we have already seen it
|
||||
if (cir.inTFO(obj) && !gate2varref[fid]) {
|
||||
gate2varref[fid] = getNewVar();
|
||||
gate2varcone[fid] = getNewVar();
|
||||
compare_nodes.push_back(fid);
|
||||
}
|
||||
}
|
||||
setupEqualityConstraints(compare_nodes);
|
||||
|
||||
for (int i = cir.getNofObjs() - cir.getNofPos() - 1; i > cir.getNofPis(); i--) {
|
||||
if (gate2varref[i]) { // the gate is connected to a PO that is in the TFO of the subcircuit
|
||||
const auto obj = cir.getObj(i);
|
||||
for (const auto& f : obj.fanins) {
|
||||
int fid = f->node_id;
|
||||
if (gate2varref[fid] == 0) {
|
||||
gate2varref[fid] = getNewVar();
|
||||
}
|
||||
}
|
||||
encodeGate(obj, gate2varref[i], gate2varref);
|
||||
|
||||
if (cir.inTFO(obj) && !cir.inSubcircuit(obj)) {
|
||||
// For an input in a forbidden pair no successors needs to be processed before
|
||||
gate2varcone[i] = gate2varcone[i] ? gate2varcone[i] : getNewVar();
|
||||
for (const auto& f : obj.fanins) {
|
||||
int fid = f->node_id;
|
||||
if (cir.inSubcircuit(*f) || cir.inTFO(*f)) {
|
||||
if (gate2varcone[fid] == 0) {
|
||||
gate2varcone[fid] = getNewVar();
|
||||
}
|
||||
} else {
|
||||
gate2varcone[fid] = gate2varref[fid];
|
||||
}
|
||||
}
|
||||
encodeGate(obj, gate2varcone[i], gate2varcone);
|
||||
} else if (gate2varcone[i] == 0) {
|
||||
gate2varcone[i] = gate2varref[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Gia_ManIncrementTravId(pGia);
|
||||
Gia_ManForEachObjVec( subcir.nodes, pGia, pObj, i ) {
|
||||
Gia_ObjSetTravIdCurrent(pGia, pObj);
|
||||
for (int i = 1; i <= cir.getNofPis(); i++) {
|
||||
if (gate2varref[i] != 0) {
|
||||
cone_input_variables.push_back(gate2varref[i]);
|
||||
// Simplifies handling of variables
|
||||
if (gate2varcone[i] == 0) {
|
||||
gate2varcone[i] = gate2varref[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
void RelationGenerator::encodeCircuitApproximative() {
|
||||
setupConstantGate();
|
||||
std::vector<int> compare_nodes = markRestrictedCone();
|
||||
int max_node = *std::max_element(compare_nodes.begin(), compare_nodes.end());
|
||||
for (int i = max_node; i > cir.getNofPis(); i--) {
|
||||
const auto obj = cir.getObj(i);
|
||||
if (gate2varref[i] != 0) {
|
||||
for (auto& f : obj.fanins ) {
|
||||
if (gate2varref[f->node_id] == 0) {
|
||||
gate2varref[f->node_id] = getNewVar();
|
||||
gate2varcone[f->node_id] = gate2varref[f->node_id];
|
||||
}
|
||||
}
|
||||
encodeGate(obj, gate2varref[i], gate2varref);
|
||||
if (!cir.inSubcircuit(obj) && gate2varcone[i] != gate2varref[i]) {
|
||||
encodeGate(obj, gate2varcone[i], gate2varcone);
|
||||
}
|
||||
}
|
||||
}
|
||||
// --------------- 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;
|
||||
for (int i = 1; i <= cir.getNofPis(); i++) {
|
||||
if (gate2varref[i] != 0) {
|
||||
cone_input_variables.push_back(gate2varref[i]);
|
||||
}
|
||||
}
|
||||
setupEqualityConstraints(compare_nodes);
|
||||
}
|
||||
|
||||
}
|
||||
void RelationGenerator::encodeCircuitApproximativeBoundedTFI() {
|
||||
setupConstantGate();
|
||||
std::vector<int> compare_nodes = markRestrictedCone();
|
||||
std::vector<unsigned char> counts(cir.getNofObjs() - cir.getNofPos());
|
||||
int max_node = *std::max_element(compare_nodes.begin(), compare_nodes.end());
|
||||
for (int i = max_node; i > cir.getNofPis(); i--) {
|
||||
const auto obj = cir.getObj(i);
|
||||
if (gate2varref[i] != 0) {
|
||||
if (cir.inTFO(obj) || cir.inSubcircuit(obj)) {
|
||||
counts[i] = cfg.relation_tfi_bound + 1;
|
||||
} else if (counts[i] == 0) {
|
||||
cone_input_variables.push_back(gate2varref[i]);
|
||||
continue;
|
||||
}
|
||||
for (auto& f : obj.fanins ) {
|
||||
if (gate2varref[f->node_id] == 0) {
|
||||
gate2varref[f->node_id] = getNewVar();
|
||||
gate2varcone[f->node_id] = gate2varref[f->node_id];
|
||||
counts[f->node_id] = std::max(counts[f->node_id], static_cast<unsigned char>(counts[i] - 1));
|
||||
}
|
||||
}
|
||||
encodeGate(obj, gate2varref[i], gate2varref);
|
||||
if (!cir.inSubcircuit(obj) && gate2varcone[i] != gate2varref[i]) {
|
||||
encodeGate(obj, gate2varcone[i], gate2varcone);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 1; i <= cir.getNofPis(); i++) {
|
||||
if (gate2varref[i] != 0) {
|
||||
cone_input_variables.push_back(gate2varref[i]);
|
||||
}
|
||||
}
|
||||
setupEqualityConstraints(compare_nodes);
|
||||
}
|
||||
|
||||
std::vector<int> RelationGenerator::markRestrictedCone() {
|
||||
std::vector<unsigned char> counts(cir.getNofObjs() - cir.getNofPos());
|
||||
for (int i : subcir.outputs) {
|
||||
gate2varref[i] = getNewVar();
|
||||
gate2varcone[i] = getNewVar();
|
||||
counts[i] = cfg.relation_tfo_bound;
|
||||
}
|
||||
if (cfg.relation_tfo_bound == 0) {
|
||||
std::vector<int> nodes(subcir.outputs.begin(), subcir.outputs.end());
|
||||
return nodes;
|
||||
}
|
||||
std::vector<int> nodes;
|
||||
for (int i = subcir.outputs[0] + 1; i < cir.getNofObjs() - cir.getNofPos(); i++) { //outputs are ordered
|
||||
const auto obj = cir.getObj(i);
|
||||
if (!cir.inTFO(obj) || cir.inSubcircuit(obj)) {
|
||||
continue;
|
||||
}
|
||||
unsigned char x = 0;
|
||||
for (auto& f : obj.fanins) {
|
||||
x = std::max(x, counts[f->node_id]);
|
||||
}
|
||||
if (x > 0) {
|
||||
gate2varcone[i] = getNewVar();
|
||||
gate2varref[i] = getNewVar();
|
||||
counts[i] = x - 1;
|
||||
if (x == 1) {
|
||||
nodes.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::set<int> used;
|
||||
for (int i = cir.getNofObjs() - cir.getNofPos(); i < cir.getNofObjs(); i++) {
|
||||
const auto obj = cir.getObj(i);
|
||||
if (cir.inTFO(obj) && counts[obj.fanins[0]->node_id] > 0 && used.find(obj.fanins[0]->node_id) == used.end()) {
|
||||
nodes.push_back(obj.fanins[0]->node_id);
|
||||
used.insert(obj.fanins[0]->node_id);
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
void RelationGenerator::setupConstantGate() {
|
||||
int const_var = getNewVar();
|
||||
gate2varref[0] = const_var;
|
||||
gate2varcone[0] = const_var;
|
||||
solver.addClause({-const_var});
|
||||
}
|
||||
|
||||
void RelationGenerator::setupEqualityConstraints(const std::vector<int>& nodes) {
|
||||
mode_selection_variable = getNewVar();
|
||||
std::vector<int> one_different {-mode_selection_variable};
|
||||
for (int cnd : nodes) {
|
||||
int eq_var = getNewVar();
|
||||
equality_variables.push_back(eq_var);
|
||||
getEqualityClauses(gate2varref[cnd], gate2varcone[cnd], eq_var);
|
||||
one_different.push_back(-eq_var);
|
||||
}
|
||||
solver.addClause(one_different);
|
||||
}
|
||||
|
||||
|
||||
void RelationGenerator::getEqualityClauses(int x, int y, int aux) {
|
||||
solver.addClause({x, -y, -aux});
|
||||
solver.addClause({-x, y, -aux});
|
||||
solver.addClause({x, y, aux});
|
||||
solver.addClause({-x, -y, aux});
|
||||
}
|
||||
|
||||
int RelationGenerator::findConflict(double& timeout, int mode_selection) {
|
||||
abctime time_start = Abc_Clock();
|
||||
int solver_status = solver.solve(timeout, {mode_selection});
|
||||
double solver_time = (double)1.0*(Abc_Clock() - time_start)/CLOCKS_PER_SEC;
|
||||
log.cummulative_sat_runtime_relation_generation += solver_time;
|
||||
log.max_sat_runtime_relation_generation = std::max(log.max_sat_runtime_relation_generation, solver_time);
|
||||
// log.cummulative_sat_runtime_relation_generation += solver.getRunTime();
|
||||
log.nof_sat_calls_relation_generation++;
|
||||
return solver_status;
|
||||
}
|
||||
|
||||
int RelationGenerator::reduceConflict(double& timeout, const std::vector<int>& cone_input,
|
||||
const std::vector<int>& subcircuit_output, const std::vector<int>& equality) {
|
||||
solver.assume(cone_input);
|
||||
solver.assume(subcircuit_output);
|
||||
solver.assume(equality);
|
||||
abctime time_start = Abc_Clock();
|
||||
int status = solver.solve(timeout);
|
||||
double solver_time = (double)1.0*(Abc_Clock() - time_start)/CLOCKS_PER_SEC;
|
||||
log.cummulative_sat_runtime_relation_generation += solver_time;
|
||||
log.max_sat_runtime_relation_generation = std::max(log.max_sat_runtime_relation_generation, solver_time);
|
||||
// log.cummulative_sat_runtime_relation_generation += solver.getRunTime();
|
||||
log.nof_sat_calls_relation_generation++;
|
||||
return status;
|
||||
}
|
||||
|
||||
Relation RelationGenerator::getRelation() {
|
||||
std::vector<int> subcircuit_input_variables;
|
||||
subcircuit_input_variables.reserve(subcir.inputs.size());
|
||||
for (int sin : subcir.inputs) {
|
||||
int var = gate2varcone[sin];
|
||||
subcircuit_input_variables.push_back(var);
|
||||
}
|
||||
std::vector<int> subcircuit_output_variables;
|
||||
subcircuit_output_variables.reserve(subcir.outputs.size());
|
||||
// outputs in forbidden pairs must not removed
|
||||
std::vector<bool> outputs_to_keep(subcir.outputs.size(), false);
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
int sout = subcir.outputs[i];
|
||||
int var = gate2varcone[sout];
|
||||
subcircuit_output_variables.push_back(var);
|
||||
if (subcir.forbidden_pairs.find(sout) != subcir.forbidden_pairs.end()) {
|
||||
outputs_to_keep[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Relation rel(subcir.inputs.size());
|
||||
|
||||
int solver_status;
|
||||
double timeout = cfg.relation_generation_timeout;
|
||||
abctime time_start = Abc_Clock();
|
||||
while( (solver_status=findConflict(timeout, mode_selection_variable)) == 10) {
|
||||
timeout -= (double)1.0*(Abc_Clock() - time_start)/CLOCKS_PER_SEC;
|
||||
time_start = Abc_Clock();
|
||||
if (timeout <= 0) {
|
||||
rel.status = false;
|
||||
return rel;
|
||||
}
|
||||
std::vector<int> cone_in_assm = solver.getValues(cone_input_variables);
|
||||
std::vector<int> sin_assm = solver.getValues(subcircuit_input_variables);
|
||||
std::vector<int> sout_assm = solver.getValues(subcircuit_output_variables);
|
||||
int status = reduceConflict(timeout, cone_in_assm, sout_assm, equality_variables);
|
||||
if (status != 20) {
|
||||
assert (status != 10);
|
||||
rel.status = false;
|
||||
return rel;
|
||||
}
|
||||
assert (status == 20);
|
||||
std::vector<int> blocking_clause {-mode_selection_variable};
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
blocking_clause.push_back(-sin_assm[i]);
|
||||
}
|
||||
std::vector<bool> pattern (2*subcir.outputs.size(), false);
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
if (solver.isFailed(sout_assm[i]) || outputs_to_keep[i]) {
|
||||
pattern[2*i] = true;
|
||||
pattern[2*i + 1] = sout_assm[i] < 0; // at least one output must be assigned differently in order to preserve the function
|
||||
blocking_clause.push_back(-sout_assm[i]);
|
||||
}
|
||||
}
|
||||
solver.addClause(blocking_clause);
|
||||
rel.addOutputPattern(assignment2bvindex(sin_assm), std::move(pattern));
|
||||
}
|
||||
if (solver_status != 20) {
|
||||
rel.status = false;
|
||||
}
|
||||
return rel;
|
||||
}
|
||||
|
||||
int RelationGenerator::assignment2bvindex(const std::vector<int>& assm) {
|
||||
int idx = 0;
|
||||
for (int i = 0; i < assm.size(); i++) {
|
||||
if (assm[i] > 0) {
|
||||
idx |= 1 << i;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -6,190 +6,114 @@
|
|||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Procedures for computing Boolean relations.]
|
||||
Synopsis [SAT-based computation of Boolean relations.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: relationGeneration.hpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__RELATIONGENERATION_h
|
||||
#define ABC__OPT__ESLIM__RELATIONGENERATION_h
|
||||
#ifndef ABC__OPT__ESLIM__RELATIONGENERATION_hpp
|
||||
#define ABC__OPT__ESLIM__RELATIONGENERATION_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
#include <misc/util/abc_global.h>
|
||||
#include "aig/gia/gia.h"
|
||||
#include "misc/util/utilTruth.h" // ioResub.h depends on utilTruth.h
|
||||
#include "base/io/ioResub.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "cadicalSolver.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
#include "utils.hpp"
|
||||
// #include "satInterfaces.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace eSLIM {
|
||||
|
||||
template<class Derived>
|
||||
class RelationGenerator {
|
||||
class RelationGenerator;
|
||||
|
||||
class Relation{
|
||||
|
||||
public:
|
||||
static Abc_RData_t* computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir);
|
||||
|
||||
Relation(int nfanins);
|
||||
const std::vector<std::vector<bool>>& getPattern(int id) const {return output_patterns[id];}
|
||||
int getNPatterns() const {return output_patterns.size();}
|
||||
int getPatternSize(int id) const {return output_patterns[id].size();}
|
||||
unsigned int getNLinesWithPattern() const {return lines_with_pattern;}
|
||||
bool getStatus() const {return status;}
|
||||
|
||||
|
||||
private:
|
||||
Gia_Man_t* pGia;
|
||||
const Subcircuit& subcir;
|
||||
|
||||
RelationGenerator(Gia_Man_t* pGia, const Subcircuit& subcir);
|
||||
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 );
|
||||
|
||||
// Each entry of the first vector level corresponds to an input assignment.
|
||||
// The second level lists all conflicting output assignments.
|
||||
// The third lists the individual conflicting output assignments.
|
||||
// One output is represented by two bits, the first bit determines if this output is present the conflicting output assignments
|
||||
// and the second indicate if it is true or false
|
||||
void addOutputPattern(int inputidx, std::vector<bool>&& pattern);
|
||||
std::vector<std::vector<std::vector<bool>>> output_patterns;
|
||||
|
||||
friend Derived;
|
||||
};
|
||||
unsigned int lines_with_pattern = 0;
|
||||
bool status = true;
|
||||
|
||||
// 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<RelationGeneratorABC> {
|
||||
|
||||
private:
|
||||
RelationGeneratorABC(Gia_Man_t* pGia, const Subcircuit& subcir);
|
||||
void setupImpl() {};
|
||||
Vec_Int_t* getRelationImpl();
|
||||
Gia_Man_t * generateMiter();
|
||||
|
||||
std::unordered_set<int> inputs_in_forbidden_pairs;
|
||||
|
||||
friend RelationGenerator;
|
||||
};
|
||||
|
||||
class RelationGenerator {
|
||||
|
||||
// Add other engine for the generation of relations
|
||||
// class MyRelationGenerator : public RelationGenerator<MyRelationGenerator> {
|
||||
// private:
|
||||
// void setupImpl()
|
||||
// Vec_Int_t* getRelationImpl();
|
||||
// friend RelationGenerator;
|
||||
// };
|
||||
public:
|
||||
static Relation computeRelation(const eSLIMCirMan& cir, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
private:
|
||||
const eSLIMCirMan& cir;
|
||||
const Subcircuit& subcir;
|
||||
|
||||
const eSLIMConfig& cfg;
|
||||
eSLIMLog& log;
|
||||
|
||||
int max_var = 1;
|
||||
|
||||
std::vector<int> gate2varref;
|
||||
std::vector<int> gate2varcone;
|
||||
std::vector<int> equality_variables;
|
||||
std::vector<int> cone_input_variables;
|
||||
int mode_selection_variable;
|
||||
|
||||
|
||||
CadicalSolver solver;
|
||||
|
||||
RelationGenerator(const eSLIMCirMan& cir, const Subcircuit& subcir, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
void setupEncoding();
|
||||
|
||||
void encodeCircuitAffected();
|
||||
void encodeCircuitApproximative();
|
||||
void encodeCircuitApproximativeBoundedTFI();
|
||||
std::vector<int> markRestrictedCone();
|
||||
void setupConstantGate();
|
||||
void setupEqualityConstraints(const std::vector<int>& nodes);
|
||||
|
||||
Relation getRelation();
|
||||
|
||||
void encodeGate(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var);
|
||||
void getGateEncodingUnique(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var, bool unique_bit);
|
||||
void getGateEncodingNaive(const eSLIMCirObj& obj, int var, const std::vector<int>& gate2var);
|
||||
void getEqualityClauses(int x, int y, int aux);
|
||||
int assignment2bvindex(const std::vector<int>& assm);
|
||||
|
||||
int findConflict(double& timeout, int mode_selection);
|
||||
int reduceConflict(double& timeout, const std::vector<int>& cone_input, const std::vector<int>& subcircuit_output, const std::vector<int>& equality);
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline RelationGenerator<T>::RelationGenerator(Gia_Man_t* pGia, const Subcircuit& subcir)
|
||||
: pGia(pGia), subcir(subcir) {
|
||||
}
|
||||
int getNewVar();
|
||||
|
||||
template <typename T>
|
||||
inline Abc_RData_t* RelationGenerator<T>::computeRelation(Gia_Man_t* gia_man, const Subcircuit& subcir) {
|
||||
T generator(gia_man, subcir);
|
||||
generator.setup();
|
||||
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 <typename T>
|
||||
inline Abc_RData_t* RelationGenerator<T>::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 <typename T>
|
||||
inline Abc_RData_t * RelationGenerator<T>::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 <typename T>
|
||||
inline void RelationGenerator<T>::setup() {
|
||||
static_cast<T*>(this)->setupImpl();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Vec_Int_t* RelationGenerator<T>::getRelation() {
|
||||
return static_cast<T*>(this)->getRelationImpl();
|
||||
}
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -0,0 +1,612 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [relationSynthesiser.cpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Base class for SAT-based synthesis]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "relationSynthesiser.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
namespace eSLIM {
|
||||
|
||||
RelationSynthesiser::RelationSynthesiser(const Relation& relation, const Subcircuit& subcir, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: relation(relation), subcir(subcir),
|
||||
max_size(max_size), config(cfg), log(log) {
|
||||
setupEncoding();
|
||||
}
|
||||
|
||||
double RelationSynthesiser::getDynamicTimeout(int size) {
|
||||
if (log.nof_sat_calls_per_size[size] > config.minimum_dynamic_timeout_sample_size) {
|
||||
return std::max(static_cast<double>(config.minimum_sat_timeout), static_cast<double>(log.cummulative_sat_runtimes_per_size[size]) / (1000*log.nof_sat_calls_per_size[size])); //logged timings are given in ms
|
||||
} else {
|
||||
return config.base_sat_timeout;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int RelationSynthesiser::getSizeFromActivationVars(const std::vector<bool>& model) {
|
||||
unsigned int sz = 0;
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
if (model[gate_activation_variables[i]]) {
|
||||
sz++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
unsigned int RelationSynthesiser::getSizeFromActivationVars() {
|
||||
unsigned int sz = 0;
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
if (solver.getValue(gate_activation_variables[i])) {
|
||||
sz++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void RelationSynthesiser::logRun(int status, unsigned int size) {
|
||||
log.cummulative_sat_runtime_synthesis += solver.getRunTime();
|
||||
log.max_sat_runtime_synthesis = std::max(log.max_sat_runtime_synthesis, solver.getRunTime());
|
||||
|
||||
log.nof_sat_calls_synthesis++;
|
||||
if (status == 10) {
|
||||
log.cummulative_sat_runtimes_per_size[size] += solver.getRunTime();
|
||||
log.nof_sat_calls_per_size[size] ++;
|
||||
} else if (status == 20) { //if the solver does not report sat the formula is unsat or there was a timeout
|
||||
log.cummulative_unsat_runtimes_per_size[size] += solver.getRunTime();
|
||||
log.nof_unsat_calls_per_size[size] ++;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> RelationSynthesiser::getSizeAssumption(int size) {
|
||||
std::vector<int> assumptions;
|
||||
assumptions.reserve(max_size - size);
|
||||
for (int i = size; i < max_size; i++) {
|
||||
assumptions.push_back(-gate_activation_variables[i]);
|
||||
}
|
||||
return assumptions;
|
||||
}
|
||||
|
||||
eSLIMCirMan RelationSynthesiser::getReplacement(const std::vector<bool>& model, int size) {
|
||||
assert (model.size() > 0);
|
||||
eSLIMCirMan circ(subcir.inputs.size() + subcir.outputs.size() + size);
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
circ.addPi();
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::vector<int> fanins;
|
||||
for (int j = 0; j < selection_variables[i].size(); j++) {
|
||||
if (model[selection_variables[i][j]]) {
|
||||
fanins.push_back(j+1);
|
||||
}
|
||||
}
|
||||
ABC_UINT64_T tt = 0;
|
||||
for (int j = 0; j < gate_definition_variables[i].size(); j++) {
|
||||
int idx = j + 1;
|
||||
if (model[gate_definition_variables[i][j]]) {
|
||||
tt |= static_cast<ABC_UINT64_T>(1) << idx;
|
||||
}
|
||||
}
|
||||
circ.addNode(fanins, tt);
|
||||
}
|
||||
|
||||
// outputs
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
for (int j = 0; j < max_size; j++) {
|
||||
if (model[gate_output_variables[j][i]]) {
|
||||
circ.addPo(subcir.inputs.size() + j + 1, false);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < subcir.inputs.size(); j++) {
|
||||
if (model[gate_output_variables[max_size + j][i]]) {
|
||||
circ.addPo(j + 1, false);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (model[gate_output_variables.back()[i]]) {
|
||||
circ.addPo(0, false);
|
||||
}
|
||||
end:;
|
||||
}
|
||||
return circ;
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupEncoding() {
|
||||
setupVariables();
|
||||
setupStructuralConstraints();
|
||||
setupSymmetryBreaking();
|
||||
setupEquivalenceConstraints();
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupVariables() {
|
||||
gate_activation_variables.reserve(max_size);
|
||||
selection_variables.reserve(max_size);
|
||||
gate_definition_variables.reserve(max_size);
|
||||
gate_variables.reserve(max_size);
|
||||
is_ith_fanin_variable.reserve(max_size);
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
gate_activation_variables.push_back(getNewVariable());
|
||||
selection_variables.push_back(getNewVariableVector(subcir.inputs.size() + i));
|
||||
gate_definition_variables.push_back(getNewVariableVector(pow2(config.gate_size) - 1));
|
||||
// The replacement circuit shall be normal so we ignore the all-false-behaviour
|
||||
int normality_offset = relation.getPatternSize(0) > 0;
|
||||
gate_variables.push_back(getNewVariableVector(relation.getNLinesWithPattern() - normality_offset));
|
||||
|
||||
std::vector<std::vector<int>> fanin_vars;
|
||||
for (int j = 0; j < config.gate_size; j++) {
|
||||
std::vector<int> fvs(subcir.inputs.size() + i, 0);
|
||||
for (int k = j; k < subcir.inputs.size() + i - config.gate_size + j + 1; k++) {
|
||||
fvs[k] = getNewVariable();
|
||||
}
|
||||
fanin_vars.push_back(fvs);
|
||||
}
|
||||
is_ith_fanin_variable.push_back(fanin_vars);
|
||||
}
|
||||
gate_output_variables.reserve(max_size + subcir.inputs.size() + 1);
|
||||
for (int i = 0; i < max_size + subcir.inputs.size() + 1; i++) {
|
||||
gate_output_variables.push_back(getNewVariableVector(subcir.outputs.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupStructuralConstraints() {
|
||||
constrainSelectionVariables();
|
||||
constraintGateOutputVariables();
|
||||
setupActivationCompatibilityConstraints();
|
||||
if (config.aig) {
|
||||
setupAigerConstraints();
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupSymmetryBreaking() {
|
||||
addNonTrivialConstraint();
|
||||
addUseAllStepsConstraint();
|
||||
// addNoReapplicationConstraint();
|
||||
// addOrderedStepsConstraint();
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupIsFaninVariables(int gtidx, const std::vector<std::vector<int>>& counter_vars) {
|
||||
// If we have 3 inputs and gates with two fanins then the first fanin of the first gate can be input 1 or 2 but not input 3.
|
||||
int noptions = subcir.inputs.size() + gtidx - config.gate_size + 1;
|
||||
for (int i = 0; i < config.gate_size; i++) {
|
||||
solver.addClause({-counter_vars[i][i], is_ith_fanin_variable[gtidx][i][i]});
|
||||
solver.addClause({counter_vars[i][i], -is_ith_fanin_variable[gtidx][i][i]});
|
||||
int offset = (i == config.gate_size - 1); // we do not use block variables for the last selection variables
|
||||
for (int j = i + 1; j < i + noptions - offset; j++) {
|
||||
solver.addClause({counter_vars[j - 1][i], counter_vars[j][i], -is_ith_fanin_variable[gtidx][i][j]});
|
||||
solver.addClause({counter_vars[j - 1][i], -counter_vars[j][i], is_ith_fanin_variable[gtidx][i][j]});
|
||||
}
|
||||
}
|
||||
solver.addClause({selection_variables[gtidx].back(), -is_ith_fanin_variable[gtidx].back().back()});
|
||||
solver.addClause({-selection_variables[gtidx].back(), is_ith_fanin_variable[gtidx].back().back()});
|
||||
}
|
||||
|
||||
void RelationSynthesiser::constrainSelectionVariables() {
|
||||
int start = 0;
|
||||
// if the subcircuit has k inputs and gates have k fanins each input is a fanin of the first gate
|
||||
if (selection_variables[0].size() == config.gate_size) {
|
||||
start = 1;
|
||||
for (int j = 0; j < config.gate_size; j++) {
|
||||
solver.addClause({selection_variables[0][j]});
|
||||
solver.addClause({is_ith_fanin_variable[0][j][j]});
|
||||
}
|
||||
}
|
||||
for (int i = start; i < max_size; i++) {
|
||||
std::vector<std::vector<int>> counter_vars = addSequentialCounter(selection_variables[i], config.gate_size);
|
||||
setupIsFaninVariables(i, counter_vars);
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::constraintGateOutputVariables() {
|
||||
// If the activation variable is false then the gate must not be an output
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
for (int v : gate_output_variables[i]) {
|
||||
solver.addClause({gate_activation_variables[i], -v});
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < subcir.outputs.size(); i++) {
|
||||
std::vector<int> clause;
|
||||
clause.reserve(max_size + subcir.inputs.size() + 1);
|
||||
for (int j = 0; j < max_size + subcir.inputs.size() + 1; j++) {
|
||||
clause.push_back(gate_output_variables[j][i]);
|
||||
}
|
||||
addCardinalityConstraint(clause, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::addGateValueConstraint(int gtidx, int gt_val, const std::vector<int>& fanin_variables) {
|
||||
// If all fanins are 0, then the gate yields 0
|
||||
std::vector<int> clause {-gate_activation_variables[gtidx]};
|
||||
clause.reserve(config.gate_size + 3);
|
||||
for (int j = 0; j < config.gate_size; j++) {
|
||||
clause.push_back(fanin_variables[j]);
|
||||
}
|
||||
clause.push_back(-gt_val);
|
||||
solver.addClause(clause);
|
||||
clause.push_back(0);
|
||||
|
||||
for (int i = 1; i < pow2(config.gate_size); i++) { // we consider normal gates -> the all-0-behaviour does not need to be considered
|
||||
for (int j = 0; j < config.gate_size; j++) {
|
||||
clause[j + 1] = abs(clause[j + 1]) * (1-2*getTTValue(i, j));
|
||||
}
|
||||
int gdv = gate_definition_variables[gtidx][i - 1]; // we do not use a gdv for the all-0-behaviour
|
||||
clause[config.gate_size + 1] = -gdv;
|
||||
clause[config.gate_size + 2] = gt_val;
|
||||
solver.addClause(clause);
|
||||
clause[config.gate_size + 1] = gdv;
|
||||
clause[config.gate_size + 2] = -gt_val;
|
||||
solver.addClause(clause);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> RelationSynthesiser::setupFaninVariables(int gtidx, int tt_line, int pidx) {
|
||||
int noptions = subcir.inputs.size() + gtidx - config.gate_size + 1;
|
||||
std::vector<int> fanin_variables = getNewVariableVector(config.gate_size);
|
||||
for (int i = 0; i < config.gate_size; i++) {
|
||||
int bound = i + noptions < subcir.inputs.size() ? i + noptions : subcir.inputs.size();
|
||||
for (int j = i; j < bound; j++) {
|
||||
if (getTTValue(tt_line, j)) {
|
||||
solver.addClause({-is_ith_fanin_variable[gtidx][i][j], fanin_variables[i]});
|
||||
} else {
|
||||
solver.addClause({-is_ith_fanin_variable[gtidx][i][j], -fanin_variables[i]});
|
||||
}
|
||||
}
|
||||
for (int j = subcir.inputs.size(); j < i + noptions; j++) {
|
||||
solver.addClause({-is_ith_fanin_variable[gtidx][i][j], gate_variables[j - subcir.inputs.size()][pidx], -fanin_variables[i]});
|
||||
solver.addClause({-is_ith_fanin_variable[gtidx][i][j], -gate_variables[j - subcir.inputs.size()][pidx], fanin_variables[i]});
|
||||
}
|
||||
}
|
||||
return fanin_variables;
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupGateValues() {
|
||||
int pidx = 0;
|
||||
for (int i = 1; i < relation.getNPatterns(); i++) {
|
||||
if (relation.getPatternSize(i) > 0) {
|
||||
for (int j = 0; j < max_size; j++) {
|
||||
std::vector<int> fanin_variables = setupFaninVariables(j, i, pidx);
|
||||
addGateValueConstraint(j, gate_variables[j][pidx], fanin_variables);
|
||||
}
|
||||
pidx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupEquivalenceConstraints() {
|
||||
setupGateValues();
|
||||
// normal circuit: all-0-behaviour is ignored
|
||||
int pidx = 0;
|
||||
for (int i = 1; i < relation.getNPatterns(); i++) {
|
||||
std::vector<int> output_vars (subcir.outputs.size(), 0);
|
||||
const auto& patterns = relation.getPattern(i);
|
||||
for (const auto& p : patterns) {
|
||||
assert(2 * subcir.outputs.size() == p.size());
|
||||
std::vector<int> cl;
|
||||
for (int j = 0; j < subcir.outputs.size(); j++) {
|
||||
if (p[2*j]) {
|
||||
if (output_vars[j] == 0) {
|
||||
output_vars[j] = setupOutputVariable(j, i, pidx);
|
||||
}
|
||||
if (p[2*j + 1]) {
|
||||
cl.push_back(output_vars[j]);
|
||||
} else {
|
||||
cl.push_back(-output_vars[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
solver.addClause(cl);
|
||||
}
|
||||
pidx += !patterns.empty();
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupActivationCompatibilityConstraints() {
|
||||
for (int i = 1; i < max_size; i++) {
|
||||
solver.addClause({-gate_activation_variables[i], gate_activation_variables[i-1]});
|
||||
}
|
||||
}
|
||||
|
||||
int RelationSynthesiser::setupOutputVariable(int output_index, int tt_index, int pattern_idx) {
|
||||
int var = getNewVariable();
|
||||
std::vector<int> clause;
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
clause.assign({-gate_activation_variables[i], -gate_output_variables[i][output_index], -gate_variables[i][pattern_idx], var});
|
||||
solver.addClause(clause);
|
||||
clause[2] = -clause[2];
|
||||
clause[3] = -clause[3];
|
||||
solver.addClause(clause);
|
||||
}
|
||||
|
||||
for (int i = 0; i < subcir.inputs.size(); i++) {
|
||||
if (getTTValue(tt_index, i)) {
|
||||
clause.assign({-gate_output_variables[i + max_size][output_index], var});
|
||||
} else {
|
||||
clause.assign({-gate_output_variables[i + max_size][output_index], -var});
|
||||
}
|
||||
solver.addClause(clause);
|
||||
}
|
||||
|
||||
clause.assign({-gate_output_variables.back()[output_index], -var});
|
||||
solver.addClause(clause);
|
||||
return var;
|
||||
}
|
||||
|
||||
void RelationSynthesiser::setupAigerConstraints() {
|
||||
assert (config.gate_size == 2);
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
solver.addClause({-gate_definition_variables[i][0], -gate_definition_variables[i][1], gate_definition_variables[i][2]});
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::addCardinalityConstraint(const std::vector<int>& vars, unsigned int cardinality, int activator) {
|
||||
assert (cardinality > 0);
|
||||
assert (vars.size() >= cardinality);
|
||||
if (vars.size() == cardinality) {
|
||||
std::vector<int> clause;
|
||||
if (activator != 0) {
|
||||
clause.push_back(activator);
|
||||
}
|
||||
for (int var : vars) {
|
||||
clause.push_back(var);
|
||||
solver.addClause(clause);
|
||||
clause.pop_back();
|
||||
}
|
||||
} else {
|
||||
// CHECK: is the naive encoding better?
|
||||
if (activator == 0) {
|
||||
if (cardinality == 1) {
|
||||
addNaiveIs1CardinalityConstraint(vars);
|
||||
} else if (cardinality == 2) {
|
||||
addNaiveIs2CardinalityConstraint(vars);
|
||||
} else {
|
||||
addSequentialCounter(vars, cardinality, activator);
|
||||
}
|
||||
} else {
|
||||
addSequentialCounter(vars, cardinality, activator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see Carsten Sinz: Towards an Optimal CNF Encoding of Boolean Cardinality Constraints
|
||||
// As we want that exactly cardinality many variables are set to true we need additional constraints.
|
||||
// Because of this reason we cannot use the single polarity encoding presented in the paper
|
||||
std::vector<std::vector<int>> RelationSynthesiser::addSequentialCounter(const std::vector<int>& vars, unsigned int cardinality, int activator) {
|
||||
std::vector<std::vector<int>> component_outputs;
|
||||
component_outputs.push_back({vars.front()});
|
||||
assert (vars.size() > cardinality);
|
||||
for (int i = 1; i < vars.size() - 1; i++) {
|
||||
std::vector<int> current_component_outputs;
|
||||
int v = vars[i];
|
||||
int in_var = v;
|
||||
for (int j = 0; j < component_outputs.back().size(); j++) {
|
||||
int orv = getNewVariable();
|
||||
defineDisjunction(orv, {in_var, component_outputs.back()[j]}, activator);
|
||||
current_component_outputs.push_back(orv);
|
||||
if (j < cardinality - 1) {
|
||||
in_var = getNewVariable();
|
||||
defineConjunction(in_var, {v, component_outputs.back()[j]}, activator);
|
||||
} else {
|
||||
solver.addClause({-component_outputs.back().back(), -v});
|
||||
}
|
||||
}
|
||||
if (component_outputs.back().size() < cardinality) {
|
||||
current_component_outputs.push_back(in_var);
|
||||
}
|
||||
component_outputs.push_back(current_component_outputs);
|
||||
}
|
||||
|
||||
solver.addClause({-component_outputs.back().back(), -vars.back()});
|
||||
|
||||
// Either subcircuit_outputs.back() is true or subcircuit_outputs[-2] and vars.back() is true
|
||||
std::vector<int> clause {component_outputs.back().back(), vars.back()};
|
||||
solver.addClause(clause);
|
||||
if (cardinality > 1) {
|
||||
clause.pop_back();
|
||||
clause.push_back(component_outputs.back()[component_outputs.back().size() - 2]);
|
||||
solver.addClause(clause);
|
||||
}
|
||||
return component_outputs;
|
||||
}
|
||||
|
||||
void RelationSynthesiser::addNaiveIs1CardinalityConstraint(const std::vector<int>& vars) {
|
||||
solver.addClause(vars);
|
||||
for (int i = 0; i < vars.size(); i++) {
|
||||
for (int j = i + 1; j < vars.size(); j++) {
|
||||
solver.addClause({-vars[i], -vars[j]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::addNaiveIs2CardinalityConstraint(const std::vector<int>& vars) {
|
||||
std::vector<int> cl;
|
||||
cl.reserve(vars.size() - 1);
|
||||
for (int i = 0; i < vars.size(); i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
cl.push_back(vars[j]);
|
||||
}
|
||||
for (int j = i + 1; j < vars.size(); j++) {
|
||||
cl.push_back(vars[j]);
|
||||
}
|
||||
solver.addClause(cl);
|
||||
cl.clear();
|
||||
|
||||
for (int j = i + 1; j < vars.size(); j++) {
|
||||
for (int k = j + 1; k < vars.size(); k++) {
|
||||
solver.addClause({-vars[i], -vars[j], -vars[k]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::defineConjunction(int var, std::vector<int>&& literals, int activator) {
|
||||
std::vector<int> big_clause, small_clause;
|
||||
if (activator != 0) {
|
||||
big_clause.reserve(literals.size() + 2);
|
||||
small_clause.reserve(3);
|
||||
big_clause.push_back(activator);
|
||||
small_clause.push_back(activator);
|
||||
} else {
|
||||
big_clause.reserve(literals.size() + 1);
|
||||
small_clause.reserve(2);
|
||||
}
|
||||
big_clause.push_back(var);
|
||||
small_clause.push_back(-var);
|
||||
for (int lit : literals) {
|
||||
big_clause.push_back(-lit);
|
||||
small_clause.push_back(lit);
|
||||
solver.addClause(small_clause);
|
||||
small_clause.pop_back();
|
||||
}
|
||||
solver.addClause(big_clause);
|
||||
}
|
||||
|
||||
void RelationSynthesiser::defineDisjunction(int var, std::vector<int>&& literals, int activator) {
|
||||
std::vector<int> clause;
|
||||
literals.push_back(-var);
|
||||
if (activator != 0) {
|
||||
literals.push_back(activator);
|
||||
solver.addClause(literals);
|
||||
literals.pop_back();
|
||||
clause.reserve(3);
|
||||
clause.push_back(activator);
|
||||
} else {
|
||||
clause.reserve(2);
|
||||
solver.addClause(literals);
|
||||
}
|
||||
literals.pop_back();
|
||||
clause.push_back(var);
|
||||
for (int lit : literals) {
|
||||
clause.push_back(-lit);
|
||||
solver.addClause(clause);
|
||||
clause.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void RelationSynthesiser::addNonTrivialConstraint() {
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
// We do not allow constant gates
|
||||
solver.addClause(gate_definition_variables[i]);
|
||||
// We exclude gates representing the projection to one of its inputs
|
||||
for (int j = 0; j < config.gate_size; j++) {
|
||||
int start = pow2(config.gate_size - j);
|
||||
int block_length = pow2(config.gate_size - j - 1);
|
||||
std::vector<int> clause;
|
||||
clause.reserve(pow2(config.gate_size) - 1);
|
||||
for (int k = 0; k < pow2(j); k++) {
|
||||
for (int l = k * start - (k == 0 ? 0 : 1); l < k * start + block_length -1; l++) {
|
||||
clause.push_back(gate_definition_variables[i][l]);
|
||||
}
|
||||
for (int l = k * start + block_length - 1; l < (k + 1) * start - 1; l++) {
|
||||
clause.push_back(-gate_definition_variables[i][l]);
|
||||
}
|
||||
}
|
||||
solver.addClause(clause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Every gate is either an output or an input of another gate
|
||||
void RelationSynthesiser::addUseAllStepsConstraint() {
|
||||
for (int i = 0; i < max_size; i++) {
|
||||
std::vector<int> clause (gate_output_variables[i].begin(), gate_output_variables[i].end());
|
||||
clause.reserve(max_size - i + 1);
|
||||
for (int j = i + 1; j < max_size; j++) {
|
||||
clause.push_back(selection_variables[j][subcir.inputs.size() + i]);
|
||||
}
|
||||
clause.push_back(-gate_activation_variables[i]);
|
||||
solver.addClause(clause);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Suppose gate i has inputs i1,...,in and gate j uses i as an input.
|
||||
// Then the other n-1 inputs of j shall not be contained in the inputs of i.
|
||||
// Otherwise j could be directly represented by a gate with inputs i1,...,in
|
||||
void RelationSynthesiser::addNoReapplicationConstraint() {
|
||||
std::vector<bool> filter(config.gate_size, 1);
|
||||
// A 1 at index i indicates that the ith node is used as an input.
|
||||
// By using prev_permutation we get all possible permutations of the filter
|
||||
filter.resize(subcir.inputs.size() + max_size - 1);
|
||||
std::vector<int> indices(config.gate_size,0);
|
||||
// int tt_size = RelationSynthesiser::pow2(subcir.inputs.size()) - 1;
|
||||
do {
|
||||
indices.clear();
|
||||
for (int i = 0; i < subcir.inputs.size() + max_size - 1; i++) {
|
||||
if (filter[i]) {
|
||||
indices.push_back(i);
|
||||
}
|
||||
}
|
||||
int first_gate = getPotentialSuccessors(indices);
|
||||
for (int i = first_gate; i < max_size; i++) {
|
||||
std::vector<int> clause;
|
||||
clause.reserve(subcir.inputs.size() + max_size);
|
||||
for (int idx : indices) {
|
||||
clause.push_back(-selection_variables[i][idx]);
|
||||
}
|
||||
int start_with = clause.size();
|
||||
for (int j = i + 1; j < max_size; j++) {
|
||||
// gate j has inputs.size() + j potential inputs
|
||||
clause.resize(subcir.inputs.size() + j + 1, 0);
|
||||
clause[start_with] = -selection_variables[j][subcir.inputs.size() + i];
|
||||
clause[start_with + 1] = -gate_activation_variables[j];
|
||||
int k = 0, l = 0, m = 0;
|
||||
// while (k < inputs.size() + j && l < indices.size()) {
|
||||
while (k < subcir.inputs.size() + j) {
|
||||
if (l >= indices.size() || k < indices[l]) {
|
||||
if (k != subcir.inputs.size() + i) {
|
||||
clause[start_with + m + 2] = selection_variables[j][k];
|
||||
m++;
|
||||
}
|
||||
k++;
|
||||
} else if (k > indices[l]) {
|
||||
l++;
|
||||
} else {
|
||||
k++;
|
||||
l++;
|
||||
}
|
||||
}
|
||||
solver.addClause(clause);
|
||||
}
|
||||
}
|
||||
} while (std::prev_permutation(filter.begin(), filter.end()));
|
||||
}
|
||||
|
||||
// Order steps according to their inputs.
|
||||
// If step i has input j then step i+1 must have an input >=j
|
||||
void RelationSynthesiser::addOrderedStepsConstraint() {
|
||||
for (int i = 0; i < max_size - 1; i++) {
|
||||
for (int j = 0; j < subcir.inputs.size() + i; j++) {
|
||||
std::vector<int> clause {-gate_activation_variables[i+1], -selection_variables[i][j]};
|
||||
clause.reserve(subcir.inputs.size() + i - j + 3);
|
||||
for (int k = j; k < subcir.inputs.size() + i + 1; k++) {
|
||||
clause.push_back(selection_variables[i+1][k]);
|
||||
}
|
||||
solver.addClause(clause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [relationSynthesiser.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Base class for SAT-based synthesis]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__RELATIONSYNTHESISER_hpp
|
||||
#define ABC__OPT__ESLIM__RELATIONSYNTHESISER_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#include "relationGeneration.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
#include "cadicalSolver.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class RelationSynthesiser {
|
||||
|
||||
protected:
|
||||
CadicalSolver solver;
|
||||
const Subcircuit& subcir;
|
||||
unsigned int max_size; // The maximal circuit size that can be checked
|
||||
|
||||
std::vector<int> gate_activation_variables;
|
||||
std::vector<std::vector<int>> selection_variables;
|
||||
std::vector<std::vector<int>> gate_output_variables;
|
||||
|
||||
RelationSynthesiser(const Relation& relation, const Subcircuit& subcir, unsigned int max_size, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
int getNewVariable();
|
||||
std::vector<int> getNewVariableVector(unsigned int size);
|
||||
|
||||
std::vector<int> getSizeAssumption(int size);
|
||||
double getDynamicTimeout(int size);
|
||||
unsigned int getSizeFromActivationVars(const std::vector<bool>& model);
|
||||
unsigned int getSizeFromActivationVars();
|
||||
void logRun(int status, unsigned int size);
|
||||
eSLIMCirMan getReplacement(const std::vector<bool>& model, int size);
|
||||
|
||||
|
||||
private:
|
||||
const Relation& relation;
|
||||
const eSLIMConfig& config;
|
||||
eSLIMLog& log;
|
||||
|
||||
int max_var = 0; // The maximal variable occurring in inputs/outputs
|
||||
|
||||
std::vector<std::vector<std::vector<int>>> is_ith_fanin_variable;
|
||||
std::vector<std::vector<int>> gate_definition_variables;
|
||||
std::vector<std::vector<int>> gate_variables;
|
||||
|
||||
|
||||
void setupEncoding();
|
||||
void setupVariables();
|
||||
void setupStructuralConstraints();
|
||||
|
||||
void setupSymmetryBreaking();
|
||||
void setupGateValues();
|
||||
std::vector<int> setupFaninVariables(int gtidx, int tt_line, int pidx);
|
||||
void setupEquivalenceConstraints();
|
||||
void setupActivationCompatibilityConstraints();
|
||||
void setupIsFaninVariables(int gtidx, const std::vector<std::vector<int>>& counter_vars);
|
||||
|
||||
void constrainSelectionVariables();
|
||||
void constraintGateOutputVariables();
|
||||
void addGateValueConstraint(int gtidx, int gt_val, const std::vector<int>& fanin_variables);
|
||||
void setupCycleConstraints();
|
||||
void setupAigerConstraints();
|
||||
|
||||
int setupOutputVariable(int output_index, int tt_index, int pattern_idx);
|
||||
|
||||
void addNonTrivialConstraint();
|
||||
void addUseAllStepsConstraint();
|
||||
void addNoReapplicationConstraint();
|
||||
void addOrderedStepsConstraint();
|
||||
|
||||
// activator = 0: do not use an activation variable
|
||||
void addCardinalityConstraint(const std::vector<int>& vars, unsigned int cardinality, int activator = 0);
|
||||
std::vector<std::vector<int>> addSequentialCounter(const std::vector<int>& vars, unsigned int cardinality, int activator = 0);
|
||||
|
||||
void addNaiveIs1CardinalityConstraint(const std::vector<int>& vars);
|
||||
void addNaiveIs2CardinalityConstraint(const std::vector<int>& vars);
|
||||
|
||||
void defineConjunction(int var, std::vector<int>&& literals, int activator);
|
||||
void defineDisjunction(int var, std::vector<int>&& literals, int activator);
|
||||
|
||||
// computes the index of the first gate that can used the indexed nodes as inputs
|
||||
// indices must be ordered
|
||||
int getPotentialSuccessors(const std::vector<int>& indices) const;
|
||||
|
||||
static bool getTTValue(int tt_line, int var);
|
||||
static unsigned int pow2(int x);
|
||||
|
||||
};
|
||||
|
||||
inline int RelationSynthesiser::getNewVariable() {
|
||||
return ++max_var;
|
||||
}
|
||||
|
||||
inline std::vector<int> RelationSynthesiser::getNewVariableVector(unsigned int size) {
|
||||
std::vector<int> vars;
|
||||
vars.reserve(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
vars.push_back(getNewVariable());
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
inline int RelationSynthesiser::getPotentialSuccessors(const std::vector<int>& indices) const {
|
||||
if (indices.back() < subcir.inputs.size()) {
|
||||
return 0;
|
||||
}
|
||||
return indices.back() - subcir.inputs.size() + 1;
|
||||
}
|
||||
|
||||
inline bool RelationSynthesiser::getTTValue(int tt_line, int var) {
|
||||
return (tt_line >> var) & 1;
|
||||
}
|
||||
|
||||
inline unsigned int RelationSynthesiser::pow2(int x) {
|
||||
return 1u << x;
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
/**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 <vector>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#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<int>& 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<std::chrono::steady_clock> 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<double> 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<int>& assumptions) {
|
||||
for (auto& l: assumptions) {
|
||||
solver.assume(l);
|
||||
}
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve() {
|
||||
std::chrono::time_point<std::chrono::steady_clock> start = std::chrono::steady_clock::now();
|
||||
int status = solver.solve();
|
||||
last_runtime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline int CadicalSolver::solve(double timeout) {
|
||||
std::chrono::time_point<std::chrono::steady_clock> 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::milliseconds>(std::chrono::steady_clock::now() - start).count();
|
||||
if (solver.state() == CaDiCaL::INVALID) {
|
||||
std::cerr<<"Solver is in invalid state"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
solver.disconnect_terminator();
|
||||
return status;
|
||||
}
|
||||
|
||||
inline Vec_Int_t* CadicalSolver::getModelVec() {
|
||||
Vec_Int_t* assignment = Vec_IntAlloc( solver.vars() );
|
||||
for (int v = 1; v <= solver.vars(); v++) {
|
||||
Vec_IntSetEntryFull( assignment, Abc_AbsInt(val(v)), val(v) > 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
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [selectionStrategies.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Subcircuit selection]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__SELECTIONSTRATEGIES_hpp
|
||||
#define ABC__OPT__ESLIM__SELECTIONSTRATEGIES_hpp
|
||||
|
||||
#include <random>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "tabooList.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
struct SubcircuitValidator {
|
||||
public:
|
||||
SubcircuitValidator(const eSLIMConfig& cf);
|
||||
bool check(const Subcircuit& candidate) const;
|
||||
|
||||
private:
|
||||
const eSLIMConfig& cfg;
|
||||
static constexpr unsigned int min_size = 2;
|
||||
static constexpr unsigned int max_ninputs = 10;
|
||||
|
||||
};
|
||||
|
||||
struct SubcircuitNoFBValidator : public SubcircuitValidator {
|
||||
public:
|
||||
using SubcircuitValidator::SubcircuitValidator;
|
||||
bool check(const Subcircuit& candidate) const;
|
||||
};
|
||||
|
||||
class ForwardSearch {
|
||||
public:
|
||||
ForwardSearch(eSLIMCirMan& es_man);
|
||||
auto getNextBegin(const eSLIMCirObj& obj);
|
||||
auto getNextEnd(const eSLIMCirObj& obj);
|
||||
bool check(const eSLIMCirObj& obj) const;
|
||||
private:
|
||||
eSLIMCirMan& es_man;
|
||||
};
|
||||
|
||||
class BackwardSearch {
|
||||
public:
|
||||
BackwardSearch(eSLIMCirMan& es_man);
|
||||
auto getNextBegin(const eSLIMCirObj& obj);
|
||||
auto getNextEnd(const eSLIMCirObj& obj);
|
||||
bool check(const eSLIMCirObj& obj) const;
|
||||
private:
|
||||
eSLIMCirMan& es_man;
|
||||
};
|
||||
|
||||
class BaseRootSelector {
|
||||
public:
|
||||
BaseRootSelector(eSLIMCirMan& es_man, const eSLIMConfig& cfg);
|
||||
int getRoot(std::mt19937& rng);
|
||||
void reset() {}
|
||||
|
||||
private:
|
||||
unsigned int getUniformRandomNumber(std::mt19937& rng, unsigned int lower, unsigned int upper); // requires lower < upper
|
||||
|
||||
eSLIMCirMan& es_man;
|
||||
// const eSLIMConfig& cfg;
|
||||
std::uniform_int_distribution<std::mt19937::result_type> udistr;
|
||||
};
|
||||
|
||||
class TabooRootSelector {
|
||||
public:
|
||||
TabooRootSelector(eSLIMCirMan& es_man, const eSLIMConfig& cfg);
|
||||
~TabooRootSelector();
|
||||
int getRoot(std::mt19937& rng);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
eSLIMCirMan& es_man;
|
||||
|
||||
|
||||
protected:
|
||||
const eSLIMConfig& cfg;
|
||||
TabooList taboo;
|
||||
|
||||
};
|
||||
|
||||
class CriticalPathSelector : public TabooRootSelector {
|
||||
public:
|
||||
using TabooRootSelector::TabooRootSelector;
|
||||
int getRoot(std::mt19937& rng);
|
||||
};
|
||||
|
||||
struct BaseCandidateNodeConstraint {
|
||||
static bool check(int to_check, const eSLIMCirMan& cir, const std::set<int>& subcircuit);
|
||||
};
|
||||
|
||||
struct SingleOutputCandidateNodeConstraint {
|
||||
static bool check(int to_check, const eSLIMCirMan& cir, const std::set<int>& subcircuit);
|
||||
};
|
||||
|
||||
struct NoBiasSelector {
|
||||
static bool useBias(const eSLIMCirMan& es_man, const eSLIMCirObj& obj) {return false;}
|
||||
};
|
||||
|
||||
struct CriticalPathBiasSelector {
|
||||
static bool useBias(const eSLIMCirMan& es_man, const eSLIMCirObj& obj) {return es_man.isOnCricticalPath(obj);}
|
||||
};
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector = NoBiasSelector, typename CandidateNodeConstraint = BaseCandidateNodeConstraint>
|
||||
class RandomizedBFSSelection {
|
||||
|
||||
public:
|
||||
RandomizedBFSSelection(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
Subcircuit getSubcircuit(bool& status); // status indicates if the search was successful
|
||||
void setSeed(int seed);
|
||||
void reset();
|
||||
|
||||
static constexpr bool requiresRemainingTimes() {return std::is_same_v<CriticalPathBiasSelector, BiasSelector>;}
|
||||
|
||||
private:
|
||||
|
||||
std::set<int> computeSubcircuitCandidate();
|
||||
int selectRoot();
|
||||
void processCandidateNode(int candidate, std::set<int>& subcircuit, std::queue<int>& candidates);
|
||||
bool getRandomBool();
|
||||
bool getBiasedRandomBool();
|
||||
|
||||
eSLIMCirMan& es_man;
|
||||
const eSLIMConfig& cfg;
|
||||
static constexpr unsigned int min_size = 2;
|
||||
static constexpr unsigned int max_ninputs = 10;
|
||||
|
||||
eSLIMLog& log;
|
||||
Validator validator;
|
||||
RootSelector root_selector;
|
||||
SearchDirection search_direction;
|
||||
|
||||
std::mt19937 rng;
|
||||
std::bernoulli_distribution bdist;
|
||||
std::bernoulli_distribution biased_bdist;
|
||||
};
|
||||
|
||||
|
||||
|
||||
using RamdomizedBFS=RandomizedBFSSelection<SubcircuitValidator,BaseRootSelector, BackwardSearch>;
|
||||
using RamdomizedBFSForward=RandomizedBFSSelection<SubcircuitValidator,BaseRootSelector, ForwardSearch>;
|
||||
using RandomizedBFSNoFB=RandomizedBFSSelection<SubcircuitNoFBValidator,BaseRootSelector, BackwardSearch>;
|
||||
using RamdomizedBFSTaboo=RandomizedBFSSelection<SubcircuitValidator,TabooRootSelector, BackwardSearch>;
|
||||
using RamdomizedBFSTabooForward=RandomizedBFSSelection<SubcircuitValidator,TabooRootSelector, ForwardSearch>;
|
||||
using RamdomizedBFSTabooNoFB=RandomizedBFSSelection<SubcircuitNoFBValidator,TabooRootSelector, BackwardSearch>;
|
||||
|
||||
using SingleOutputBFS = RandomizedBFSSelection<SubcircuitValidator,TabooRootSelector, BackwardSearch, NoBiasSelector, SingleOutputCandidateNodeConstraint>;
|
||||
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
|
||||
#include "selectionStrategies.tpp"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [selectionStrategies.tpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Subcircuit selection]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "selectionStrategies.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
inline SubcircuitValidator::SubcircuitValidator(const eSLIMConfig& cfg) : cfg(cfg) {
|
||||
|
||||
}
|
||||
|
||||
inline bool SubcircuitValidator::check(const Subcircuit& candidate) const {
|
||||
return candidate.inputs.size() <= max_ninputs && candidate.inputs.size() >= cfg.gate_size;
|
||||
}
|
||||
|
||||
inline bool SubcircuitNoFBValidator::check(const Subcircuit& candidate) const {
|
||||
return SubcircuitValidator::check(candidate) && candidate.forbidden_pairs.empty();
|
||||
}
|
||||
|
||||
inline ForwardSearch::ForwardSearch(eSLIMCirMan& es_man) : es_man(es_man) {
|
||||
}
|
||||
|
||||
inline auto ForwardSearch::getNextBegin(const eSLIMCirObj& obj) {
|
||||
return obj.fanouts.begin();
|
||||
}
|
||||
|
||||
inline auto ForwardSearch::getNextEnd(const eSLIMCirObj& obj) {
|
||||
return obj.fanouts.end();
|
||||
}
|
||||
|
||||
inline bool ForwardSearch::check(const eSLIMCirObj& obj) const {
|
||||
return !es_man.isPo(obj.node_id);
|
||||
}
|
||||
|
||||
inline BackwardSearch::BackwardSearch(eSLIMCirMan& es_man) : es_man(es_man) {
|
||||
}
|
||||
|
||||
inline auto BackwardSearch::getNextBegin(const eSLIMCirObj& obj) {
|
||||
return obj.fanins.begin();
|
||||
}
|
||||
|
||||
inline auto BackwardSearch::getNextEnd(const eSLIMCirObj& obj) {
|
||||
return obj.fanins.end();
|
||||
}
|
||||
|
||||
inline bool BackwardSearch::check(const eSLIMCirObj& obj) const {
|
||||
return !es_man.isPi(obj.node_id);
|
||||
}
|
||||
|
||||
// inline BaseRootSelector::BaseRootSelector(eSLIMCirMan& es_man, const eSLIMConfig& cfg) : es_man(es_man), cfg(cfg) {
|
||||
inline BaseRootSelector::BaseRootSelector(eSLIMCirMan& es_man, const eSLIMConfig& cfg) : es_man(es_man) {
|
||||
|
||||
}
|
||||
|
||||
inline TabooRootSelector::TabooRootSelector(eSLIMCirMan& es_man, const eSLIMConfig& cfg) : es_man(es_man), cfg(cfg), taboo(es_man) {
|
||||
es_man.registerTabooList(&taboo);
|
||||
}
|
||||
|
||||
inline TabooRootSelector::~TabooRootSelector() {
|
||||
es_man.unregisterTabooList();
|
||||
}
|
||||
|
||||
|
||||
inline unsigned int BaseRootSelector::getUniformRandomNumber(std::mt19937& rng, unsigned int lower, unsigned int upper) {
|
||||
udistr.param(std::uniform_int_distribution<std::mt19937::result_type>::param_type(lower, upper));
|
||||
return udistr(rng);
|
||||
}
|
||||
|
||||
inline int BaseRootSelector::getRoot(std::mt19937& rng) {
|
||||
int min_id = es_man.getNofPis() + 1;
|
||||
int max_id = es_man.getNofObjs() - es_man.getNofPos() - 1;
|
||||
return getUniformRandomNumber(rng, min_id, max_id);
|
||||
}
|
||||
|
||||
|
||||
inline int TabooRootSelector::getRoot(std::mt19937& rng) {
|
||||
return taboo.getRandomNonTaboo(rng, cfg.taboo_ratio, cfg.taboo_time);
|
||||
}
|
||||
|
||||
inline void TabooRootSelector::reset() {
|
||||
taboo.reset();
|
||||
es_man.registerTabooList(&taboo);
|
||||
}
|
||||
|
||||
inline int CriticalPathSelector::getRoot(std::mt19937& rng) {
|
||||
return taboo.getBiasedRandomNonTaboo<CriticalPathBiasSelector>(rng, cfg.bias, cfg.taboo_ratio, cfg.taboo_time);
|
||||
}
|
||||
|
||||
inline bool BaseCandidateNodeConstraint::check(int to_check, const eSLIMCirMan& cir, const std::set<int>& subcircuit) {
|
||||
return subcircuit.find(to_check) == subcircuit.end();
|
||||
}
|
||||
|
||||
inline bool SingleOutputCandidateNodeConstraint::check(int to_check, const eSLIMCirMan& cir, const std::set<int>& subcircuit) {
|
||||
if (subcircuit.find(to_check) != subcircuit.end()) {
|
||||
return false;
|
||||
}
|
||||
const auto& obj = cir.getObj(to_check);
|
||||
for (const auto& fo : obj.fanouts) {
|
||||
// The node has a fanout that is not yet in the subcircuit
|
||||
if (subcircuit.find(fo->node_id) == subcircuit.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::RandomizedBFSSelection(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: es_man(es_man), cfg(cfg), log(log), validator(cfg), root_selector(es_man, cfg), search_direction(es_man),
|
||||
bdist(cfg.expansion_probability), biased_bdist(std::min(1., cfg.expansion_probability*1.5)) {
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
void RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::setSeed(int seed) {
|
||||
rng.seed(seed);
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
bool RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::getRandomBool() {
|
||||
return bdist(rng);
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
bool RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::getBiasedRandomBool() {
|
||||
return biased_bdist(rng);
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
int RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::selectRoot() {
|
||||
return root_selector.getRoot(rng);
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
void RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::reset() {
|
||||
root_selector.reset();
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
std::set<int> RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::computeSubcircuitCandidate() {
|
||||
std::set<int> scir;
|
||||
int root_id = selectRoot();
|
||||
std::queue<int> candidates;
|
||||
processCandidateNode(root_id, scir, candidates);
|
||||
std::queue<int> rejected_nodes;
|
||||
while (!candidates.empty() && scir.size() < cfg.subcircuit_max_size) {
|
||||
int c = candidates.front();
|
||||
candidates.pop();
|
||||
if (CandidateNodeConstraint::check(c, es_man, scir)) {
|
||||
bool add_node;
|
||||
if (BiasSelector::useBias(es_man, es_man.getObj(c))) {
|
||||
add_node = getBiasedRandomBool();
|
||||
} else {
|
||||
add_node = getRandomBool();
|
||||
}
|
||||
if (add_node) {
|
||||
processCandidateNode(c, scir, candidates);
|
||||
} else {
|
||||
rejected_nodes.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this->cfg.fill_subcircuits) {
|
||||
while (!rejected_nodes.empty() && scir.size() < cfg.subcircuit_max_size) {
|
||||
int c = rejected_nodes.front();
|
||||
rejected_nodes.pop();
|
||||
if (CandidateNodeConstraint::check(c, es_man, scir)) {
|
||||
processCandidateNode(c, scir, rejected_nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
return scir;
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
void RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::processCandidateNode(int node, std::set<int>& subcircuit, std::queue<int>& candidates) {
|
||||
subcircuit.insert(node);
|
||||
auto& obj = es_man.getObj(node);
|
||||
for (auto it = search_direction.getNextBegin(obj); it != search_direction.getNextEnd(obj); it++) {
|
||||
const auto& f = *it;
|
||||
if (search_direction.check(*f)) {
|
||||
candidates.push(f->node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Validator, typename RootSelector, typename SearchDirection, typename BiasSelector, typename CandidateNodeConstraint>
|
||||
Subcircuit RandomizedBFSSelection<Validator, RootSelector, SearchDirection, BiasSelector, CandidateNodeConstraint>::getSubcircuit(bool& status) {
|
||||
std::set<int> scir;
|
||||
status = false;
|
||||
for (int i = 1; i < cfg.nselection_trials; i++) {
|
||||
scir = computeSubcircuitCandidate();
|
||||
if (scir.size() < min_size) {
|
||||
scir.clear();
|
||||
continue;
|
||||
}
|
||||
es_man.incrementTraversalId();
|
||||
Subcircuit candidate = Subcircuit::getSubcircuit(es_man, scir);
|
||||
if (validator.check(candidate)) {
|
||||
status = true;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return Subcircuit::getEmptySubcircuit();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/**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 <random>
|
||||
#include <queue>
|
||||
|
||||
#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<typename T>
|
||||
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<int, std::unordered_set<int>> 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<int, std::unordered_set<int>>& pairs, const std::unordered_map<int,int>& 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<std::mt19937::result_type> udistr;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class randomizedBFS : public SelectionStrategy<T> {
|
||||
private:
|
||||
randomizedBFS(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
Subcircuit findSubcircuit();
|
||||
int selectRoot();
|
||||
void checkCandidate(Subcircuit& subcircuit, std::queue<int>& candidate, std::queue<int>& rejected, bool add);
|
||||
const int nPis;
|
||||
const int nPos;
|
||||
friend SelectionStrategy<T>;
|
||||
friend T;
|
||||
};
|
||||
|
||||
class randomizedBFSFP : public randomizedBFS<randomizedBFSFP> {
|
||||
public :
|
||||
randomizedBFSFP(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
private:
|
||||
Subcircuit getSubcircuitImpl();
|
||||
bool filterSubcircuitImpl(const Subcircuit& subcir);
|
||||
|
||||
friend SelectionStrategy<randomizedBFSFP>;
|
||||
};
|
||||
|
||||
class randomizedBFSnoFP : public randomizedBFS<randomizedBFSnoFP> {
|
||||
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<randomizedBFSnoFP>;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
SelectionStrategy<T>::SelectionStrategy(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: gia_man(gia_man), cfg(cfg), log(log), rng(std::random_device()()), bdist(cfg.expansion_probability) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SelectionStrategy<T>::setSeed(int seed) {
|
||||
rng.seed(seed);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
unsigned int SelectionStrategy<T>::getUniformRandomNumber(unsigned int lower, unsigned int upper) {
|
||||
udistr.param(std::uniform_int_distribution<std::mt19937::result_type>::param_type(lower, upper));
|
||||
return udistr(rng);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SelectionStrategy<T>::getRandomBool() {
|
||||
return bdist(rng);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
randomizedBFS<T>::randomizedBFS(Gia_Man_t*& gia_man, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: SelectionStrategy<T>(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<randomizedBFSFP>(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<randomizedBFSnoFP>(gia_man, cfg, log) {
|
||||
}
|
||||
|
||||
inline bool randomizedBFSFP::filterSubcircuitImpl(const Subcircuit& subcir) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#include "selectionStrategy.tpp"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,233 +0,0 @@
|
|||
/**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 <queue>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
#include "selectionStrategy.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace eSLIM {
|
||||
|
||||
template<typename T>
|
||||
Subcircuit SelectionStrategy<T>::getSubcircuit() {
|
||||
for (int i = 0; i < cfg.nselection_trials; i++) {
|
||||
Subcircuit subcir = static_cast<T*>(this)->getSubcircuitImpl();
|
||||
if (filterSubcircuit(subcir)) {
|
||||
return subcir;
|
||||
} else {
|
||||
subcir.free();
|
||||
}
|
||||
}
|
||||
status = false;
|
||||
Subcircuit empty_subcir;
|
||||
return empty_subcir;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool SelectionStrategy<T>::filterSubcircuit(const Subcircuit& subcir) {
|
||||
// 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;
|
||||
}
|
||||
if (Vec_IntSize(subcir.nodes) < min_size) {
|
||||
return false;
|
||||
}
|
||||
return static_cast<T*>(this)->filterSubcircuitImpl(subcir);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SelectionStrategy<T>::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 <typename T>
|
||||
std::unordered_map<int, std::unordered_set<int>> SelectionStrategy<T>::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<int,int> 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<int, std::unordered_set<int>> 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 <typename T>
|
||||
void SelectionStrategy<T>::forbiddenPairsRec(Gia_Obj_t * pObj, int input, int min_level, std::unordered_map<int, std::unordered_set<int>>& pairs, const std::unordered_map<int,int>& 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<typename T>
|
||||
int randomizedBFS<T>::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<typename T>
|
||||
void randomizedBFS<T>::checkCandidate(Subcircuit& subcircuit, std::queue<int>& candidates, std::queue<int>& 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<typename T>
|
||||
Subcircuit randomizedBFS<T>::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<int> candidates;
|
||||
candidates.push(Gia_ObjFaninId0(gia_obj, root_id));
|
||||
candidates.push(Gia_ObjFaninId1(gia_obj, root_id));
|
||||
std::queue<int> 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
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [subcircuit.cpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Subcircuit representation]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
|
||||
#include "subcircuit.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
namespace eSLIM {
|
||||
|
||||
Subcircuit Subcircuit::getSubcircuit(eSLIMCirMan& es_man, const std::set<int>& nodes) {
|
||||
Subcircuit scir = getSubcircuitBare(es_man, nodes.begin(), nodes.end());
|
||||
es_man.markCones(scir.nodes);
|
||||
scir.setForbiddenPairs(es_man);
|
||||
return scir;
|
||||
}
|
||||
|
||||
Subcircuit Subcircuit::getEmptySubcircuit() {
|
||||
Subcircuit scir;
|
||||
return scir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Subcircuit::setIO(eSLIMCirMan& es_man) {
|
||||
std::set<int> input_set;
|
||||
std::set<int> output_set;
|
||||
for (int n : nodes) {
|
||||
const auto& obj = es_man.getObj(n);
|
||||
for (const auto& f : obj.fanins) {
|
||||
if (!es_man.inSubcircuit(*f) && !es_man.isConst(*f)) {
|
||||
input_set.insert(f->node_id);
|
||||
}
|
||||
}
|
||||
for (const auto& f : obj.fanouts) {
|
||||
if (!es_man.inSubcircuit(*f)) {
|
||||
output_set.insert(obj.node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
inputs.insert(inputs.end(), input_set.begin(), input_set.end());
|
||||
outputs.insert(outputs.end(), output_set.begin(), output_set.end());
|
||||
}
|
||||
|
||||
void Subcircuit::setForbiddenPairs(const eSLIMCirMan& es_man) {
|
||||
std::unordered_set<int> seen;
|
||||
for (int inp : inputs) {
|
||||
getForbiddenPairsRec(inp, seen, es_man.getObj(inp), es_man);
|
||||
seen.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Subcircuit::getForbiddenPairsRec(int inp, std::unordered_set<int>& seen, const eSLIMCirObj& obj, const eSLIMCirMan& es_man) {
|
||||
if (seen.find(obj.node_id) != seen.end()) {
|
||||
return;
|
||||
}
|
||||
seen.insert(obj.node_id);
|
||||
for (const auto& f : obj.fanins) {
|
||||
if (es_man.inSubcircuit(*f)) {
|
||||
forbidden_pairs[f->node_id].emplace(inp);
|
||||
} else if (es_man.inTFI(*f) && es_man.inTFO(*f)) {
|
||||
getForbiddenPairsRec(inp, seen, *f, es_man);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Subcircuit::setupTimings(eSLIMCirMan& es_man) {
|
||||
// es_man.setupTimings();
|
||||
for (int in : inputs) {
|
||||
arrival_times.push_back(es_man.getObj(in).depth);
|
||||
}
|
||||
int max_crossing_path = 0;
|
||||
for (int out : outputs) {
|
||||
remaining_times.push_back(es_man.getObj(out).remaining_time);
|
||||
max_crossing_path = std::max(max_crossing_path, es_man.getObj(out).remaining_time + es_man.getObj(out).depth);
|
||||
}
|
||||
return max_crossing_path;
|
||||
}
|
||||
|
||||
void Subcircuit::print() const {
|
||||
std::cout << "Inputs:";
|
||||
for (int i : inputs) {
|
||||
std::cout << " " << i;
|
||||
}
|
||||
std::cout << "\nOutputs:";
|
||||
for (int o : outputs) {
|
||||
std::cout << " " << o;
|
||||
}
|
||||
std::cout << "\nArrival times:";
|
||||
for (int ar : arrival_times) {
|
||||
std::cout << " " << ar;
|
||||
}
|
||||
std::cout << "\nRemaining times:";
|
||||
for (int re : remaining_times) {
|
||||
std::cout << " " << re;
|
||||
}
|
||||
std::cout << "\nNodes:";
|
||||
for (int n : nodes) {
|
||||
std::cout << " " << n;
|
||||
}
|
||||
std::cout << "\nForbidden pairs:";
|
||||
for (const auto & [out,inps] : forbidden_pairs) {
|
||||
std::cout << "\n" << out << " :";
|
||||
for (int inp : inps) {
|
||||
std::cout << " " << inp;
|
||||
}
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [subcircuit.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Subcircuit representation]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__SUBCIRCUIT_hpp
|
||||
#define ABC__OPT__ESLIM__SUBCIRCUIT_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class Subcircuit {
|
||||
|
||||
public:
|
||||
template <typename It>
|
||||
static Subcircuit getSubcircuitBare(eSLIMCirMan& es_man, It begin, It end);
|
||||
static Subcircuit getSubcircuit(eSLIMCirMan& es_man, const std::set<int>& nodes);
|
||||
static Subcircuit getEmptySubcircuit();
|
||||
|
||||
int setupTimings(eSLIMCirMan& es_man);
|
||||
|
||||
std::vector<int> nodes;
|
||||
std::vector<int> inputs;
|
||||
std::vector<int> outputs;
|
||||
// Assigns the inputs of the subcircuit that can be reached from an output x to x.
|
||||
std::unordered_map<int, std::set<int>> forbidden_pairs;
|
||||
|
||||
std::vector<unsigned int> arrival_times;
|
||||
std::vector<unsigned int> remaining_times;
|
||||
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
template <typename It>
|
||||
Subcircuit(eSLIMCirMan& es_man, It begin, It end);
|
||||
Subcircuit() = default;
|
||||
void setIO(eSLIMCirMan& es_man);
|
||||
void setForbiddenPairs(const eSLIMCirMan& es_man);
|
||||
void getForbiddenPairsRec(int inp, std::unordered_set<int>& seen, const eSLIMCirObj& obj, const eSLIMCirMan& es_man);
|
||||
};
|
||||
|
||||
template <typename It>
|
||||
Subcircuit::Subcircuit(eSLIMCirMan& es_man, It begin, It end) : nodes(begin, end) {
|
||||
es_man.markSubcircuit(this->nodes);
|
||||
setIO(es_man);
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
Subcircuit Subcircuit::getSubcircuitBare(eSLIMCirMan& es_man, It begin, It end) {
|
||||
Subcircuit scir(es_man, begin, end);
|
||||
return scir;
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
/**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 <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#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 Derived>
|
||||
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<int, std::vector<int>> connection_variables;
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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<int, std::unordered_set<int>>& 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<int, std::unordered_set<int>> computeNotInPair(const std::unordered_map<int, std::unordered_set<int>>& pairs);
|
||||
|
||||
int prepareLits(int * pLits, int& nLits);
|
||||
|
||||
friend Derived;
|
||||
};
|
||||
|
||||
// applies Cadical incrementally
|
||||
class CadicalEngine : public exactSynthesisEngine<CadicalEngine> {
|
||||
|
||||
public:
|
||||
CadicalEngine(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg);
|
||||
Mini_Aig_t* getCircuit(int size, double timeout);
|
||||
|
||||
private:
|
||||
using exactSynthesisEngine::addClause;
|
||||
std::vector<int> 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<int> getAssumptions(int size);
|
||||
|
||||
friend exactSynthesisEngine<CadicalEngine>;
|
||||
};
|
||||
|
||||
class OneshotEngine {
|
||||
protected:
|
||||
int getAuxilaryVariableCountDerived() {return 0;};
|
||||
int getGateEnablingLiteralImpl(int index, bool negated) {return 0;};
|
||||
// void addAssumptions(int size) {};
|
||||
void addGateDeactivatedConstraint(int idx) {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class OneshotManager {
|
||||
public:
|
||||
OneshotManager(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int maxnNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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<int, std::unordered_set<int>>& forbidden_pairs;
|
||||
eSLIMLog& log;
|
||||
const eSLIMConfig& cfg;
|
||||
};
|
||||
|
||||
class CadicalEngineOneShot : public exactSynthesisEngine<CadicalEngineOneShot>, public OneshotEngine {
|
||||
|
||||
public:
|
||||
CadicalEngineOneShot( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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<CadicalEngineOneShot>;
|
||||
};
|
||||
|
||||
class KissatEngineOneShot : public exactSynthesisEngine<KissatEngineOneShot>, public OneshotEngine {
|
||||
|
||||
public:
|
||||
KissatEngineOneShot( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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<KissatEngineOneShot>;
|
||||
};
|
||||
|
||||
|
||||
class KissatCmdEngine : public exactSynthesisEngine<KissatCmdEngine>, public OneshotEngine {
|
||||
|
||||
public:
|
||||
KissatCmdEngine( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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<KissatCmdEngine>;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline int exactSynthesisEngine<T>::addClause(int lit1, int lit2, int lit3, int lit4) {
|
||||
int clause[4] = {lit1, lit2, lit3, lit4};
|
||||
return static_cast<T*>(this)->addClause(clause, 4);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int exactSynthesisEngine<T>::getGateEnablingLiteral(int index, bool negated) {
|
||||
return static_cast<T*>(this)->getGateEnablingLiteralImpl(index, negated);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int exactSynthesisEngine<T>::getAuxilaryVariableCount() {
|
||||
int ncvars = connection_variables.empty() ? 0 : connection_variables.begin()->second.size() * connection_variables.size();
|
||||
return ncvars + static_cast<T*>(this)->getAuxilaryVariableCountDerived();
|
||||
}
|
||||
|
||||
typedef OneshotManager<CadicalEngineOneShot> CadicalOneShot;
|
||||
typedef OneshotManager<KissatEngineOneShot> KissatOneShot;
|
||||
typedef OneshotManager<KissatCmdEngine> KissatCmdOneShot;
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#include "synthesisEngine.tpp"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,632 +0,0 @@
|
|||
/**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 <numeric>
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#define unlink _unlink
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#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 <typename T>
|
||||
exactSynthesisEngine<T>::exactSynthesisEngine( Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int nNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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 <typename T>
|
||||
bool exactSynthesisEngine<T>::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 <typename T>
|
||||
int exactSynthesisEngine<T>::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 <typename T>
|
||||
int exactSynthesisEngine<T>::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 <typename T>
|
||||
Mini_Aig_t * exactSynthesisEngine<T>::getAig(Vec_Int_t * vValues) {
|
||||
return getAig(vValues, nNodes);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Mini_Aig_t * exactSynthesisEngine<T>::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 <typename T>
|
||||
void exactSynthesisEngine<T>::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 <typename T>
|
||||
void exactSynthesisEngine<T>::introduceConnectionVariables() {
|
||||
std::unordered_set<int> 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<int> (nCVars, 0));
|
||||
std::iota(connection_variables[in].begin(), connection_variables[in].end(), nCnfVars);
|
||||
nCnfVars += nCVars;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void exactSynthesisEngine<T>::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 <typename T>
|
||||
void exactSynthesisEngine<T>::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 <typename T>
|
||||
void exactSynthesisEngine<T>::addCombinedCycleConstraints() {
|
||||
assert (forbidden_pairs.size() > 1 && "Combined connectivity constraints are only needed if there are forbidden pairs for multiple inputs.");
|
||||
std::unordered_map<int, std::unordered_set<int>> 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 <typename T>
|
||||
std::unordered_map<int, std::unordered_set<int>> exactSynthesisEngine<T>::computeNotInPair(const std::unordered_map<int, std::unordered_set<int>>& pairs) {
|
||||
std::unordered_set<int> 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<int, std::unordered_set<int>> 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 <typename T>
|
||||
int exactSynthesisEngine<T>::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<T*>(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<T*>(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<T*>(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 <typename T>
|
||||
void exactSynthesisEngine<T>::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<T*>(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 <typename T>
|
||||
int exactSynthesisEngine<T>::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<int, std::unordered_set<int>>& 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<int> 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<int> CadicalEngine::getAssumptions(int size) {
|
||||
std::vector<int> 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 <typename T>
|
||||
OneshotManager<T>::OneshotManager(Vec_Wrd_t * vSimsIn, Vec_Wrd_t * vSimsOut, int nIns, int nDivs, int nOuts, int maxnNodes,
|
||||
const std::unordered_map<int, std::unordered_set<int>>& 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 <typename T>
|
||||
T OneshotManager<T>::getOneshotEngine(int size) {
|
||||
assert(size <= maxnNodes);
|
||||
T oneshotEngine(vSimsIn, vSimsOut, nIns, nDivs, nOuts, size, forbidden_pairs, log, cfg);
|
||||
return oneshotEngine;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Mini_Aig_t* OneshotManager<T>::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<int, std::unordered_set<int>>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg)
|
||||
: exactSynthesisEngine<CadicalEngineOneShot>(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<int, std::unordered_set<int>>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg)
|
||||
: exactSynthesisEngine<KissatEngineOneShot>(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<int, std::unordered_set<int>>& forbidden_pairs, eSLIMLog& log, const eSLIMConfig& cfg)
|
||||
: exactSynthesisEngine<KissatCmdEngine>(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 );
|
||||
#ifdef __wasm
|
||||
if ( 1 ) {
|
||||
#else
|
||||
if ( system( pCommand ) == -1 ) {
|
||||
#endif
|
||||
std::cerr << "Command " << pCommand << " failed\n";
|
||||
return nullptr;
|
||||
}
|
||||
Vec_Int_t * vRes = Exa4_ManParse( pFileNameOut );
|
||||
unlink( pFileNameIn );
|
||||
return vRes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [synthesisEngines.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Synthesis engines]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__SYNTHESISENGINES_hpp
|
||||
#define ABC__OPT__ESLIM__SYNTHESISENGINES_hpp
|
||||
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "areaEngine.hpp"
|
||||
#include "delayEngine.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class Relation;
|
||||
class Subcircuit;
|
||||
class eSLIMConfig;
|
||||
class eSLIMLog;
|
||||
|
||||
class AreaMinimizer {
|
||||
public:
|
||||
static eSLIMCirMan optimize(const eSLIMCirMan& encompassing, const Relation& relation, const Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
return AreaEngine::synthesiseMinimumSizeCircuit(relation, subcir, cfg, log);
|
||||
}
|
||||
private:
|
||||
AreaMinimizer() = default;
|
||||
};
|
||||
|
||||
class AreaDelayConstraintMinimizer {
|
||||
public:
|
||||
static eSLIMCirMan optimize(eSLIMCirMan& encompassing, const Relation& relation, Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
subcir.setupTimings(encompassing);
|
||||
return DelayEngine::synthesizeMinimumAreaDelayConstraintCircuit(relation, subcir, encompassing.getDepth(), cfg, log);
|
||||
}
|
||||
private:
|
||||
AreaDelayConstraintMinimizer() = default;
|
||||
};
|
||||
|
||||
class AreaDelayMinimizer {
|
||||
public:
|
||||
static eSLIMCirMan optimize(eSLIMCirMan& encompassing, const Relation& relation, Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
subcir.setupTimings(encompassing);
|
||||
return DelayEngine::synthesizeMinimumAreaDelayCircuit(relation, subcir, cfg, log);
|
||||
}
|
||||
private:
|
||||
AreaDelayMinimizer() = default;
|
||||
};
|
||||
|
||||
class DelayMinimizer {
|
||||
public:
|
||||
static eSLIMCirMan optimize(eSLIMCirMan& encompassing, const Relation& relation, Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
int max_crossing_path = subcir.setupTimings(encompassing);
|
||||
unsigned int max_size = std::min(cfg.subcircuit_max_size, static_cast<unsigned int>(subcir.nodes.size() + cfg.additional_gates));
|
||||
return DelayEngine::synthesizeMinimumDelayCircuit(relation, subcir, max_crossing_path, max_size, cfg, log);
|
||||
}
|
||||
private:
|
||||
DelayMinimizer() = default;
|
||||
};
|
||||
|
||||
class DelayAreaMinimizer {
|
||||
public:
|
||||
static eSLIMCirMan optimize(eSLIMCirMan& encompassing, const Relation& relation, Subcircuit& subcir,
|
||||
const eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
int max_crossing_path = subcir.setupTimings(encompassing);
|
||||
unsigned int max_size = std::min(cfg.subcircuit_max_size, static_cast<unsigned int>(subcir.nodes.size() + cfg.additional_gates));
|
||||
return DelayEngine::synthesizeMinimumDelayAreaCircuit(relation, subcir, max_crossing_path, max_size, cfg, log);
|
||||
}
|
||||
private:
|
||||
DelayAreaMinimizer() = default;
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
struct isDelayEngine : std::integral_constant< bool,
|
||||
std::is_same<eSLIM::AreaDelayMinimizer, typename std::remove_cv<T>::type>::value
|
||||
|| std::is_same<eSLIM::AreaDelayConstraintMinimizer, typename std::remove_cv<T>::type>::value
|
||||
|| std::is_same<eSLIM::DelayMinimizer, typename std::remove_cv<T>::type>::value
|
||||
|| std::is_same<eSLIM::DelayAreaMinimizer, typename std::remove_cv<T>::type>::value
|
||||
> {};
|
||||
|
||||
static_assert(!isDelayEngine<AreaMinimizer>::value);
|
||||
static_assert(isDelayEngine<AreaDelayMinimizer>::value);
|
||||
static_assert(isDelayEngine<AreaDelayConstraintMinimizer>::value);
|
||||
static_assert(isDelayEngine<DelayMinimizer>::value);
|
||||
static_assert(isDelayEngine<DelayAreaMinimizer>::value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [tabooList.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Taboo list for subcircuit selection.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__TABOOLIST_hpp
|
||||
#define ABC__OPT__ESLIM__TABOOLIST_hpp
|
||||
|
||||
#include <set>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
class TabooList {
|
||||
|
||||
public:
|
||||
TabooList(const eSLIMCirMan& es_man);
|
||||
int getRandomNonTaboo(std::mt19937& rng, double taboo_ratio, unsigned int taboo_time);
|
||||
template<typename BiasCondition>
|
||||
int getBiasedRandomNonTaboo(std::mt19937& rng, unsigned int bias, double taboo_ratio, unsigned int taboo_time);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
struct eSLIMCirObjCompBase {
|
||||
bool operator()(eSLIMCirObj* a, eSLIMCirObj* b) const {
|
||||
return a->getId() < b->getId();
|
||||
}
|
||||
};
|
||||
|
||||
struct eSLIMCirObjComp {
|
||||
bool operator()(eSLIMCirObj* a, eSLIMCirObj* b) const {
|
||||
return a->isTaboo < b->isTaboo || (a->isTaboo == b->isTaboo && eSLIMCirObjCompBase()(a,b));
|
||||
}
|
||||
};
|
||||
|
||||
void updateTaboo(double taboo_ratio, unsigned int taboo_time);
|
||||
void registerReplacement(eSLIMCirMan& replacement, const Subcircuit& subcir);
|
||||
void discardSubcircuit(const Subcircuit& subcir);
|
||||
void removeRedundantNode(eSLIMCirObj* nptr);
|
||||
void fill();
|
||||
|
||||
void addNode(eSLIMCirObj* pobj);
|
||||
void discardNode(eSLIMCirObj* pobj);
|
||||
void addNonTaboo(eSLIMCirObj* pobj);
|
||||
void removeNonTaboo(eSLIMCirObj* pobj);
|
||||
|
||||
|
||||
const eSLIMCirMan& es_man;
|
||||
std::set<eSLIMCirObj*, eSLIMCirObjComp> taboo_nodes;
|
||||
std::set<eSLIMCirObj*, eSLIMCirObjCompBase> non_taboo_nodes;
|
||||
|
||||
friend eSLIMCirMan;
|
||||
};
|
||||
|
||||
inline TabooList::TabooList(const eSLIMCirMan& es_man)
|
||||
: es_man(es_man) {
|
||||
fill();
|
||||
}
|
||||
|
||||
inline void TabooList::fill() {
|
||||
for (int i = es_man.getNofPis() + 1; i < es_man.getNofObjs()-es_man.getNofPos(); i++) {
|
||||
auto pObj = es_man.nodes[i].get();
|
||||
addNonTaboo(pObj);
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabooList::reset() {
|
||||
taboo_nodes.clear();
|
||||
non_taboo_nodes.clear();
|
||||
fill();
|
||||
}
|
||||
|
||||
inline void TabooList::updateTaboo(double taboo_ratio, unsigned int taboo_time) {
|
||||
assert (taboo_ratio > 0 && taboo_ratio < 1);
|
||||
auto it = taboo_nodes.begin();
|
||||
while (it != taboo_nodes.end()) {
|
||||
if (!es_man.isTaboo(*(*it), taboo_time)) {
|
||||
addNonTaboo(*it);
|
||||
it = taboo_nodes.erase(it);
|
||||
} else if (taboo_nodes.size() > static_cast<double>(es_man.getNofGates()) * taboo_ratio) {
|
||||
addNonTaboo(*it);
|
||||
it = taboo_nodes.erase(it);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabooList::registerReplacement(eSLIMCirMan& replacement, const Subcircuit& subcir) {
|
||||
discardSubcircuit(subcir);
|
||||
for (int i = replacement.getNofPis() + 1; i < replacement.getNofObjs() - replacement.getNofPos(); i++) {
|
||||
auto pObj = replacement.nodes[i].get();
|
||||
taboo_nodes.insert(pObj);
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabooList::discardSubcircuit(const Subcircuit& subcir) {
|
||||
for (int nd : subcir.nodes) {
|
||||
discardNode(es_man.nodes[nd].get());
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabooList::removeRedundantNode(eSLIMCirObj* nptr) {
|
||||
discardNode(nptr);
|
||||
}
|
||||
|
||||
|
||||
inline int TabooList::getRandomNonTaboo(std::mt19937& rng, double taboo_ratio, unsigned int taboo_time) {
|
||||
updateTaboo(taboo_ratio, taboo_time);
|
||||
assert(non_taboo_nodes.size() > 0);
|
||||
std::uniform_int_distribution<std::mt19937::result_type> udistr(0, non_taboo_nodes.size() - 1);
|
||||
int rv = udistr(rng);
|
||||
auto it = non_taboo_nodes.begin();
|
||||
std::advance(it, rv);
|
||||
return (*it)->node_id;
|
||||
}
|
||||
|
||||
template<typename BiasCondition>
|
||||
int TabooList::getBiasedRandomNonTaboo(std::mt19937& rng, unsigned int bias, double taboo_ratio, unsigned int taboo_time) {
|
||||
updateTaboo(taboo_ratio, taboo_time);
|
||||
std::vector<int> weights;
|
||||
weights.reserve(non_taboo_nodes.size());
|
||||
for (const auto& pObj : non_taboo_nodes) {
|
||||
if (BiasCondition::useBias(es_man, *pObj)) {
|
||||
weights.push_back(bias);
|
||||
} else {
|
||||
weights.push_back(1);
|
||||
}
|
||||
}
|
||||
std::discrete_distribution<std::mt19937::result_type> ddistr(weights.begin(), weights.end());
|
||||
int rv = ddistr(rng);
|
||||
auto it = non_taboo_nodes.begin();
|
||||
std::advance(it, rv);
|
||||
return (*it)->node_id;
|
||||
}
|
||||
|
||||
inline void TabooList::addNode(eSLIMCirObj* pobj) {
|
||||
taboo_nodes.insert(pobj);
|
||||
}
|
||||
|
||||
inline void TabooList::discardNode(eSLIMCirObj* pobj) {
|
||||
removeNonTaboo(pobj);
|
||||
taboo_nodes.erase(pobj);
|
||||
}
|
||||
|
||||
inline void TabooList::addNonTaboo(eSLIMCirObj* pobj) {
|
||||
non_taboo_nodes.insert(pobj);
|
||||
}
|
||||
|
||||
inline void TabooList::removeNonTaboo(eSLIMCirObj* pobj) {
|
||||
non_taboo_nodes.erase(pobj);
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif
|
||||
|
|
@ -6,48 +6,118 @@
|
|||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Utilities for the eSLIM package.]
|
||||
Synopsis [Utilities]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - March 2025.]
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: utils.hpp,v 1.00 2025/03/17 00:00:00 Exp $]
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__UTILS_h
|
||||
#define ABC__OPT__ESLIM__UTILS_h
|
||||
#ifndef ABC__OPT__ESLIM__UTILS_hpp
|
||||
#define ABC__OPT__ESLIM__UTILS_hpp
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
#include "misc/vec/vec.h"
|
||||
#include "aig/gia/gia.h"
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// C++20 (and later) code
|
||||
#include <bit>
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// // C++20 (and later) code
|
||||
// #include <bit>
|
||||
#define popcount(x) std::popcount(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define popcount(x) __builtin_popcountll(x)
|
||||
// #elif defined(_MSC_VER)
|
||||
#elif defined(_WIN64)
|
||||
#define popcount(x) __popcnt64(x)
|
||||
#else
|
||||
|
||||
inline int popcount64Impl(ABC_UINT64_T x) {
|
||||
// Constants are 64-bit masks
|
||||
const ABC_UINT64_T m1 = 0x5555555555555555;
|
||||
const ABC_UINT64_T m2 = 0x3333333333333333;
|
||||
const ABC_UINT64_T m3 = 0x0F0F0F0F0F0F0F0F;
|
||||
const ABC_UINT64_T m4 = 0x0101010101010101;
|
||||
x = x - ((x >> 1) & m1);
|
||||
x = (x & m2) + ((x >> 2) & m2);
|
||||
x = (x + (x >> 4)) & m3;
|
||||
return (x * m4) >> 56;
|
||||
}
|
||||
#define popcount(x) popcount64Impl(x)
|
||||
|
||||
#endif
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace eSLIM {
|
||||
|
||||
struct eSLIMConfig {
|
||||
bool extended_normality_processing = false;
|
||||
inline int lsb(ABC_UINT64_T tt) {
|
||||
#if __cplusplus >= 202002L
|
||||
if (tt == 0) {
|
||||
return -1;
|
||||
}
|
||||
return std::countr_zero(tt);
|
||||
#elif defined(__GNUC__)
|
||||
return __builtin_ffsl(tt) - 1;
|
||||
// #elif defined(_MSC_VER)
|
||||
#elif defined(_WIN64)
|
||||
if (tt == 0) {
|
||||
return -1;
|
||||
}
|
||||
int x = 0;
|
||||
bool status = _BitScanForward64(x, tt);
|
||||
return x;
|
||||
#else
|
||||
if (tt == 0) {
|
||||
return -1;
|
||||
}
|
||||
ABC_UINT64_T lsb = tt & -tt;
|
||||
const ABC_UINT64_T debruijn = 0x03f79d71b4cb0a89ULL;
|
||||
ABC_UINT64_T scrambled = (lsb * debruijn) >> 58;
|
||||
const int index64[64] = {
|
||||
0, 1, 48, 2, 57, 49, 28, 3, 61, 58, 50, 42, 29, 17, 4, 62,
|
||||
55, 59, 36, 53, 51, 43, 22, 30, 18, 12, 5, 63, 35, 56, 60, 54,
|
||||
37, 52, 44, 27, 23, 31, 19, 8, 13, 6, 64, 32, 47, 38, 45, 21,
|
||||
26, 24, 39, 16, 7, 64, 33, 46, 20, 25, 41, 15, 64, 34, 40, 64
|
||||
};
|
||||
return index64[scrambled];
|
||||
#endif
|
||||
}
|
||||
|
||||
struct eSLIMConfig {
|
||||
bool aig = true;
|
||||
int gate_size = 2;
|
||||
|
||||
bool apply_strash = true;
|
||||
bool fix_seed = false;
|
||||
bool fill_subcircuits = false;
|
||||
bool trial_limit_active = true;
|
||||
bool allow_xors = false;
|
||||
bool allow_xors = false;
|
||||
|
||||
unsigned int timeout = 3600;
|
||||
unsigned int iterations = 0;
|
||||
unsigned int subcircuit_size_bound = 6;
|
||||
unsigned int subcircuit_max_size = 6;
|
||||
unsigned int additional_gates = 0;
|
||||
unsigned int strash_intervall = 100;
|
||||
int seed = 0;
|
||||
unsigned int nselection_trials = 100;
|
||||
double expansion_probability = 0.6;
|
||||
unsigned int nselection_trials = 120;
|
||||
double expansion_probability = 0.5;
|
||||
unsigned int bias = 2;
|
||||
unsigned int nwindows = 1;
|
||||
unsigned int window_size = 500;
|
||||
|
||||
unsigned int taboo_time = 100;
|
||||
double taboo_ratio = 0.5;
|
||||
|
||||
// times given in sec
|
||||
int minimum_sat_timeout = 1;
|
||||
|
|
@ -55,49 +125,73 @@ namespace eSLIM {
|
|||
int minimum_dynamic_timeout_sample_size = 50;
|
||||
double dynamic_timeout_buffer_factor = 1.4;
|
||||
|
||||
int relation_generation_timeout = 180;
|
||||
bool approximate_relation = false; // Compute an overapproximation of the relation that may not use all don't cares by limiting the tfo of the subcircuit
|
||||
bool generate_relation_with_tfi_limit = false; // If approximate_relation is true, also limit the tfi of the subcircuit
|
||||
unsigned int relation_tfi_bound = 0;
|
||||
unsigned int relation_tfo_bound = 0;
|
||||
|
||||
int verbosity_level = 0;
|
||||
};
|
||||
|
||||
struct eSLIMLog {
|
||||
unsigned int iteration_count = 0;
|
||||
double relation_generation_time = 0;
|
||||
double synthesis_time = 0;
|
||||
unsigned int subcircuits_with_forbidden_pairs = 0;
|
||||
class eSLIMLog {
|
||||
|
||||
std::vector<int> nof_analyzed_circuits_per_size;
|
||||
std::vector<int> nof_replaced_circuits_per_size;
|
||||
std::vector<int> nof_reduced_circuits_per_size;
|
||||
public:
|
||||
unsigned int iteration_count = 0;
|
||||
double relation_generation_time = 0;
|
||||
double synthesis_time = 0;
|
||||
unsigned int subcircuits_with_forbidden_pairs = 0;
|
||||
|
||||
std::vector<ABC_UINT64_T> cummulative_sat_runtimes_per_size;
|
||||
std::vector<int> nof_sat_calls_per_size;
|
||||
std::vector<ABC_UINT64_T> cummulative_unsat_runtimes_per_size;
|
||||
std::vector<int> nof_unsat_calls_per_size;
|
||||
std::vector<int> nof_analyzed_circuits_per_size;
|
||||
std::vector<int> nof_replaced_circuits_per_size;
|
||||
std::vector<int> nof_reduced_circuits_per_size;
|
||||
|
||||
eSLIMLog(int size);
|
||||
std::vector<ABC_UINT64_T> cummulative_sat_runtimes_per_size;
|
||||
std::vector<int> nof_sat_calls_per_size;
|
||||
std::vector<ABC_UINT64_T> cummulative_unsat_runtimes_per_size;
|
||||
std::vector<int> nof_unsat_calls_per_size;
|
||||
std::vector<double> cummulative_relation_generation_times_per_size;
|
||||
std::vector<int> nof_relation_generations_per_size;
|
||||
|
||||
double cummulative_sat_runtime_synthesis = 0; // msec
|
||||
double max_sat_runtime_synthesis = 0; // msec
|
||||
ABC_UINT64_T nof_sat_calls_synthesis = 0;
|
||||
|
||||
double cummulative_sat_runtime_relation_generation = 0; // sec
|
||||
double max_sat_runtime_relation_generation = 0; // sec
|
||||
ABC_UINT64_T nof_sat_calls_relation_generation = 0;
|
||||
|
||||
eSLIMLog(int size);
|
||||
int getSize() const;
|
||||
void resize(int size);
|
||||
};
|
||||
|
||||
struct Subcircuit {
|
||||
Vec_Int_t* nodes;
|
||||
Vec_Int_t* io;
|
||||
unsigned int nof_inputs;
|
||||
std::unordered_map<int, std::unordered_set<int>> 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) {
|
||||
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),
|
||||
cummulative_relation_generation_times_per_size(size + 1, 0), nof_relation_generations_per_size(size + 1, 0) {
|
||||
}
|
||||
|
||||
inline int eSLIMLog::getSize() const {
|
||||
return nof_analyzed_circuits_per_size.size() - 1;
|
||||
}
|
||||
|
||||
inline void eSLIMLog::resize(int size) {
|
||||
int sz = size + 1;
|
||||
nof_analyzed_circuits_per_size.resize(sz);
|
||||
nof_replaced_circuits_per_size.resize(sz);
|
||||
nof_reduced_circuits_per_size.resize(size);
|
||||
cummulative_sat_runtimes_per_size.resize(sz);
|
||||
nof_sat_calls_per_size.resize(sz);
|
||||
cummulative_unsat_runtimes_per_size.resize(sz);
|
||||
nof_unsat_calls_per_size.resize(sz);
|
||||
cummulative_relation_generation_times_per_size.resize(sz);
|
||||
nof_relation_generations_per_size.resize(sz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [windowMan.hpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Basic implementation of a window manager.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef ABC__OPT__ESLIM__WINDOWMAN_hpp
|
||||
#define ABC__OPT__ESLIM__WINDOWMAN_hpp
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
#include "eslimCirMan.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
namespace eSLIM {
|
||||
|
||||
// The parallelisation strategy implemented in this class is rather easy and mainly intended to demonstrate
|
||||
// how the eslim package could make use of parallel computing
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
class WindowMan {
|
||||
|
||||
public:
|
||||
void static applyeSLIM(eSLIMCirMan& es_man, eSLIMConfig& cfg, eSLIMLog& log);
|
||||
|
||||
private:
|
||||
|
||||
WindowMan(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log);
|
||||
eSLIMCirMan getCircuit();
|
||||
|
||||
void setupWindows();
|
||||
void computeWindow(const std::vector<int>& gate_ids, int node_begin, int node_end);
|
||||
void reorderCircuit();
|
||||
|
||||
void runParallel();
|
||||
eSLIMCirMan recombineWindows();
|
||||
void addEncompassing(eSLIMCirMan& es_man, int node_begin, int node_end);
|
||||
void addWindow(eSLIMCirMan& es_man, int wid);
|
||||
|
||||
void combineLogs();
|
||||
|
||||
|
||||
int nwindows = 0;
|
||||
eSLIMCirMan& es_man;
|
||||
const eSLIMConfig& cfg;
|
||||
eSLIMLog& log;
|
||||
std::vector<eSLIMLog> wlogs;
|
||||
std::mt19937 rng;
|
||||
|
||||
std::vector<eSLIMCirMan> windows;
|
||||
std::vector<Subcircuit> scirs;
|
||||
std::vector<int> node_ranges_begin;
|
||||
std::vector<int> node_ranges_end;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#include "windowMan.tpp"
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [windowMan.tpp]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Using Exact Synthesis with the SAT-based Local Improvement Method (eSLIM).]
|
||||
|
||||
Synopsis [Basic implementation of a window manager.]
|
||||
|
||||
Author [Franz-Xaver Reichl]
|
||||
|
||||
Affiliation [University of Freiburg]
|
||||
|
||||
Date [Ver. 1.0. Started - April 2026.]
|
||||
|
||||
Revision [$Id: eSLIM.cpp,v 1.00 2025/04/14 00:00:00 Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef ABC_USE_PTHREADS
|
||||
#include <thread>
|
||||
#endif
|
||||
|
||||
#include "windowMan.hpp"
|
||||
#include "subcircuit.hpp"
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
namespace eSLIM {
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::applyeSLIM(eSLIMCirMan& es_man, eSLIMConfig& cfg, eSLIMLog& log) {
|
||||
int v = cfg.verbosity_level;
|
||||
cfg.verbosity_level = 0;
|
||||
WindowMan win_man(es_man, cfg, log);
|
||||
win_man.setupWindows();
|
||||
win_man.runParallel();
|
||||
cfg.verbosity_level = v;
|
||||
// eSLIMCirMan combined = win_man.recombineWindows();
|
||||
// std::swap(es_man, combined);
|
||||
es_man = win_man.recombineWindows();
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
WindowMan<SynthesisEngine, SelectionStrategy>::WindowMan(eSLIMCirMan& es_man, const eSLIMConfig& cfg, eSLIMLog& log)
|
||||
: es_man(es_man), cfg(cfg), log(log) {
|
||||
if (cfg.fix_seed) {
|
||||
rng.seed(cfg.seed);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::setupWindows() {
|
||||
reorderCircuit();
|
||||
unsigned int nmax_windows = std::ceil(static_cast<double>(es_man.getNofGates()) / cfg.window_size);
|
||||
nwindows = std::min(nmax_windows, cfg.nwindows);
|
||||
std::vector<int> gate_ids(es_man.getNofGates());
|
||||
std::iota(gate_ids.begin(), gate_ids.end(), es_man.getNofPis() + 1);
|
||||
std::vector<int> window_ids (nmax_windows);
|
||||
std::iota(window_ids.begin(), window_ids.end(), 0);
|
||||
std::vector<int> selected_window_ids;
|
||||
selected_window_ids.reserve(nwindows);
|
||||
std::sample(window_ids.begin(), window_ids.end(), std::back_inserter(selected_window_ids), nwindows, rng);
|
||||
for (int i = 0; i < nwindows; i++) {
|
||||
int begin_idx = selected_window_ids[i]*cfg.window_size;
|
||||
// int end_idx = selected_window_ids[i] == nmax_windows ? gate_ids.size() : selected_window_ids[i+1]*cfg.window_size;
|
||||
// int end_idx = selected_window_ids[i] == nmax_windows - 1 ? gate_ids.size() : begin_idx + cfg.window_size;
|
||||
int end_idx = begin_idx + cfg.window_size;
|
||||
computeWindow(gate_ids, begin_idx, end_idx);
|
||||
wlogs.emplace_back(log.getSize());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::reorderCircuit() {
|
||||
std::vector<int> pos;
|
||||
pos.reserve(es_man.getNofPos());
|
||||
for (int i = es_man.getNofObjs() - es_man.getNofPos(); i < es_man.getNofObjs(); i++) {
|
||||
pos.push_back(i);
|
||||
}
|
||||
std::shuffle(pos.begin(), pos.end(), rng);
|
||||
es_man.applyDFSOrdering(pos);
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::computeWindow(const std::vector<int>& gate_ids, int node_begin, int node_end) {
|
||||
es_man.incrementTraversalId(); // needed for the insubcircuit marks
|
||||
int end_node;
|
||||
if (node_end >= gate_ids.size()) {
|
||||
node_end = gate_ids.size();
|
||||
end_node = gate_ids.back() + 1;
|
||||
} else {
|
||||
end_node = gate_ids[node_end];
|
||||
}
|
||||
Subcircuit scir = Subcircuit::getSubcircuitBare(es_man, gate_ids.begin() + node_begin, gate_ids.begin() + node_end);
|
||||
scirs.push_back(scir);
|
||||
windows.emplace_back(es_man, scir);
|
||||
node_ranges_begin.push_back(gate_ids[node_begin]);
|
||||
node_ranges_end.push_back(end_node);
|
||||
}
|
||||
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::runParallel() {
|
||||
#ifdef ABC_USE_PTHREADS
|
||||
std::vector<std::thread> eslim_threads;
|
||||
eslim_threads.reserve(nwindows);
|
||||
for (int i = 0; i < nwindows; i++) {
|
||||
std::thread esman_thread(eSLIM_Man<SynthesisEngine, SelectionStrategy>::applyeSLIM, std::ref(windows[i]), std::ref(cfg), std::ref(wlogs[i]));
|
||||
eslim_threads.push_back(std::move(esman_thread));
|
||||
|
||||
}
|
||||
for(auto& t: eslim_threads) {
|
||||
t.join();
|
||||
}
|
||||
#else
|
||||
std::cout << "PThreads not available, minimize random window.\n";
|
||||
std::uniform_int_distribution<> udist(0, windows.size() - 1);
|
||||
int wid = udist(rng);
|
||||
eSLIM_Man<SynthesisEngine, SelectionStrategy>::applyeSLIM(windows[wid], cfg, wlogs[wid])
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
eSLIMCirMan WindowMan<SynthesisEngine, SelectionStrategy>::recombineWindows() {
|
||||
combineLogs();
|
||||
eSLIMCirMan combined(es_man.getNofObjs());
|
||||
for (int i = 1; i <= es_man.getNofPis(); i++) {
|
||||
es_man.nodes[i]->value1 = combined.addPi(); //node 0 is the constant node
|
||||
}
|
||||
int block_begin = es_man.getNofPis() + 1;
|
||||
for (int i = 0; i < nwindows; i++) {
|
||||
// windows[i].print();
|
||||
int block_end = node_ranges_begin[i];
|
||||
addEncompassing(combined, block_begin, block_end);
|
||||
addWindow(combined, i);
|
||||
block_begin = node_ranges_end[i];
|
||||
}
|
||||
if (node_ranges_end.back() < es_man.getNofObjs() - es_man.getNofPos()) {
|
||||
addEncompassing(combined, node_ranges_end.back(), es_man.getNofObjs() - es_man.getNofPos());
|
||||
}
|
||||
for (int i = 0; i < es_man.getNofPos(); i++) {
|
||||
int nd_id = es_man.getNofObjs() - es_man.getNofPos() + i;
|
||||
auto& nd = es_man.nodes[nd_id];
|
||||
bool is_negated = nd->tt == 1;
|
||||
combined.addPo(nd->fanins[0]->value1, is_negated);
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::addEncompassing(eSLIMCirMan& combined, int node_begin, int node_end) {
|
||||
for (int i = node_begin; i < node_end; i++) {
|
||||
auto& nd = es_man.nodes[i];
|
||||
std::vector<int> fanins;
|
||||
fanins.reserve(nd->fanins.size());
|
||||
for (int i = 0; i < nd->fanins.size(); i++) {
|
||||
fanins.push_back(nd->fanins[i]->value1);
|
||||
}
|
||||
nd->value1 = combined.addNode(fanins, nd->tt);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::addWindow(eSLIMCirMan& combined, int wid) {
|
||||
for (int i = 1; i <= windows[wid].getNofPis(); i++) {
|
||||
windows[wid].nodes[i]->value1 = es_man.nodes[scirs[wid].inputs[i-1]]->value1;
|
||||
}
|
||||
for (int i = windows[wid].getNofPis() + 1; i < windows[wid].getNofObjs() - windows[wid].getNofPos(); i++) {
|
||||
auto& nd = windows[wid].nodes[i];
|
||||
std::vector<int> fanins;
|
||||
fanins.reserve(nd->fanins.size());
|
||||
for (int i = 0; i < nd->fanins.size(); i++) {
|
||||
fanins.push_back(nd->fanins[i]->value1);
|
||||
}
|
||||
nd->value1 = combined.addNode(fanins, nd->tt);
|
||||
}
|
||||
for (int i = 0; i < windows[wid].getNofPos(); i++) {
|
||||
auto& out_nd = windows[wid].nodes[windows[wid].getNofObjs() - windows[wid].getNofPos() + i];
|
||||
es_man.nodes[scirs[wid].outputs[i]]->value1 = out_nd->fanins[0]->value1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename SynthesisEngine, typename SelectionStrategy>
|
||||
void WindowMan<SynthesisEngine, SelectionStrategy>::combineLogs() {
|
||||
for (const auto& wl : wlogs) {
|
||||
int wl_size = wl.getSize();
|
||||
if (log.getSize() < wl_size) {
|
||||
log.resize(wl_size);
|
||||
}
|
||||
log.iteration_count += wl.iteration_count;
|
||||
log.relation_generation_time += wl.relation_generation_time;
|
||||
log.synthesis_time += wl.synthesis_time;
|
||||
log.subcircuits_with_forbidden_pairs += wl.subcircuits_with_forbidden_pairs;
|
||||
|
||||
for (int i = 0; i <= wl_size; i++) {
|
||||
log.nof_analyzed_circuits_per_size[i] += wl.nof_analyzed_circuits_per_size[i];
|
||||
log.nof_replaced_circuits_per_size[i] += wl.nof_replaced_circuits_per_size[i];
|
||||
log.nof_reduced_circuits_per_size[i] += wl.nof_reduced_circuits_per_size[i];
|
||||
log.cummulative_sat_runtimes_per_size[i] += wl.cummulative_sat_runtimes_per_size[i];
|
||||
log.nof_sat_calls_per_size[i] += wl.nof_sat_calls_per_size[i];
|
||||
log.cummulative_unsat_runtimes_per_size[i] += wl.cummulative_unsat_runtimes_per_size[i];
|
||||
log.nof_unsat_calls_per_size[i] += wl.nof_unsat_calls_per_size[i];
|
||||
log.cummulative_relation_generation_times_per_size[i] += wl.cummulative_relation_generation_times_per_size[i];
|
||||
log.nof_relation_generations_per_size[i] += wl.nof_relation_generations_per_size[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -19,6 +19,9 @@
|
|||
***********************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "aig/gia/gia.h"
|
||||
#include "aig/gia/giaAig.h"
|
||||
|
||||
|
|
@ -52,14 +55,23 @@ extern int Bmcg_ManPerform( Gia_Man_t * pGia, Bmc_AndPar_t * pPars );
|
|||
|
||||
typedef struct Par_Share_t_ Par_Share_t;
|
||||
typedef struct Par_ThData_t_ Par_ThData_t;
|
||||
static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result );
|
||||
|
||||
typedef struct Wlc_Ntk_t_ Wlc_Ntk_t;
|
||||
struct Cec_ScorrStop_t_;
|
||||
struct Cec_SproveTrace_t_;
|
||||
static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result );
|
||||
static Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, struct Cec_ScorrStop_t_ * pStopOut );
|
||||
static Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, struct Cec_ScorrStop_t_ * pStopOut );
|
||||
static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, struct Cec_SproveTrace_t_ * pTrace );
|
||||
static void Cec_GiaStopThreads( Par_ThData_t * ThData, pthread_t * WorkerThread, int nWorkers );
|
||||
static int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int RetValue, int * pRetEngine );
|
||||
|
||||
extern int Ufar_ProveWithTimeout( Wlc_Ntk_t * pNtk, int nTimeOut, int fVerbose, int (*pFuncStop)(int), int RunId );
|
||||
|
||||
#ifndef ABC_USE_PTHREADS
|
||||
|
||||
int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; }
|
||||
int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile ) { return -1; }
|
||||
int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, int * pnTimeOut2, int * pnTimeOut3, int * pfUseUif ) { return 0; }
|
||||
int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent ) { return -1; }
|
||||
|
||||
#else // pthreads are used
|
||||
|
||||
|
|
@ -68,6 +80,13 @@ int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, in
|
|||
#define PAR_ENGINE_SCORR1 7
|
||||
#define PAR_ENGINE_SCORR2 8
|
||||
#define PAR_ENGINE_GLA 9
|
||||
#define SPROVE_STAGE_MAX 4
|
||||
#define SPROVE_NET_ORIG 0
|
||||
#define SPROVE_NET_SCNEW 1
|
||||
#define SPROVE_NET_SCOLD 2
|
||||
typedef struct Cec_SproveTrace_t_ Cec_SproveTrace_t;
|
||||
typedef struct Cec_SproveStage_t_ Cec_SproveStage_t;
|
||||
typedef struct Cec_SprovePlan_t_ Cec_SprovePlan_t;
|
||||
struct Par_Share_t_
|
||||
{
|
||||
volatile int fSolved;
|
||||
|
|
@ -85,7 +104,12 @@ typedef struct Par_ThData_t_
|
|||
int fVerbose;
|
||||
int nTimeOutU;
|
||||
Wlc_Ntk_t * pWlc;
|
||||
int WorkerId;
|
||||
int StageId;
|
||||
int NetId;
|
||||
int StopReason;
|
||||
Par_Share_t * pShare;
|
||||
Cec_SproveTrace_t * pTrace;
|
||||
pthread_mutex_t Mutex;
|
||||
pthread_cond_t Cond;
|
||||
} Par_ThData_t;
|
||||
|
|
@ -93,7 +117,44 @@ typedef struct Cec_ScorrStop_t_
|
|||
{
|
||||
Par_Share_t * pShare;
|
||||
abctime TimeToStop;
|
||||
int fStoppedByCallback;
|
||||
int fStoppedByTimeout;
|
||||
} Cec_ScorrStop_t;
|
||||
struct Cec_SproveTrace_t_
|
||||
{
|
||||
FILE * pFile;
|
||||
int fActive;
|
||||
abctime clkStart;
|
||||
pthread_mutex_t Mutex;
|
||||
};
|
||||
struct Cec_SproveStage_t_
|
||||
{
|
||||
int Id;
|
||||
int fGuardUnsolved;
|
||||
int GuardExistsNet;
|
||||
int GuardAndLimitNet;
|
||||
int GuardAndLimit;
|
||||
int fHasRound;
|
||||
int RoundNet;
|
||||
int RoundTimeout;
|
||||
int nRoundEngines;
|
||||
int RoundEngines[PAR_THR_MAX];
|
||||
int fHasReduce;
|
||||
int ReduceType;
|
||||
int ReduceNetIn;
|
||||
int ReduceNetOut;
|
||||
int ReduceTimeout;
|
||||
};
|
||||
struct Cec_SprovePlan_t_
|
||||
{
|
||||
int nProcs;
|
||||
int nTimeOut;
|
||||
int nTimeOut2;
|
||||
int nTimeOut3;
|
||||
int fUseUif;
|
||||
int nStages;
|
||||
Cec_SproveStage_t Stages[SPROVE_STAGE_MAX];
|
||||
};
|
||||
static volatile Par_Share_t * g_pUfarShare = NULL;
|
||||
static volatile Par_Share_t * g_pGlaShare = NULL;
|
||||
static inline const char * Cec_SolveEngineName( int iEngine )
|
||||
|
|
@ -146,9 +207,15 @@ static int Cec_ScorrStop( void * pUser )
|
|||
if ( p == NULL )
|
||||
return 0;
|
||||
if ( p->pShare && p->pShare->fSolved )
|
||||
{
|
||||
p->fStoppedByCallback = 1;
|
||||
return 1;
|
||||
}
|
||||
if ( p->TimeToStop && Abc_Clock() >= p->TimeToStop )
|
||||
{
|
||||
p->fStoppedByTimeout = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result )
|
||||
|
|
@ -170,6 +237,547 @@ static int Cec_SProveCallback( void * pUser, int fSolved, unsigned Result )
|
|||
return pShare->fSolved != 0;
|
||||
}
|
||||
|
||||
static inline const char * Cec_SproveNetName( int NetId )
|
||||
{
|
||||
if ( NetId == SPROVE_NET_ORIG )
|
||||
return "orig";
|
||||
if ( NetId == SPROVE_NET_SCNEW )
|
||||
return "scnew";
|
||||
if ( NetId == SPROVE_NET_SCOLD )
|
||||
return "scold";
|
||||
return "unknown";
|
||||
}
|
||||
static inline int Cec_SproveNetId( const char * pName )
|
||||
{
|
||||
if ( !strcmp(pName, "orig") )
|
||||
return SPROVE_NET_ORIG;
|
||||
if ( !strcmp(pName, "scnew") )
|
||||
return SPROVE_NET_SCNEW;
|
||||
if ( !strcmp(pName, "scold") )
|
||||
return SPROVE_NET_SCOLD;
|
||||
return -1;
|
||||
}
|
||||
static inline const char * Cec_SproveStopName( int StopReason )
|
||||
{
|
||||
if ( StopReason == 1 )
|
||||
return "self";
|
||||
if ( StopReason == 2 )
|
||||
return "callback";
|
||||
if ( StopReason == 3 )
|
||||
return "timeout";
|
||||
if ( StopReason == 4 )
|
||||
return "skip";
|
||||
return "unknown";
|
||||
}
|
||||
static inline const char * Cec_SproveResultName( int RetValue )
|
||||
{
|
||||
if ( RetValue == 0 )
|
||||
return "sat";
|
||||
if ( RetValue == 1 )
|
||||
return "unsat";
|
||||
return "undecided";
|
||||
}
|
||||
static inline unsigned long long Cec_SproveClockToMs( abctime Time )
|
||||
{
|
||||
return (unsigned long long)(1000.0 * (double)Time / (double)CLOCKS_PER_SEC);
|
||||
}
|
||||
static int Cec_SproveFindValue( char * pLine, const char * pKey, char * pValue, int nValueSize )
|
||||
{
|
||||
char * pBeg = strstr( pLine, pKey );
|
||||
int i = 0;
|
||||
if ( pBeg == NULL )
|
||||
return 0;
|
||||
pBeg += strlen(pKey);
|
||||
while ( *pBeg && *pBeg != ' ' && *pBeg != '\t' && *pBeg != '\r' && *pBeg != '\n' )
|
||||
{
|
||||
if ( i < nValueSize - 1 )
|
||||
pValue[i++] = *pBeg;
|
||||
pBeg++;
|
||||
}
|
||||
pValue[i] = 0;
|
||||
return i > 0;
|
||||
}
|
||||
static int Cec_SproveParseEngineName( const char * pName )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i <= PAR_ENGINE_GLA; i++ )
|
||||
if ( !strcmp(pName, Cec_SolveEngineName(i)) )
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
static void Cec_SproveDeriveEngineList( int nProcs, int fUseUif, int * pEngines, int * pnEngines )
|
||||
{
|
||||
int i, nEngines = nProcs + (fUseUif ? 1 : 0);
|
||||
assert( nEngines >= 1 && nEngines <= PAR_THR_MAX );
|
||||
for ( i = 0; i < nEngines; i++ )
|
||||
{
|
||||
if ( fUseUif && i == nEngines - 1 )
|
||||
pEngines[i] = PAR_ENGINE_UFAR;
|
||||
else if ( !fUseUif && nEngines == 6 && i == 5 )
|
||||
pEngines[i] = PAR_ENGINE_GLA;
|
||||
else
|
||||
pEngines[i] = i;
|
||||
}
|
||||
*pnEngines = nEngines;
|
||||
}
|
||||
static void Cec_SprovePlanDefault( Cec_SprovePlan_t * pPlan, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif )
|
||||
{
|
||||
int nEngines;
|
||||
memset( pPlan, 0, sizeof(Cec_SprovePlan_t) );
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < SPROVE_STAGE_MAX; i++ )
|
||||
pPlan->Stages[i].GuardExistsNet = pPlan->Stages[i].GuardAndLimitNet = -1;
|
||||
}
|
||||
pPlan->nProcs = nProcs;
|
||||
pPlan->nTimeOut = nTimeOut;
|
||||
pPlan->nTimeOut2 = nTimeOut2;
|
||||
pPlan->nTimeOut3 = nTimeOut3;
|
||||
pPlan->fUseUif = fUseUif;
|
||||
pPlan->nStages = 4;
|
||||
Cec_SproveDeriveEngineList( nProcs, fUseUif, pPlan->Stages[0].RoundEngines, &nEngines );
|
||||
|
||||
pPlan->Stages[0].Id = 1;
|
||||
pPlan->Stages[0].fHasRound = 1;
|
||||
pPlan->Stages[0].RoundNet = SPROVE_NET_ORIG;
|
||||
pPlan->Stages[0].RoundTimeout = nTimeOut;
|
||||
pPlan->Stages[0].nRoundEngines = nEngines;
|
||||
pPlan->Stages[0].fHasReduce = 1;
|
||||
pPlan->Stages[0].ReduceType = PAR_ENGINE_SCORR1;
|
||||
pPlan->Stages[0].ReduceNetIn = SPROVE_NET_ORIG;
|
||||
pPlan->Stages[0].ReduceNetOut = SPROVE_NET_SCNEW;
|
||||
pPlan->Stages[0].ReduceTimeout = nTimeOut;
|
||||
|
||||
pPlan->Stages[1].Id = 2;
|
||||
pPlan->Stages[1].fGuardUnsolved = 1;
|
||||
pPlan->Stages[1].fHasRound = 1;
|
||||
pPlan->Stages[1].RoundNet = SPROVE_NET_SCNEW;
|
||||
pPlan->Stages[1].RoundTimeout = nTimeOut2;
|
||||
pPlan->Stages[1].nRoundEngines = nEngines;
|
||||
memcpy( pPlan->Stages[1].RoundEngines, pPlan->Stages[0].RoundEngines, sizeof(int) * nEngines );
|
||||
|
||||
pPlan->Stages[2].Id = 3;
|
||||
pPlan->Stages[2].fGuardUnsolved = 1;
|
||||
pPlan->Stages[2].GuardAndLimitNet = SPROVE_NET_SCNEW;
|
||||
pPlan->Stages[2].GuardAndLimit = 100000;
|
||||
pPlan->Stages[2].fHasReduce = 1;
|
||||
pPlan->Stages[2].ReduceType = PAR_ENGINE_SCORR2;
|
||||
pPlan->Stages[2].ReduceNetIn = SPROVE_NET_SCNEW;
|
||||
pPlan->Stages[2].ReduceNetOut = SPROVE_NET_SCOLD;
|
||||
pPlan->Stages[2].ReduceTimeout = nTimeOut3;
|
||||
|
||||
pPlan->Stages[3].Id = 4;
|
||||
pPlan->Stages[3].fGuardUnsolved = 1;
|
||||
pPlan->Stages[3].GuardExistsNet = SPROVE_NET_SCOLD;
|
||||
pPlan->Stages[3].fHasRound = 1;
|
||||
pPlan->Stages[3].RoundNet = SPROVE_NET_SCOLD;
|
||||
pPlan->Stages[3].RoundTimeout = nTimeOut3;
|
||||
pPlan->Stages[3].nRoundEngines = nEngines;
|
||||
memcpy( pPlan->Stages[3].RoundEngines, pPlan->Stages[0].RoundEngines, sizeof(int) * nEngines );
|
||||
}
|
||||
static void Cec_SproveTraceWrite( Cec_SproveTrace_t * pTrace, const char * pFormat, ... )
|
||||
{
|
||||
va_list args;
|
||||
if ( pTrace == NULL || !pTrace->fActive || pTrace->pFile == NULL )
|
||||
return;
|
||||
pthread_mutex_lock( &pTrace->Mutex );
|
||||
va_start( args, pFormat );
|
||||
vfprintf( pTrace->pFile, pFormat, args );
|
||||
va_end( args );
|
||||
fputc( '\n', pTrace->pFile );
|
||||
fflush( pTrace->pFile );
|
||||
pthread_mutex_unlock( &pTrace->Mutex );
|
||||
}
|
||||
static abctime Cec_SproveTraceTime( Cec_SproveTrace_t * pTrace )
|
||||
{
|
||||
return pTrace ? Abc_Clock() - pTrace->clkStart : 0;
|
||||
}
|
||||
static void Cec_SproveTraceOpen( Cec_SproveTrace_t * pTrace, Gia_Man_t * p, Cec_SprovePlan_t * pPlan, char * pReplayFile )
|
||||
{
|
||||
int i, k;
|
||||
char * pProbName = p->pSpec ? p->pSpec : Gia_ManName(p);
|
||||
memset( pTrace, 0, sizeof(Cec_SproveTrace_t) );
|
||||
if ( pReplayFile == NULL )
|
||||
return;
|
||||
pTrace->pFile = fopen( pReplayFile, "wb" );
|
||||
if ( pTrace->pFile == NULL )
|
||||
return;
|
||||
pTrace->fActive = 1;
|
||||
pTrace->clkStart = Abc_Clock();
|
||||
pthread_mutex_init( &pTrace->Mutex, NULL );
|
||||
Cec_SproveTraceWrite( pTrace, "SPROVE_REPLAY 1" );
|
||||
Cec_SproveTraceWrite( pTrace, "CASE %s", pProbName ? pProbName : "(none)" );
|
||||
Cec_SproveTraceWrite( pTrace, "PARAMS P=%d T=%d U=%d W=%d UIF=%d", pPlan->nProcs, pPlan->nTimeOut, pPlan->nTimeOut2, pPlan->nTimeOut3, pPlan->fUseUif );
|
||||
Cec_SproveTraceWrite( pTrace, "" );
|
||||
Cec_SproveTraceWrite( pTrace, "PLAN_BEGIN" );
|
||||
for ( i = 0; i < pPlan->nStages; i++ )
|
||||
{
|
||||
Cec_SproveStage_t * pStage = &pPlan->Stages[i];
|
||||
char Buffer[256];
|
||||
Buffer[0] = 0;
|
||||
if ( pStage->fGuardUnsolved )
|
||||
strcat( Buffer, "unsolved" );
|
||||
if ( pStage->GuardExistsNet >= 0 )
|
||||
sprintf( Buffer + strlen(Buffer), "%sexists(%s)", Buffer[0] ? "," : "", Cec_SproveNetName(pStage->GuardExistsNet) );
|
||||
if ( pStage->GuardAndLimitNet >= 0 )
|
||||
sprintf( Buffer + strlen(Buffer), "%sand_lt(%s,%d)", Buffer[0] ? "," : "", Cec_SproveNetName(pStage->GuardAndLimitNet), pStage->GuardAndLimit );
|
||||
if ( !Buffer[0] )
|
||||
strcpy( Buffer, "none" );
|
||||
if ( pStage->fHasRound )
|
||||
{
|
||||
char EngBuf[128];
|
||||
EngBuf[0] = 0;
|
||||
for ( k = 0; k < pStage->nRoundEngines; k++ )
|
||||
{
|
||||
if ( k > 0 )
|
||||
strcat( EngBuf, "," );
|
||||
strcat( EngBuf, Cec_SolveEngineName(pStage->RoundEngines[k]) );
|
||||
}
|
||||
Cec_SproveTraceWrite( pTrace, "ROUND stage=%d guard=%s net=%s timeout=%d engines=%s", pStage->Id, Buffer, Cec_SproveNetName(pStage->RoundNet), pStage->RoundTimeout, EngBuf );
|
||||
}
|
||||
if ( pStage->fHasReduce )
|
||||
Cec_SproveTraceWrite( pTrace, "REDUCE stage=%d guard=%s name=%s in=%s out=%s timeout=%d stop=callback_or_timeout", pStage->Id, Buffer, Cec_SolveEngineName(pStage->ReduceType), Cec_SproveNetName(pStage->ReduceNetIn), Cec_SproveNetName(pStage->ReduceNetOut), pStage->ReduceTimeout );
|
||||
}
|
||||
Cec_SproveTraceWrite( pTrace, "PLAN_END" );
|
||||
Cec_SproveTraceWrite( pTrace, "" );
|
||||
Cec_SproveTraceWrite( pTrace, "OBSERVED_BEGIN" );
|
||||
Cec_SproveTraceWrite( pTrace, "CHECKPOINT net=orig regs=%d ands=%d pos=%d", Gia_ManRegNum(p), Gia_ManAndNum(p), Gia_ManPoNum(p) );
|
||||
}
|
||||
static void Cec_SproveTraceClose( Cec_SproveTrace_t * pTrace )
|
||||
{
|
||||
if ( pTrace == NULL || !pTrace->fActive )
|
||||
return;
|
||||
Cec_SproveTraceWrite( pTrace, "OBSERVED_END" );
|
||||
pthread_mutex_destroy( &pTrace->Mutex );
|
||||
fclose( pTrace->pFile );
|
||||
pTrace->pFile = NULL;
|
||||
pTrace->fActive = 0;
|
||||
}
|
||||
static int Cec_SproveReplayReadParamsInt( char * pFileName, Cec_SprovePlan_t * pPlan )
|
||||
{
|
||||
char Buffer[1024], Value[256];
|
||||
FILE * pFile = fopen( pFileName, "rb" );
|
||||
if ( pFile == NULL )
|
||||
return 0;
|
||||
memset( pPlan, 0, sizeof(Cec_SprovePlan_t) );
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < SPROVE_STAGE_MAX; i++ )
|
||||
pPlan->Stages[i].GuardExistsNet = pPlan->Stages[i].GuardAndLimitNet = -1;
|
||||
}
|
||||
while ( fgets( Buffer, sizeof(Buffer), pFile ) != NULL )
|
||||
{
|
||||
if ( strncmp(Buffer, "PARAMS ", 7) == 0 )
|
||||
{
|
||||
if ( !Cec_SproveFindValue(Buffer, "P=", Value, sizeof(Value)) ) break;
|
||||
pPlan->nProcs = atoi(Value);
|
||||
if ( !Cec_SproveFindValue(Buffer, "T=", Value, sizeof(Value)) ) break;
|
||||
pPlan->nTimeOut = atoi(Value);
|
||||
if ( !Cec_SproveFindValue(Buffer, "U=", Value, sizeof(Value)) ) break;
|
||||
pPlan->nTimeOut2 = atoi(Value);
|
||||
if ( !Cec_SproveFindValue(Buffer, "W=", Value, sizeof(Value)) ) break;
|
||||
pPlan->nTimeOut3 = atoi(Value);
|
||||
if ( !Cec_SproveFindValue(Buffer, "UIF=", Value, sizeof(Value)) ) break;
|
||||
pPlan->fUseUif = atoi(Value);
|
||||
fclose( pFile );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
fclose( pFile );
|
||||
return 0;
|
||||
}
|
||||
static int Cec_SproveReplayReadPlan( char * pFileName, Cec_SprovePlan_t * pPlan )
|
||||
{
|
||||
char Buffer[1024], Value[256], Guard[256], Engines[256];
|
||||
FILE * pFile;
|
||||
int fInPlan = 0;
|
||||
if ( !Cec_SproveReplayReadParamsInt( pFileName, pPlan ) )
|
||||
return 0;
|
||||
pFile = fopen( pFileName, "rb" );
|
||||
if ( pFile == NULL )
|
||||
return 0;
|
||||
while ( fgets( Buffer, sizeof(Buffer), pFile ) != NULL )
|
||||
{
|
||||
Cec_SproveStage_t * pStage;
|
||||
int StageId;
|
||||
if ( strncmp(Buffer, "PLAN_BEGIN", 10) == 0 )
|
||||
{
|
||||
fInPlan = 1;
|
||||
continue;
|
||||
}
|
||||
if ( strncmp(Buffer, "PLAN_END", 8) == 0 || strncmp(Buffer, "OBSERVED_BEGIN", 14) == 0 )
|
||||
break;
|
||||
if ( !fInPlan )
|
||||
continue;
|
||||
if ( strncmp(Buffer, "ROUND ", 6) == 0 )
|
||||
{
|
||||
char * pTok;
|
||||
int nEngines = 0;
|
||||
if ( !Cec_SproveFindValue(Buffer, "stage=", Value, sizeof(Value)) )
|
||||
continue;
|
||||
StageId = atoi(Value);
|
||||
if ( StageId < 1 || StageId > SPROVE_STAGE_MAX )
|
||||
continue;
|
||||
pStage = &pPlan->Stages[StageId - 1];
|
||||
if ( StageId > pPlan->nStages )
|
||||
pPlan->nStages = StageId;
|
||||
memset( Guard, 0, sizeof(Guard) );
|
||||
Cec_SproveFindValue(Buffer, "guard=", Guard, sizeof(Guard));
|
||||
pStage->Id = StageId;
|
||||
pStage->fGuardUnsolved = strstr( Guard, "unsolved" ) != NULL;
|
||||
if ( strstr(Guard, "exists(") )
|
||||
{
|
||||
sscanf( strstr(Guard, "exists("), "exists(%255[^)])", Value );
|
||||
pStage->GuardExistsNet = Cec_SproveNetId( Value );
|
||||
}
|
||||
if ( strstr(Guard, "and_lt(") )
|
||||
{
|
||||
sscanf( strstr(Guard, "and_lt("), "and_lt(%255[^,],%d)", Value, &pStage->GuardAndLimit );
|
||||
pStage->GuardAndLimitNet = Cec_SproveNetId( Value );
|
||||
}
|
||||
if ( Cec_SproveFindValue(Buffer, "net=", Value, sizeof(Value)) )
|
||||
pStage->RoundNet = Cec_SproveNetId( Value );
|
||||
if ( Cec_SproveFindValue(Buffer, "timeout=", Value, sizeof(Value)) )
|
||||
pStage->RoundTimeout = atoi(Value);
|
||||
if ( Cec_SproveFindValue(Buffer, "engines=", Engines, sizeof(Engines)) )
|
||||
{
|
||||
pTok = strtok( Engines, "," );
|
||||
while ( pTok && nEngines < PAR_THR_MAX )
|
||||
{
|
||||
pStage->RoundEngines[nEngines++] = Cec_SproveParseEngineName( pTok );
|
||||
pTok = strtok( NULL, "," );
|
||||
}
|
||||
}
|
||||
pStage->fHasRound = 1;
|
||||
pStage->nRoundEngines = nEngines;
|
||||
}
|
||||
else if ( strncmp(Buffer, "REDUCE ", 7) == 0 )
|
||||
{
|
||||
if ( !Cec_SproveFindValue(Buffer, "stage=", Value, sizeof(Value)) )
|
||||
continue;
|
||||
StageId = atoi(Value);
|
||||
if ( StageId < 1 || StageId > SPROVE_STAGE_MAX )
|
||||
continue;
|
||||
pStage = &pPlan->Stages[StageId - 1];
|
||||
if ( StageId > pPlan->nStages )
|
||||
pPlan->nStages = StageId;
|
||||
memset( Guard, 0, sizeof(Guard) );
|
||||
Cec_SproveFindValue(Buffer, "guard=", Guard, sizeof(Guard));
|
||||
pStage->Id = StageId;
|
||||
pStage->fGuardUnsolved = strstr( Guard, "unsolved" ) != NULL;
|
||||
if ( strstr(Guard, "exists(") )
|
||||
{
|
||||
sscanf( strstr(Guard, "exists("), "exists(%255[^)])", Value );
|
||||
pStage->GuardExistsNet = Cec_SproveNetId( Value );
|
||||
}
|
||||
if ( strstr(Guard, "and_lt(") )
|
||||
{
|
||||
sscanf( strstr(Guard, "and_lt("), "and_lt(%255[^,],%d)", Value, &pStage->GuardAndLimit );
|
||||
pStage->GuardAndLimitNet = Cec_SproveNetId( Value );
|
||||
}
|
||||
if ( Cec_SproveFindValue(Buffer, "name=", Value, sizeof(Value)) )
|
||||
pStage->ReduceType = Cec_SproveParseEngineName( Value );
|
||||
if ( Cec_SproveFindValue(Buffer, "in=", Value, sizeof(Value)) )
|
||||
pStage->ReduceNetIn = Cec_SproveNetId( Value );
|
||||
if ( Cec_SproveFindValue(Buffer, "out=", Value, sizeof(Value)) )
|
||||
pStage->ReduceNetOut = Cec_SproveNetId( Value );
|
||||
if ( Cec_SproveFindValue(Buffer, "timeout=", Value, sizeof(Value)) )
|
||||
pStage->ReduceTimeout = atoi(Value);
|
||||
pStage->fHasReduce = 1;
|
||||
}
|
||||
}
|
||||
fclose( pFile );
|
||||
return pPlan->nStages > 0;
|
||||
}
|
||||
static Gia_Man_t * Cec_SproveGetNet( int NetId, Gia_Man_t * pOrig, Gia_Man_t * pScorr, Gia_Man_t * pScorr2 )
|
||||
{
|
||||
if ( NetId == SPROVE_NET_ORIG )
|
||||
return pOrig;
|
||||
if ( NetId == SPROVE_NET_SCNEW )
|
||||
return pScorr;
|
||||
if ( NetId == SPROVE_NET_SCOLD )
|
||||
return pScorr2;
|
||||
return NULL;
|
||||
}
|
||||
static void Cec_SproveSetNet( int NetId, Gia_Man_t ** ppScorr, Gia_Man_t ** ppScorr2, Gia_Man_t * pNet )
|
||||
{
|
||||
if ( NetId == SPROVE_NET_SCNEW )
|
||||
{
|
||||
Gia_ManStopP( ppScorr );
|
||||
*ppScorr = pNet;
|
||||
}
|
||||
else if ( NetId == SPROVE_NET_SCOLD )
|
||||
{
|
||||
Gia_ManStopP( ppScorr2 );
|
||||
*ppScorr2 = pNet;
|
||||
}
|
||||
else
|
||||
Gia_ManStop( pNet );
|
||||
}
|
||||
static int Cec_SproveCheckGuard( Cec_SproveStage_t * pStage, int RetValue, Gia_Man_t * pOrig, Gia_Man_t * pScorr, Gia_Man_t * pScorr2 )
|
||||
{
|
||||
Gia_Man_t * pNet;
|
||||
if ( pStage->fGuardUnsolved && RetValue != -1 )
|
||||
return 0;
|
||||
if ( pStage->GuardExistsNet >= 0 && Cec_SproveGetNet( pStage->GuardExistsNet, pOrig, pScorr, pScorr2 ) == NULL )
|
||||
return 0;
|
||||
if ( pStage->GuardAndLimitNet >= 0 )
|
||||
{
|
||||
pNet = Cec_SproveGetNet( pStage->GuardAndLimitNet, pOrig, pScorr, pScorr2 );
|
||||
if ( pNet == NULL || Gia_ManAndNum(pNet) >= pStage->GuardAndLimit )
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
static void Cec_SproveTraceCheckpoint( Cec_SproveTrace_t * pTrace, int NetId, Gia_Man_t * pNet )
|
||||
{
|
||||
if ( pTrace == NULL || !pTrace->fActive || pNet == NULL )
|
||||
return;
|
||||
Cec_SproveTraceWrite( pTrace, "CHECKPOINT net=%s regs=%d ands=%d pos=%d", Cec_SproveNetName(NetId), Gia_ManRegNum(pNet), Gia_ManAndNum(pNet), Gia_ManPoNum(pNet) );
|
||||
}
|
||||
static Gia_Man_t * Cec_SproveRunReduce( Gia_Man_t * pInput, Cec_SproveStage_t * pStage, Par_Share_t * pShare, Cec_SproveTrace_t * pTrace, abctime * pClkUsed, int * pRetValue, int * pRetEngine )
|
||||
{
|
||||
Cec_ScorrStop_t Stop;
|
||||
abctime clk = Abc_Clock();
|
||||
Gia_Man_t * pOutput = NULL;
|
||||
int StopReason = 1;
|
||||
memset( &Stop, 0, sizeof(Stop) );
|
||||
if ( pTrace && pTrace->fActive )
|
||||
Cec_SproveTraceWrite( pTrace, "START kind=reduce stage=%d name=%s in=%s out=%s timeout=%d t=%llu",
|
||||
pStage->Id, Cec_SolveEngineName(pStage->ReduceType), Cec_SproveNetName(pStage->ReduceNetIn), Cec_SproveNetName(pStage->ReduceNetOut), pStage->ReduceTimeout,
|
||||
Cec_SproveClockToMs( Cec_SproveTraceTime(pTrace) ) );
|
||||
if ( pStage->ReduceType == PAR_ENGINE_SCORR1 )
|
||||
pOutput = Cec_GiaScorrNew( pInput, pStage->ReduceTimeout, pShare, &Stop );
|
||||
else if ( pStage->ReduceType == PAR_ENGINE_SCORR2 )
|
||||
pOutput = Cec_GiaScorrOld( pInput, pStage->ReduceTimeout, pShare, &Stop );
|
||||
else
|
||||
assert( 0 );
|
||||
if ( Gia_ManAndNum(pOutput) == 0 )
|
||||
{
|
||||
pShare->fSolved = 1;
|
||||
pShare->Result = 1;
|
||||
pShare->iEngine = pStage->ReduceType;
|
||||
*pRetValue = 1;
|
||||
*pRetEngine = pStage->ReduceType;
|
||||
}
|
||||
if ( Stop.fStoppedByCallback )
|
||||
StopReason = 2;
|
||||
else if ( Stop.fStoppedByTimeout )
|
||||
StopReason = 3;
|
||||
if ( pClkUsed )
|
||||
*pClkUsed = Abc_Clock() - clk;
|
||||
if ( pTrace && pTrace->fActive )
|
||||
{
|
||||
Cec_SproveTraceWrite( pTrace, "STOP kind=reduce stage=%d name=%s in=%s out=%s result=%s stop=%s t=%llu elapsed=%llu",
|
||||
pStage->Id, Cec_SolveEngineName(pStage->ReduceType), Cec_SproveNetName(pStage->ReduceNetIn), Cec_SproveNetName(pStage->ReduceNetOut),
|
||||
*pRetEngine == pStage->ReduceType ? Cec_SproveResultName(*pRetValue) : "undecided",
|
||||
Cec_SproveStopName(StopReason), Cec_SproveClockToMs( Cec_SproveTraceTime(pTrace) ), Cec_SproveClockToMs( Abc_Clock() - clk ) );
|
||||
Cec_SproveTraceCheckpoint( pTrace, pStage->ReduceNetOut, pOutput );
|
||||
}
|
||||
return pOutput;
|
||||
}
|
||||
static int Cec_SproveExecutePlan( Gia_Man_t * p, Cec_SprovePlan_t * pPlan, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile )
|
||||
{
|
||||
abctime clkTotal = Abc_Clock(), clkStage = 0;
|
||||
Par_ThData_t ThData[PAR_THR_MAX];
|
||||
pthread_t WorkerThread[PAR_THR_MAX];
|
||||
Par_Share_t Share;
|
||||
Cec_SproveTrace_t Trace;
|
||||
Gia_Man_t * pScorr = NULL, * pScorr2 = NULL;
|
||||
int i, RetValue = -1, RetEngine = -1, fThreadsStarted = 0;
|
||||
(void)fVeryVerbose;
|
||||
memset( &Share, 0, sizeof(Par_Share_t) );
|
||||
memset( &Trace, 0, sizeof(Cec_SproveTrace_t) );
|
||||
memset( ThData, 0, sizeof(ThData) );
|
||||
memset( WorkerThread, 0, sizeof(WorkerThread) );
|
||||
Abc_CexFreeP( &p->pCexComb );
|
||||
Abc_CexFreeP( &p->pCexSeq );
|
||||
if ( !fSilent && fVerbose )
|
||||
printf( "Solving verification problem with the following parameters:\n" );
|
||||
if ( !fSilent && fVerbose )
|
||||
printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", pPlan->nProcs, pPlan->nTimeOut, fVerbose );
|
||||
fflush( stdout );
|
||||
Cec_SproveTraceOpen( &Trace, p, pPlan, pReplayFile );
|
||||
for ( i = 0; i < pPlan->nStages; i++ )
|
||||
{
|
||||
Cec_SproveStage_t * pStage = &pPlan->Stages[i];
|
||||
Gia_Man_t * pRoundNet = NULL, * pReduceNet = NULL, * pReduceOut = NULL;
|
||||
if ( !Cec_SproveCheckGuard( pStage, RetValue, p, pScorr, pScorr2 ) )
|
||||
{
|
||||
Cec_SproveTraceWrite( &Trace, "SKIP stage=%d reason=guard", pStage->Id );
|
||||
continue;
|
||||
}
|
||||
if ( pStage->fHasRound )
|
||||
{
|
||||
pRoundNet = Cec_SproveGetNet( pStage->RoundNet, p, pScorr, pScorr2 );
|
||||
if ( pRoundNet == NULL )
|
||||
{
|
||||
Cec_SproveTraceWrite( &Trace, "SKIP stage=%d reason=missing_round_net", pStage->Id );
|
||||
continue;
|
||||
}
|
||||
Cec_SproveTraceWrite( &Trace, "START kind=round stage=%d net=%s timeout=%d t=%llu",
|
||||
pStage->Id, Cec_SproveNetName(pStage->RoundNet), pStage->RoundTimeout, Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) );
|
||||
Cec_GiaInitThreads( ThData, pStage->nRoundEngines, pRoundNet, pStage->RoundTimeout, pPlan->nTimeOut3, pWlc, fVerbose,
|
||||
fThreadsStarted ? NULL : WorkerThread, &Share, pStage->RoundEngines, pStage->Id, pStage->RoundNet, &Trace );
|
||||
fThreadsStarted = 1;
|
||||
}
|
||||
if ( pStage->fHasReduce )
|
||||
{
|
||||
pReduceNet = Cec_SproveGetNet( pStage->ReduceNetIn, p, pScorr, pScorr2 );
|
||||
if ( pReduceNet == NULL )
|
||||
Cec_SproveTraceWrite( &Trace, "SKIP stage=%d reason=missing_reduce_net", pStage->Id );
|
||||
else
|
||||
{
|
||||
pReduceOut = Cec_SproveRunReduce( pReduceNet, pStage, &Share, &Trace, &clkStage, &RetValue, &RetEngine );
|
||||
Cec_SproveSetNet( pStage->ReduceNetOut, &pScorr, &pScorr2, pReduceOut );
|
||||
}
|
||||
}
|
||||
if ( pStage->fHasRound )
|
||||
{
|
||||
RetValue = Cec_GiaWaitThreads( ThData, pStage->nRoundEngines, p, RetValue, &RetEngine );
|
||||
Cec_SproveTraceWrite( &Trace, "STOP kind=round stage=%d net=%s result=%s winner=%s t=%llu",
|
||||
pStage->Id, Cec_SproveNetName(pStage->RoundNet), Cec_SproveResultName(RetValue),
|
||||
RetEngine >= 0 ? Cec_SolveEngineName(RetEngine) : "none", Cec_SproveClockToMs( Cec_SproveTraceTime(&Trace) ) );
|
||||
}
|
||||
if ( pStage->fHasReduce && RetValue == -1 && !fSilent && fVerbose )
|
||||
{
|
||||
Gia_Man_t * pAfter = Cec_SproveGetNet( pStage->ReduceNetOut, p, pScorr, pScorr2 );
|
||||
if ( pAfter )
|
||||
{
|
||||
printf( "Reduced the miter from %d to %d nodes. ",
|
||||
Gia_ManAndNum(Cec_SproveGetNet(pStage->ReduceNetIn, p, pScorr, pScorr2)), Gia_ManAndNum(pAfter) );
|
||||
Abc_PrintTime( 1, "Time", clkStage );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( fThreadsStarted )
|
||||
Cec_GiaStopThreads( ThData, WorkerThread, pPlan->Stages[0].nRoundEngines > 0 ? pPlan->Stages[0].nRoundEngines : pPlan->nProcs + (pPlan->fUseUif ? 1 : 0) );
|
||||
Gia_ManStopP( &pScorr2 );
|
||||
Gia_ManStopP( &pScorr );
|
||||
if ( !fSilent )
|
||||
{
|
||||
char * pProbName = p->pSpec ? p->pSpec : Gia_ManName(p);
|
||||
if ( RetValue != -1 && RetEngine < 0 )
|
||||
RetEngine = PAR_ENGINE_SCORR1;
|
||||
printf( "Problem \"%s\" is ", pProbName ? pProbName : "(none)" );
|
||||
if ( RetValue == 0 )
|
||||
printf( "SATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) );
|
||||
else if ( RetValue == 1 )
|
||||
printf( "UNSATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) );
|
||||
else if ( RetValue == -1 )
|
||||
printf( "UNDECIDED." );
|
||||
else assert( 0 );
|
||||
printf( " " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal );
|
||||
fflush( stdout );
|
||||
}
|
||||
Cec_SproveTraceWrite( &Trace, "FINAL result=%s winner=%s total=%llu",
|
||||
Cec_SproveResultName(RetValue), RetEngine >= 0 ? Cec_SolveEngineName(RetEngine) : "none",
|
||||
Cec_SproveClockToMs( Abc_Clock() - clkTotal ) );
|
||||
Cec_SproveTraceClose( &Trace );
|
||||
return RetValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -189,10 +797,18 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par
|
|||
{
|
||||
abctime clk = Abc_Clock();
|
||||
int RetValue = -1;
|
||||
if ( pThData && pThData->pTrace )
|
||||
Cec_SproveTraceWrite( pThData->pTrace, "START kind=engine stage=%d net=%s engine=%s worker=%d timeout=%d t=%llu",
|
||||
pThData->StageId, Cec_SproveNetName(pThData->NetId), Cec_SolveEngineName(iEngine), pThData->WorkerId, nTimeOut,
|
||||
Cec_SproveClockToMs( Cec_SproveTraceTime(pThData->pTrace) ) );
|
||||
if ( iEngine != PAR_ENGINE_UFAR && iEngine != PAR_ENGINE_GLA && Gia_ManRegNum(p) == 0 )
|
||||
{
|
||||
if ( fVerbose )
|
||||
printf( "Engine %d (%-5s) skipped because the current miter is combinational.\n", iEngine, Cec_SolveEngineName(iEngine) );
|
||||
if ( pThData && pThData->pTrace )
|
||||
Cec_SproveTraceWrite( pThData->pTrace, "STOP kind=engine stage=%d net=%s engine=%s worker=%d result=undecided stop=skip t=%llu",
|
||||
pThData->StageId, Cec_SproveNetName(pThData->NetId), Cec_SolveEngineName(iEngine), pThData->WorkerId,
|
||||
Cec_SproveClockToMs( Cec_SproveTraceTime(pThData->pTrace) ) );
|
||||
return -1;
|
||||
}
|
||||
//abctime clkStop = nTimeOut * CLOCKS_PER_SEC + Abc_Clock();
|
||||
|
|
@ -326,19 +942,39 @@ int Cec_GiaProveOne( Gia_Man_t * p, int iEngine, int nTimeOut, int fVerbose, Par
|
|||
//while ( Abc_Clock() < clkStop );
|
||||
if ( pThData && pThData->pShare && RetValue != -1 )
|
||||
Cec_SProveCallback( (void *)pThData, 1, (unsigned)RetValue );
|
||||
if ( pThData )
|
||||
{
|
||||
if ( RetValue != -1 )
|
||||
pThData->StopReason = 1;
|
||||
else if ( pThData->pShare && pThData->pShare->fSolved )
|
||||
pThData->StopReason = 2;
|
||||
else
|
||||
pThData->StopReason = 3;
|
||||
}
|
||||
if ( pThData && pThData->pTrace )
|
||||
Cec_SproveTraceWrite( pThData->pTrace, "STOP kind=engine stage=%d net=%s engine=%s worker=%d result=%s stop=%s t=%llu elapsed=%llu",
|
||||
pThData->StageId, Cec_SproveNetName(pThData->NetId), Cec_SolveEngineName(iEngine), pThData->WorkerId,
|
||||
Cec_SproveResultName(RetValue), Cec_SproveStopName(pThData->StopReason),
|
||||
Cec_SproveClockToMs( Cec_SproveTraceTime(pThData->pTrace) ),
|
||||
Cec_SproveClockToMs( Abc_Clock() - clk ) );
|
||||
if ( fVerbose ) {
|
||||
printf( "Engine %d (%-5s) finished and %ssolved the problem. ", iEngine, Cec_SolveEngineName(iEngine), RetValue != -1 ? " " : "not " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
}
|
||||
return RetValue;
|
||||
}
|
||||
Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare )
|
||||
Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, Cec_ScorrStop_t * pStopOut )
|
||||
{
|
||||
Cec_ScorrStop_t Stop;
|
||||
memset( &Stop, 0, sizeof(Stop) );
|
||||
Stop.pShare = pShare;
|
||||
Stop.TimeToStop = nTimeOut > 0 ? (abctime)(Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC) : 0;
|
||||
if ( Gia_ManRegNum(p) == 0 )
|
||||
{
|
||||
if ( pStopOut )
|
||||
*pStopOut = Stop;
|
||||
return Gia_ManDup( p );
|
||||
}
|
||||
Ssw_Pars_t Pars, * pPars = &Pars;
|
||||
Ssw_ManSetDefaultParams( pPars );
|
||||
pPars->pFunc = (void *)Cec_ScorrStop;
|
||||
|
|
@ -348,15 +984,22 @@ Gia_Man_t * Cec_GiaScorrOld( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare )
|
|||
Gia_Man_t * pGia2 = Gia_ManFromAigSimple( pAig2 );
|
||||
Aig_ManStop( pAig2 );
|
||||
Aig_ManStop( pAig );
|
||||
if ( pStopOut )
|
||||
*pStopOut = Stop;
|
||||
return pGia2;
|
||||
}
|
||||
Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare )
|
||||
Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare, Cec_ScorrStop_t * pStopOut )
|
||||
{
|
||||
Cec_ScorrStop_t Stop;
|
||||
memset( &Stop, 0, sizeof(Stop) );
|
||||
Stop.pShare = pShare;
|
||||
Stop.TimeToStop = nTimeOut > 0 ? (abctime)(Abc_Clock() + (abctime)nTimeOut * CLOCKS_PER_SEC) : 0;
|
||||
if ( Gia_ManRegNum(p) == 0 )
|
||||
{
|
||||
if ( pStopOut )
|
||||
*pStopOut = Stop;
|
||||
return Gia_ManDup( p );
|
||||
}
|
||||
Cec_ParCor_t Pars, * pPars = &Pars;
|
||||
Cec_ManCorSetDefaultParams( pPars );
|
||||
pPars->nBTLimit = 100;
|
||||
|
|
@ -365,7 +1008,10 @@ Gia_Man_t * Cec_GiaScorrNew( Gia_Man_t * p, int nTimeOut, Par_Share_t * pShare )
|
|||
pPars->fUseCSat = 1;
|
||||
pPars->pFunc = (void *)Cec_ScorrStop;
|
||||
pPars->pData = (void *)&Stop;
|
||||
return Cec_ManLSCorrespondence( p, pPars );
|
||||
p = Cec_ManLSCorrespondence( p, pPars );
|
||||
if ( pStopOut )
|
||||
*pStopOut = Stop;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
|
@ -424,7 +1070,7 @@ static void Cec_GiaStartThreads( Par_ThData_t * ThData, int nWorkers )
|
|||
assert( status == 0 );
|
||||
}
|
||||
}
|
||||
static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fUseUif, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare )
|
||||
static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t * p, int nTimeOut, int nTimeOutU, Wlc_Ntk_t * pWlc, int fVerbose, pthread_t * WorkerThread, Par_Share_t * pShare, int * pEngines, int StageId, int NetId, Cec_SproveTrace_t * pTrace )
|
||||
{
|
||||
int i, status;
|
||||
assert( nWorkers <= PAR_THR_MAX );
|
||||
|
|
@ -434,12 +1080,7 @@ static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t *
|
|||
{
|
||||
ThData[i].p = Gia_ManDup( p );
|
||||
Cec_CopyGiaName( p, ThData[i].p );
|
||||
if ( fUseUif && i == nWorkers - 1 )
|
||||
ThData[i].iEngine = PAR_ENGINE_UFAR;
|
||||
else if ( !fUseUif && nWorkers == 6 && i == 5 )
|
||||
ThData[i].iEngine = PAR_ENGINE_GLA;
|
||||
else
|
||||
ThData[i].iEngine = i;
|
||||
ThData[i].iEngine = pEngines[i];
|
||||
ThData[i].fWorking = 0;
|
||||
ThData[i].fStop = 0;
|
||||
ThData[i].nTimeOut = nTimeOut;
|
||||
|
|
@ -447,7 +1088,12 @@ static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t *
|
|||
ThData[i].fVerbose = fVerbose;
|
||||
ThData[i].nTimeOutU= nTimeOutU;
|
||||
ThData[i].pWlc = pWlc;
|
||||
ThData[i].WorkerId = i;
|
||||
ThData[i].StageId = StageId;
|
||||
ThData[i].NetId = NetId;
|
||||
ThData[i].StopReason = 0;
|
||||
ThData[i].pShare = pShare;
|
||||
ThData[i].pTrace = pTrace;
|
||||
status = pthread_mutex_init( &ThData[i].Mutex, NULL );
|
||||
assert( status == 0 );
|
||||
status = pthread_cond_init( &ThData[i].Cond, NULL );
|
||||
|
|
@ -463,18 +1109,18 @@ static void Cec_GiaInitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t *
|
|||
Gia_ManStopP( &ThData[i].p );
|
||||
ThData[i].p = Gia_ManDup( p );
|
||||
Cec_CopyGiaName( p, ThData[i].p );
|
||||
if ( fUseUif && i == nWorkers - 1 )
|
||||
ThData[i].iEngine = PAR_ENGINE_UFAR;
|
||||
else if ( !fUseUif && nWorkers == 6 && i == 5 )
|
||||
ThData[i].iEngine = PAR_ENGINE_GLA;
|
||||
else
|
||||
ThData[i].iEngine = i;
|
||||
ThData[i].iEngine = pEngines[i];
|
||||
ThData[i].nTimeOut = nTimeOut;
|
||||
ThData[i].Result = -1;
|
||||
ThData[i].fVerbose = fVerbose;
|
||||
ThData[i].nTimeOutU= nTimeOutU;
|
||||
ThData[i].pWlc = pWlc;
|
||||
ThData[i].WorkerId = i;
|
||||
ThData[i].StageId = StageId;
|
||||
ThData[i].NetId = NetId;
|
||||
ThData[i].StopReason = 0;
|
||||
ThData[i].pShare = pShare;
|
||||
ThData[i].pTrace = pTrace;
|
||||
status = pthread_mutex_unlock( &ThData[i].Mutex );
|
||||
assert( status == 0 );
|
||||
}
|
||||
|
|
@ -527,99 +1173,37 @@ static int Cec_GiaWaitThreads( Par_ThData_t * ThData, int nWorkers, Gia_Man_t *
|
|||
return RetValue;
|
||||
}
|
||||
|
||||
int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent )
|
||||
int Cec_GiaReplayReadParams( char * pFileName, int * pnProcs, int * pnTimeOut, int * pnTimeOut2, int * pnTimeOut3, int * pfUseUif )
|
||||
{
|
||||
abctime clkScorr = 0, clkTotal = Abc_Clock();
|
||||
Par_ThData_t ThData[PAR_THR_MAX];
|
||||
pthread_t WorkerThread[PAR_THR_MAX];
|
||||
Par_Share_t Share;
|
||||
int nWorkers = nProcs + (fUseUif ? 1 : 0), RetValue = -1, RetEngine = -1;
|
||||
memset( &Share, 0, sizeof(Par_Share_t) );
|
||||
memset( ThData, 0, sizeof(ThData) );
|
||||
memset( WorkerThread, 0, sizeof(WorkerThread) );
|
||||
Abc_CexFreeP( &p->pCexComb );
|
||||
Abc_CexFreeP( &p->pCexSeq );
|
||||
if ( !fSilent && fVerbose )
|
||||
printf( "Solving verification problem with the following parameters:\n" );
|
||||
if ( !fSilent && fVerbose )
|
||||
printf( "Processes = %d TimeOut = %d sec Verbose = %d.\n", nProcs, nTimeOut, fVerbose );
|
||||
fflush( stdout );
|
||||
|
||||
Cec_SprovePlan_t Plan;
|
||||
if ( !Cec_SproveReplayReadParamsInt( pFileName, &Plan ) )
|
||||
return 0;
|
||||
if ( pnProcs )
|
||||
*pnProcs = Plan.nProcs;
|
||||
if ( pnTimeOut )
|
||||
*pnTimeOut = Plan.nTimeOut;
|
||||
if ( pnTimeOut2 )
|
||||
*pnTimeOut2 = Plan.nTimeOut2;
|
||||
if ( pnTimeOut3 )
|
||||
*pnTimeOut3 = Plan.nTimeOut3;
|
||||
if ( pfUseUif )
|
||||
*pfUseUif = Plan.fUseUif;
|
||||
return 1;
|
||||
}
|
||||
int Cec_GiaProveTest( Gia_Man_t * p, int nProcs, int nTimeOut, int nTimeOut2, int nTimeOut3, int fUseUif, Wlc_Ntk_t * pWlc, int fVerbose, int fVeryVerbose, int fSilent, char * pReplayFile )
|
||||
{
|
||||
Cec_SprovePlan_t Plan;
|
||||
Cec_SprovePlanDefault( &Plan, nProcs, nTimeOut, nTimeOut2, nTimeOut3, fUseUif );
|
||||
assert( nProcs >= 1 && nProcs <= 6 );
|
||||
assert( nWorkers <= PAR_THR_MAX );
|
||||
Cec_GiaInitThreads( ThData, nWorkers, p, nTimeOut, nTimeOut3, pWlc, fUseUif, fVerbose, WorkerThread, &Share );
|
||||
|
||||
// meanwhile, perform scorr
|
||||
Gia_Man_t * pScorr = Cec_GiaScorrNew( p, nTimeOut, &Share );
|
||||
clkScorr = Abc_Clock() - clkTotal;
|
||||
if ( Gia_ManAndNum(pScorr) == 0 )
|
||||
{
|
||||
Share.fSolved = 1;
|
||||
Share.Result = 1;
|
||||
Share.iEngine = PAR_ENGINE_SCORR1;
|
||||
RetValue = 1, RetEngine = PAR_ENGINE_SCORR1;
|
||||
}
|
||||
|
||||
RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine );
|
||||
if ( RetValue == -1 )
|
||||
{
|
||||
abctime clkScorr2, clkStart = Abc_Clock();
|
||||
if ( !fSilent && fVerbose ) {
|
||||
printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(p), Gia_ManAndNum(pScorr) );
|
||||
Abc_PrintTime( 1, "Time", clkScorr );
|
||||
}
|
||||
Cec_GiaInitThreads( ThData, nWorkers, pScorr, nTimeOut2, nTimeOut3, pWlc, fUseUif, fVerbose, NULL, &Share );
|
||||
|
||||
RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine );
|
||||
if ( RetValue == -1 && Gia_ManAndNum(pScorr) < 100000 )
|
||||
{
|
||||
// Run this reduction only when round-2 did not decide the problem.
|
||||
Gia_Man_t * pScorr2 = Cec_GiaScorrOld( pScorr, nTimeOut3, &Share );
|
||||
clkScorr2 = Abc_Clock() - clkStart;
|
||||
if ( Gia_ManAndNum(pScorr2) == 0 )
|
||||
{
|
||||
Share.fSolved = 1;
|
||||
Share.Result = 1;
|
||||
Share.iEngine = PAR_ENGINE_SCORR2;
|
||||
RetValue = 1, RetEngine = PAR_ENGINE_SCORR2;
|
||||
}
|
||||
|
||||
if ( RetValue == -1 )
|
||||
{
|
||||
if ( !fSilent && fVerbose ) {
|
||||
printf( "Reduced the miter from %d to %d nodes. ", Gia_ManAndNum(pScorr), Gia_ManAndNum(pScorr2) );
|
||||
Abc_PrintTime( 1, "Time", clkScorr2 );
|
||||
}
|
||||
Cec_GiaInitThreads( ThData, nWorkers, pScorr2, nTimeOut3, nTimeOut3, pWlc, fUseUif, fVerbose, NULL, &Share );
|
||||
|
||||
RetValue = Cec_GiaWaitThreads( ThData, nWorkers, p, RetValue, &RetEngine );
|
||||
// do something else
|
||||
}
|
||||
Gia_ManStop( pScorr2 );
|
||||
}
|
||||
}
|
||||
Gia_ManStop( pScorr );
|
||||
|
||||
// stop threads
|
||||
Cec_GiaStopThreads( ThData, WorkerThread, nWorkers );
|
||||
if ( !fSilent )
|
||||
{
|
||||
char * pProbName = p->pSpec ? p->pSpec : Gia_ManName(p);
|
||||
if ( RetValue != -1 && RetEngine < 0 )
|
||||
RetEngine = PAR_ENGINE_SCORR1;
|
||||
printf( "Problem \"%s\" is ", pProbName ? pProbName : "(none)" );
|
||||
if ( RetValue == 0 )
|
||||
printf( "SATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) );
|
||||
else if ( RetValue == 1 )
|
||||
printf( "UNSATISFIABLE (solved by %s).", Cec_SolveEngineName(RetEngine) );
|
||||
else if ( RetValue == -1 )
|
||||
printf( "UNDECIDED." );
|
||||
else assert( 0 );
|
||||
printf( " " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clkTotal );
|
||||
fflush( stdout );
|
||||
}
|
||||
return RetValue;
|
||||
assert( nProcs + (fUseUif ? 1 : 0) <= PAR_THR_MAX );
|
||||
return Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, pReplayFile );
|
||||
}
|
||||
int Cec_GiaReplayTest( Gia_Man_t * p, Wlc_Ntk_t * pWlc, char * pFileName, int fVerbose, int fVeryVerbose, int fSilent )
|
||||
{
|
||||
Cec_SprovePlan_t Plan;
|
||||
if ( !Cec_SproveReplayReadPlan( pFileName, &Plan ) )
|
||||
return -1;
|
||||
return Cec_SproveExecutePlan( p, &Plan, pWlc, fVerbose, fVeryVerbose, fSilent, NULL );
|
||||
}
|
||||
|
||||
#endif // pthreads are used
|
||||
|
|
|
|||
|
|
@ -501,6 +501,7 @@ int Ssw_ManSweepBmcConstr( Ssw_Man_t * p )
|
|||
int i, f, iLits;
|
||||
abctime clk;
|
||||
clk = Abc_Clock();
|
||||
abctime timeSatBmc = p->timeSat, timeSimSatBmc = p->timeSimSat;
|
||||
|
||||
// start initialized timeframes
|
||||
p->pFrames = Aig_ManStart( Aig_ManObjNumMax(p->pAig) * p->pPars->nFramesK );
|
||||
|
|
@ -568,7 +569,7 @@ clk = Abc_Clock();
|
|||
|
||||
// cleanup
|
||||
// Ssw_ClassesCheck( p->ppClasses );
|
||||
p->timeBmc += Abc_Clock() - clk;
|
||||
p->timeBmc += (Abc_Clock() - clk) - (p->timeSat - timeSatBmc) - (p->timeSimSat - timeSimSatBmc);
|
||||
return p->fRefined;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@ int Ssw_ManSweepBmc( Ssw_Man_t * p )
|
|||
int i, f;
|
||||
abctime clk;
|
||||
clk = Abc_Clock();
|
||||
abctime timeSatBmc = p->timeSat, timeSimSatBmc = p->timeSimSat;
|
||||
|
||||
// start initialized timeframes
|
||||
p->pFrames = Aig_ManStart( Aig_ManObjNumMax(p->pAig) * p->pPars->nFramesK );
|
||||
|
|
@ -329,7 +330,7 @@ clk = Abc_Clock();
|
|||
|
||||
// cleanup
|
||||
// Ssw_ClassesCheck( p->ppClasses );
|
||||
p->timeBmc += Abc_Clock() - clk;
|
||||
p->timeBmc += (Abc_Clock() - clk) - (p->timeSat - timeSatBmc) - (p->timeSimSat - timeSimSatBmc);
|
||||
return p->fRefined;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue