From 5e03f9fefa6caa3348b8a2fbd306e37222580d41 Mon Sep 17 00:00:00 2001 From: MyskYko Date: Fri, 20 Jun 2025 15:55:31 -0700 Subject: [PATCH 01/38] more APIs in cadical --- src/sat/cadical/cadical.hpp | 4 ++++ src/sat/cadical/cadicalSolver.c | 30 ++++++++++++++++++++++++++++ src/sat/cadical/cadicalSolver.h | 2 ++ src/sat/cadical/cadical_ccadical.cpp | 8 ++++++++ src/sat/cadical/cadical_solver.cpp | 10 ++++++++++ src/sat/cadical/ccadical.h | 2 ++ 6 files changed, 56 insertions(+) diff --git a/src/sat/cadical/cadical.hpp b/src/sat/cadical/cadical.hpp index c9ed41332..64a5d9ef7 100644 --- a/src/sat/cadical/cadical.hpp +++ b/src/sat/cadical/cadical.hpp @@ -982,6 +982,10 @@ public: // static void build (FILE *file, const char *prefix = "c "); + // Extra APIs + int clauses (); + int conflicts (); + private: //==== start of state ==================================================== diff --git a/src/sat/cadical/cadicalSolver.c b/src/sat/cadical/cadicalSolver.c index bf6df9512..dee2beaf3 100644 --- a/src/sat/cadical/cadicalSolver.c +++ b/src/sat/cadical/cadicalSolver.c @@ -261,6 +261,36 @@ int cadical_solver_get_var_value(cadical_solver* s, int v) { return ccadical_val((CCaDiCaL*)s->p, v + 1) > 0; } +/**Function************************************************************* + + Synopsis [get number of clauses] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int cadical_solver_nclauses(cadical_solver* s) { + return ccadical_clauses((CCaDiCaL*)s->p); +} + +/**Function************************************************************* + + Synopsis [get number of conflicts] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int cadical_solver_nconflicts(cadical_solver* s) { + return ccadical_conflicts((CCaDiCaL*)s->p); +} + /**Function************************************************************* diff --git a/src/sat/cadical/cadicalSolver.h b/src/sat/cadical/cadicalSolver.h index 0192ada3c..2aec06c2a 100644 --- a/src/sat/cadical/cadicalSolver.h +++ b/src/sat/cadical/cadicalSolver.h @@ -65,6 +65,8 @@ extern int cadical_solver_nvars(cadical_solver* s); extern int cadical_solver_addvar(cadical_solver* s); extern void cadical_solver_setnvars(cadical_solver* s,int n); extern int cadical_solver_get_var_value(cadical_solver* s, int v); +extern int cadical_solver_nclauses(cadical_solver* s); +extern int cadical_solver_nconflicts(cadical_solver* s); extern Vec_Int_t * cadical_solve_cnf( Cnf_Dat_t * pCnf, char * pArgs, int nConfs, int nTimeLimit, int fSat, int fUnsat, int fPrintCex, int fVerbose ); ABC_NAMESPACE_HEADER_END diff --git a/src/sat/cadical/cadical_ccadical.cpp b/src/sat/cadical/cadical_ccadical.cpp index ae5c1093f..ccc616c80 100644 --- a/src/sat/cadical/cadical_ccadical.cpp +++ b/src/sat/cadical/cadical_ccadical.cpp @@ -208,4 +208,12 @@ int ccadical_is_inconsistent(CCaDiCaL *ptr) { return ((Wrapper *) ptr)->solver->inconsistent (); } +int ccadical_clauses(CCaDiCaL *ptr) { + return ((Wrapper *) ptr)->solver->clauses (); +} + +int ccadical_conflicts(CCaDiCaL *ptr) { + return ((Wrapper *) ptr)->solver->conflicts (); +} + ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/cadical_solver.cpp b/src/sat/cadical/cadical_solver.cpp index df051f4de..84d350cf2 100644 --- a/src/sat/cadical/cadical_solver.cpp +++ b/src/sat/cadical/cadical_solver.cpp @@ -1759,6 +1759,16 @@ void Solver::error (const char *fmt, ...) { va_end (ap); } +/*------------------------------------------------------------------------*/ + +int Solver::clauses () { + return internal->stats.added.total; +} + +int Solver::conflicts () { + return internal->stats.conflicts; +} + } // namespace CaDiCaL ABC_NAMESPACE_IMPL_END diff --git a/src/sat/cadical/ccadical.h b/src/sat/cadical/ccadical.h index ec5292a79..d4c2ce8f0 100644 --- a/src/sat/cadical/ccadical.h +++ b/src/sat/cadical/ccadical.h @@ -58,6 +58,8 @@ int ccadical_reserve_difference (CCaDiCaL *, int number_of_vars); void ccadical_reserve(CCaDiCaL *, int min_max_var); int ccadical_is_inconsistent(CCaDiCaL *); +int ccadical_clauses(CCaDiCaL *); +int ccadical_conflicts(CCaDiCaL *); /*------------------------------------------------------------------------*/ From 13205ccbb3dd75bcc8dd9b7ef3a8abe2d86ae279 Mon Sep 17 00:00:00 2001 From: MyskYko Date: Sat, 21 Jun 2025 01:29:26 -0700 Subject: [PATCH 02/38] qbf with cadical --- src/aig/gia/giaQbf.c | 45 +++++++++++++++++++++++++++++++++++--------- src/base/abci/abc.c | 13 +++++++++---- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/aig/gia/giaQbf.c b/src/aig/gia/giaQbf.c index 1525e7d83..8af8c6c6f 100644 --- a/src/aig/gia/giaQbf.c +++ b/src/aig/gia/giaQbf.c @@ -23,6 +23,7 @@ #include "sat/bsat/satStore.h" #include "misc/extra/extra.h" #include "sat/glucose/AbcGlucose.h" +#include "sat/cadical/cadicalSolver.h" #include "misc/util/utilTruth.h" #include "base/io/ioResub.h" @@ -45,6 +46,7 @@ struct Qbf_Man_t_ sat_solver * pSatVer; // verification instance sat_solver * pSatSyn; // synthesis instance bmcg_sat_solver*pSatSynG; // synthesis instance + cadical_solver* pSatSynC; // synthesis instance Vec_Int_t * vValues; // variable values Vec_Int_t * vParMap; // parameter mapping Vec_Int_t * vLits; // literals for the SAT solver @@ -534,7 +536,7 @@ void Gia_QbfDumpFileInv( Gia_Man_t * pGia, int nPars ) SeeAlso [] ***********************************************************************/ -Qbf_Man_t * Gia_QbfAlloc( Gia_Man_t * pGia, int nPars, int fGlucose, int fVerbose ) +Qbf_Man_t * Gia_QbfAlloc( Gia_Man_t * pGia, int nPars, int fGlucose, int fCadical, int fVerbose ) { Qbf_Man_t * p; Cnf_Dat_t * pCnf; @@ -551,11 +553,13 @@ Qbf_Man_t * Gia_QbfAlloc( Gia_Man_t * pGia, int nPars, int fGlucose, int fVerbos p->pSatVer = (sat_solver *)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); p->pSatSyn = sat_solver_new(); p->pSatSynG = fGlucose ? bmcg_sat_solver_start() : NULL; + p->pSatSynC = fCadical ? cadical_solver_new() : NULL; p->vValues = Vec_IntAlloc( Gia_ManPiNum(pGia) ); p->vParMap = Vec_IntStartFull( nPars ); p->vLits = Vec_IntAlloc( nPars ); sat_solver_setnvars( p->pSatSyn, nPars ); if ( p->pSatSynG ) bmcg_sat_solver_set_nvars( p->pSatSynG, nPars ); + if ( p->pSatSynC ) cadical_solver_setnvars( p->pSatSynC, nPars ); Cnf_DataFree( pCnf ); return p; } @@ -564,6 +568,7 @@ void Gia_QbfFree( Qbf_Man_t * p ) sat_solver_delete( p->pSatVer ); sat_solver_delete( p->pSatSyn ); if ( p->pSatSynG ) bmcg_sat_solver_stop( p->pSatSynG ); + if ( p->pSatSynC ) cadical_solver_delete( p->pSatSynC ); Vec_IntFree( p->vLits ); Vec_IntFree( p->vValues ); Vec_IntFree( p->vParMap ); @@ -749,6 +754,21 @@ int Gia_QbfAddCofactorG( Qbf_Man_t * p, Gia_Man_t * pCof ) Cnf_DataFree( pCnf ); return 1; } +int Gia_QbfAddCofactorC( Qbf_Man_t * p, Gia_Man_t * pCof ) +{ + Cnf_Dat_t * pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( pCof, 8, 0, 1, 0, 0 ); + int i, iFirstVar = pCnf->nVars - Gia_ManPiNum(pCof); //-1 + pCnf->pMan = NULL; + Cnf_SpecialDataLift( pCnf, cadical_solver_nvars(p->pSatSynC), iFirstVar, iFirstVar + Gia_ManPiNum(p->pGia) ); + for ( i = 0; i < pCnf->nClauses; i++ ) + if ( !cadical_solver_addclause( p->pSatSynC, pCnf->pClauses[i], pCnf->pClauses[i+1] ) ) + { + Cnf_DataFree( pCnf ); + return 0; + } + Cnf_DataFree( pCnf ); + return 1; +} /**Function************************************************************* @@ -766,16 +786,20 @@ void Gia_QbfOnePattern( Qbf_Man_t * p, Vec_Int_t * vValues ) int i; Vec_IntClear( vValues ); for ( i = 0; i < p->nPars; i++ ) - Vec_IntPush( vValues, p->pSatSynG ? bmcg_sat_solver_read_cex_varvalue(p->pSatSynG, i) : sat_solver_var_value(p->pSatSyn, i) ); + Vec_IntPush( vValues, p->pSatSynC ? cadical_solver_get_var_value(p->pSatSynC, i) : + p->pSatSynG ? bmcg_sat_solver_read_cex_varvalue(p->pSatSynG, i) : sat_solver_var_value(p->pSatSyn, i) ); } void Gia_QbfPrint( Qbf_Man_t * p, Vec_Int_t * vValues, int Iter ) { printf( "%5d : ", Iter ); assert( Vec_IntSize(vValues) == p->nVars ); Vec_IntPrintBinary( vValues ); printf( " " ); - printf( "Var =%7d ", p->pSatSynG ? bmcg_sat_solver_varnum(p->pSatSynG) : sat_solver_nvars(p->pSatSyn) ); - printf( "Cla =%7d ", p->pSatSynG ? bmcg_sat_solver_clausenum(p->pSatSynG) : sat_solver_nclauses(p->pSatSyn) ); - printf( "Conf =%9d ", p->pSatSynG ? bmcg_sat_solver_conflictnum(p->pSatSynG) : sat_solver_nconflicts(p->pSatSyn) ); + printf( "Var =%7d ", p->pSatSynC ? cadical_solver_nvars(p->pSatSynC) : + p->pSatSynG ? bmcg_sat_solver_varnum(p->pSatSynG) : sat_solver_nvars(p->pSatSyn) ); + printf( "Cla =%7d ", p->pSatSynC ? cadical_solver_nclauses(p->pSatSynC) : + p->pSatSynG ? bmcg_sat_solver_clausenum(p->pSatSynG) : sat_solver_nclauses(p->pSatSyn) ); + printf( "Conf =%9d ", p->pSatSynC ? cadical_solver_nconflicts(p->pSatSynC) : + p->pSatSynG ? bmcg_sat_solver_conflictnum(p->pSatSynG) : sat_solver_nconflicts(p->pSatSyn) ); Abc_PrintTime( 1, "Time", Abc_Clock() - p->clkStart ); } @@ -869,9 +893,9 @@ void Gia_QbfLearnConstraint( Qbf_Man_t * p, Vec_Int_t * vValues ) SeeAlso [] ***********************************************************************/ -int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fVerbose ) +int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fVerbose ) { - Qbf_Man_t * p = Gia_QbfAlloc( pGia, nPars, fGlucose, fVerbose ); + Qbf_Man_t * p = Gia_QbfAlloc( pGia, nPars, fGlucose, fCadical, fVerbose ); Gia_Man_t * pCof; int i, status, RetValue = 0; abctime clk; @@ -886,12 +910,15 @@ int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, i // generate next constraint assert( Vec_IntSize(p->vValues) == p->nVars ); pCof = Gia_QbfCofactor( pGia, nPars, p->vValues, p->vParMap ); - status = p->pSatSynG ? Gia_QbfAddCofactorG( p, pCof ) : Gia_QbfAddCofactor( p, pCof ); + status = p->pSatSynC ? Gia_QbfAddCofactorC( p, pCof ) : + p->pSatSynG ? Gia_QbfAddCofactorG( p, pCof ) : Gia_QbfAddCofactor( p, pCof ); Gia_ManStop( pCof ); if ( status == 0 ) { RetValue = 1; break; } // synthesize next assignment clk = Abc_Clock(); - if ( p->pSatSynG ) + if ( p->pSatSynC ) + status = cadical_solver_solve( p->pSatSynC, NULL, NULL, 0, 0, 0, 0 ); + else if ( p->pSatSynG ) status = bmcg_sat_solver_solve( p->pSatSynG, NULL, 0 ); else status = sat_solver_solve( p->pSatSyn, NULL, NULL, (ABC_INT64_T)nConfLimit, 0, 0, 0 ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e9a21e0d8..f5b00ee84 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -51058,7 +51058,7 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Gia_QbfDumpFile( Gia_Man_t * pGia, int nPars ); extern void Gia_QbfDumpFileInv( Gia_Man_t * pGia, int nPars ); - extern int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fVerbose ); + extern int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fVerbose ); int c, nPars = -1; int nIterLimit = 0; int nConfLimit = 0; @@ -51067,9 +51067,10 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) int fDumpCnf = 0; int fDumpCnf2 = 0; int fGlucose = 0; + int fCadical = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "PICTKdegvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PICTKdegcvh" ) ) != EOF ) { switch ( c ) { @@ -51137,6 +51138,9 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'g': fGlucose ^= 1; break; + case 'c': + fCadical ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -51171,11 +51175,11 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) else if ( fDumpCnf2 ) Gia_QbfDumpFileInv( pAbc->pGia, nPars ); else - Gia_QbfSolve( pAbc->pGia, nPars, nIterLimit, nConfLimit, nTimeOut, nEncVars, fGlucose, fVerbose ); + Gia_QbfSolve( pAbc->pGia, nPars, nIterLimit, nConfLimit, nTimeOut, nEncVars, fGlucose, fCadical, fVerbose ); return 0; usage: - Abc_Print( -2, "usage: &qbf [-PICTK num] [-degvh]\n" ); + Abc_Print( -2, "usage: &qbf [-PICTK num] [-degcvh]\n" ); Abc_Print( -2, "\t solves QBF problem EpVxM(p,x)\n" ); Abc_Print( -2, "\t-P num : number of parameters p (should be the first PIs) [default = %d]\n", nPars ); Abc_Print( -2, "\t-I num : quit after the given iteration even if unsolved [default = %d]\n", nIterLimit ); @@ -51185,6 +51189,7 @@ usage: Abc_Print( -2, "\t-d : toggle dumping QDIMACS file instead of solving (complemented QBF) [default = %s]\n", fDumpCnf? "yes": "no" ); Abc_Print( -2, "\t-e : toggle dumping QDIMACS file instead of solving (original QBF) [default = %s]\n", fDumpCnf2? "yes": "no" ); Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", fGlucose? "yes": "no" ); + Abc_Print( -2, "\t-c : toggle using CaDiCaL by Armin Biere [default = %s]\n", fCadical? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n\n"); Abc_Print( -2, "\t As an example of using this command, consider specification (the three-input AND-gate) and implementation\n"); From cb971e07a399d2462b6c956a172b30c80f2d2855 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 6 Nov 2025 12:26:54 -0800 Subject: [PATCH 03/38] Recent experiments. --- src/aig/gia/giaMulFind.c | 38 +- src/aig/gia/giaMulFind3.c | 48 ++ src/aig/gia/module.make | 1 + src/base/abci/abc.c | 77 ++- src/misc/util/module.make | 1 + src/misc/util/utilBipart.c | 1324 ++++++++++++++++++++++++++++++++++++ 6 files changed, 1469 insertions(+), 20 deletions(-) create mode 100644 src/aig/gia/giaMulFind3.c create mode 100644 src/misc/util/utilBipart.c diff --git a/src/aig/gia/giaMulFind.c b/src/aig/gia/giaMulFind.c index b7bc0b0b6..5e7d8d7b2 100644 --- a/src/aig/gia/giaMulFind.c +++ b/src/aig/gia/giaMulFind.c @@ -661,15 +661,15 @@ Vec_Wec_t * Gia_ManMulFindBInputs( Gia_Man_t * p, Vec_Wec_t * vCuts4, Vec_Wec_t SeeAlso [] ***********************************************************************/ -Vec_Int_t * Gia_ManMulFindTfo( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1 ) +Vec_Int_t * Gia_ManMulFindTfo( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1, int fLits ) { Vec_Int_t * vTfo = Vec_IntAlloc( 100 ); Gia_Obj_t * pObj; int i, Obj; Gia_ManIncrementTravId( p ); Vec_IntForEachEntry( vIn0, Obj, i ) - Gia_ObjSetTravIdCurrentId( p, Obj ); + Gia_ObjSetTravIdCurrentId( p, fLits ? Abc_Lit2Var(Obj) : Obj ); Vec_IntForEachEntry( vIn1, Obj, i ) - Gia_ObjSetTravIdCurrentId( p, Obj ); + Gia_ObjSetTravIdCurrentId( p, fLits ? Abc_Lit2Var(Obj) : Obj ); Gia_ManForEachAnd( p, pObj, i ) { if ( Gia_ObjIsTravIdCurrentId(p, i) ) continue; @@ -678,15 +678,15 @@ Vec_Int_t * Gia_ManMulFindTfo( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1 } return vTfo; } -Vec_Wrd_t * Gia_ManMulFindSimCone( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1, Vec_Wrd_t * vSim0, Vec_Wrd_t * vSim1, Vec_Int_t * vTfo ) +Vec_Wrd_t * Gia_ManMulFindSimCone( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * vIn1, Vec_Wrd_t * vSim0, Vec_Wrd_t * vSim1, Vec_Int_t * vTfo, int fLits ) { Vec_Wrd_t * vRes = Vec_WrdAlloc( Vec_IntSize(vTfo) ); Vec_Wrd_t * vSims = Vec_WrdStart( Gia_ManObjNum(p) ); Gia_Obj_t * pObj; int i, Obj; Vec_IntForEachEntry( vIn0, Obj, i ) - Vec_WrdWriteEntry( vSims, Obj, Vec_WrdEntry(vSim0, i) ); + Vec_WrdWriteEntry( vSims, fLits ? Abc_Lit2Var(Obj) : Obj, (fLits && Abc_LitIsCompl(Obj)) ? ~Vec_WrdEntry(vSim0, i) : Vec_WrdEntry(vSim0, i) ); Vec_IntForEachEntry( vIn1, Obj, i ) - Vec_WrdWriteEntry( vSims, Obj, Vec_WrdEntry(vSim1, i) ); + Vec_WrdWriteEntry( vSims, fLits ? Abc_Lit2Var(Obj) : Obj, (fLits && Abc_LitIsCompl(Obj)) ? ~Vec_WrdEntry(vSim1, i) : Vec_WrdEntry(vSim1, i) ); Gia_ManForEachObjVec( vTfo, p, pObj, i ) { word Sim0 = Vec_WrdEntry(vSims, Gia_ObjFaninId0p(p, pObj) ); word Sim1 = Vec_WrdEntry(vSims, Gia_ObjFaninId1p(p, pObj) ); @@ -697,17 +697,17 @@ Vec_Wrd_t * Gia_ManMulFindSimCone( Gia_Man_t * p, Vec_Int_t * vIn0, Vec_Int_t * Vec_WrdFree( vSims ); return vRes; } -int Gia_ManMulFindGetArg( Vec_Wrd_t * vSim, int i, int fSigned ) +iword Gia_ManMulFindGetArg( Vec_Wrd_t * vSim, int i, int fSigned ) { - int w, Res = 0; word Word = 0; + int w; iword Res = 0; word Word = 0; Vec_WrdForEachEntry( vSim, Word, w ) if ( (Word >> i) & 1 ) - Res |= (1 << w); + Res |= ((iword)1 << w); if ( fSigned && ((Word >> i) & 1) ) - Res |= ~0 << Vec_WrdSize(vSim); + Res |= ~(iword)0 << Vec_WrdSize(vSim); return Res; } -void Gia_ManMulFindSetArg( Vec_Wrd_t * vSim, int i, int iNum ) +void Gia_ManMulFindSetArg( Vec_Wrd_t * vSim, int i, iword iNum ) { int w; word * pWords = Vec_WrdArray(vSim); for ( w = 0; w < Vec_WrdSize(vSim); w++ ) @@ -716,17 +716,17 @@ void Gia_ManMulFindSetArg( Vec_Wrd_t * vSim, int i, int iNum ) } Vec_Wrd_t * Gia_ManMulFindSim( Vec_Wrd_t * vSim0, Vec_Wrd_t * vSim1, int fSigned ) { - assert( Vec_WrdSize(vSim0) + Vec_WrdSize(vSim1) <= 30 ); + assert( Vec_WrdSize(vSim0) + Vec_WrdSize(vSim1) <= 62 ); Vec_Wrd_t * vRes = Vec_WrdStart( Vec_WrdSize(vSim0) + Vec_WrdSize(vSim1) ); for ( int i = 0; i < 64; i++ ) { - int a = Gia_ManMulFindGetArg( vSim0, i, fSigned ); - int b = Gia_ManMulFindGetArg( vSim1, i, fSigned ); + iword a = Gia_ManMulFindGetArg( vSim0, i, fSigned ); + iword b = Gia_ManMulFindGetArg( vSim1, i, fSigned ); Gia_ManMulFindSetArg( vRes, i, a * b ); } return vRes; } -void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fVerbose ) +void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fLits, int fVerbose ) { Abc_Random(1); for ( int m = 0; m < Vec_WecSize(vTerms)/3; m++ ) { @@ -737,8 +737,8 @@ void Gia_ManMulFindOutputs( Gia_Man_t * p, Vec_Wec_t * vTerms, int fVerbose ) Vec_Wrd_t * vSim1 = Vec_WrdStartRandom( Vec_IntSize(vIn1) ); Vec_Wrd_t * vSimU = Gia_ManMulFindSim( vSim0, vSim1, 0 ); Vec_Wrd_t * vSimS = Gia_ManMulFindSim( vSim0, vSim1, 1 ); - Vec_Int_t * vTfo = Gia_ManMulFindTfo( p, vIn0, vIn1 ); - Vec_Wrd_t * vSims = Gia_ManMulFindSimCone( p, vIn0, vIn1, vSim0, vSim1, vTfo ); + Vec_Int_t * vTfo = Gia_ManMulFindTfo( p, vIn0, vIn1, fLits ); + Vec_Wrd_t * vSims = Gia_ManMulFindSimCone( p, vIn0, vIn1, vSim0, vSim1, vTfo, fLits ); Vec_Int_t * vOutU = Vec_IntAlloc( 100 ); Vec_Int_t * vOutS = Vec_IntAlloc( 100 ); word Word; int w, iPlace; @@ -814,7 +814,7 @@ Vec_Wec_t * Gia_ManMulFindA( Gia_Man_t * p, Vec_Wec_t * vCuts3, int fVerbose ) Vec_Wec_t * vXors = Gia_ManMulFindXors( p, vCuts3, fVerbose ); Vec_Wec_t * vTerms = Gia_ManMulFindAInputs2( p, fVerbose ); if ( Vec_WecSize(vTerms) ) - Gia_ManMulFindOutputs( p, vTerms, fVerbose ); + Gia_ManMulFindOutputs( p, vTerms, 0, fVerbose ); Vec_WecFree( vXors ); return vTerms; } @@ -824,7 +824,7 @@ Vec_Wec_t * Gia_ManMulFindB( Gia_Man_t * p, Vec_Wec_t * vCuts4, Vec_Wec_t * vCut if ( Vec_WecSize(vCuts4) && Vec_WecSize(vCuts5) ) vTerms = Gia_ManMulFindBInputs2( p, vCuts4, vCuts5, fVerbose ); if ( Vec_WecSize(vTerms) ) - Gia_ManMulFindOutputs( p, vTerms, fVerbose ); + Gia_ManMulFindOutputs( p, vTerms, 0, fVerbose ); return vTerms; } void Gia_ManMulFindPrintSet( Vec_Int_t * vSet, int fLit, int fSkipLast ) diff --git a/src/aig/gia/giaMulFind3.c b/src/aig/gia/giaMulFind3.c new file mode 100644 index 000000000..52db2f120 --- /dev/null +++ b/src/aig/gia/giaMulFind3.c @@ -0,0 +1,48 @@ +/**CFile**************************************************************** + + FileName [giaMulFind3.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Scalable AIG package.] + + Synopsis [Multiplier detection.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: giaMulFind3.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include + +#include "gia.h" +#include "misc/vec/vecHsh.h" +#include "misc/util/utilTruth.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +void Gia_ManMulFindNew( Gia_Man_t * p, int nABits, int nFanLim, int fLits, int fVerbose ) +{ +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_IMPL_END + diff --git a/src/aig/gia/module.make b/src/aig/gia/module.make index ebc39b1f6..dcb30e90a 100644 --- a/src/aig/gia/module.make +++ b/src/aig/gia/module.make @@ -58,6 +58,7 @@ SRC += src/aig/gia/giaAig.c \ src/aig/gia/giaMinLut.c \ src/aig/gia/giaMinLut2.c \ src/aig/gia/giaMulFind.c \ + src/aig/gia/giaMulFind3.c \ src/aig/gia/giaMuxes.c \ src/aig/gia/giaNf.c \ src/aig/gia/giaOf.c \ diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 2787c0a82..990ed118c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -643,6 +643,7 @@ static int Abc_CommandAbc9FunAbs ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9DsdInfo ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9FunTrace ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9MulFind ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9MulFind3 ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9BsFind ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9AndCare ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1469,7 +1470,8 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&funabs", Abc_CommandAbc9FunAbs, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&dsdinfo", Abc_CommandAbc9DsdInfo, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&funtrace", Abc_CommandAbc9FunTrace, 0 ); - Cmd_CommandAdd( pAbc, "ABC9", "&mulfind", Abc_CommandAbc9MulFind, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&mulfind", Abc_CommandAbc9MulFind, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&mulfind3", Abc_CommandAbc9MulFind3, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bsfind", Abc_CommandAbc9BsFind, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&andcare", Abc_CommandAbc9AndCare, 0 ); @@ -57579,6 +57581,79 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9MulFind3( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Gia_ManMulFindNew( Gia_Man_t * p, int nABits, int nFanLim, int fLits, int fVerbose ); + int c, nABits = 0, nFanLim = 4, fLits = 0, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "IFlvh" ) ) != EOF ) + { + switch ( c ) + { + case 'I': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-I\" should be followed by an integer.\n" ); + goto usage; + } + nABits = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nABits < 0 ) + goto usage; + break; + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-F\" should be followed by an integer.\n" ); + goto usage; + } + nFanLim = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nFanLim < 0 ) + goto usage; + break; + case 'l': + fLits ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9MulFind(): There is no AIG.\n" ); + return 0; + } + Gia_ManMulFindNew( pAbc->pGia, nABits, nFanLim, fLits, fVerbose ); + return 0; + +usage: + Abc_Print( -2, "usage: &mulfind3 [-IF num] [-lvh]\n" ); + Abc_Print( -2, "\t detects multipliers in the given AIG\n" ); + Abc_Print( -2, "\t-I num : the bit-width of the first input if known [default = %d]\n", nABits ); + Abc_Print( -2, "\t-F num : the fanout limit [default = %d]\n", nFanLim ); + Abc_Print( -2, "\t-l : toggles using literals instead of nodes [default = %s]\n", fLits ? "yes": "no" ); + Abc_Print( -2, "\t-v : toggles printing verbose information [default = %s]\n", fVerbose ? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/misc/util/module.make b/src/misc/util/module.make index ef4baebf1..c3b797e7c 100644 --- a/src/misc/util/module.make +++ b/src/misc/util/module.make @@ -1,4 +1,5 @@ SRC += src/misc/util/utilBridge.c \ + src/misc/util/utilBipart.c \ src/misc/util/utilBSet.c \ src/misc/util/utilCex.c \ src/misc/util/utilColor.c \ diff --git a/src/misc/util/utilBipart.c b/src/misc/util/utilBipart.c new file mode 100644 index 000000000..8df16991c --- /dev/null +++ b/src/misc/util/utilBipart.c @@ -0,0 +1,1324 @@ +/**CFile**************************************************************** + + FileName [utilBipart.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Handling counter-examples.] + + Synopsis [Handling counter-examples.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: utilBipart.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "misc/util/abc_global.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define List_ForEachSet(pList, pSet, s) for ((s) = 0, (pSet) = (pList) + 1; (s) < (pList)[0]; ++(s), (pSet) += (pSet)[0] + 1) +#define Set_ForEachNode(pSet, node, n) for ((n) = 1; (n) <= (pSet)[0] && (((node) = (pSet)[n]), 1); ++(n)) + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct { + int *data; + int size; + int cap; +} IntVector; + +typedef struct { + int node_count; + int edge_count; + int *offset; + int *neighbors; + int *orig_ids; +} Graph; + +typedef struct { + int sizeA; + int sizeB; + int *nodesA; + int *nodesB; + uint64_t hashA; + uint64_t hashB; +} ComponentRecord; + +typedef struct { + ComponentRecord *data; + int size; + int cap; +} ComponentList; + +typedef struct { + int u; + int v; + int assigned; +} EdgeInfo; + +typedef struct { + uint64_t key; + int index; +} EdgeMapEntry; + +typedef struct { + IntVector nodesA; + IntVector nodesB; + IntVector edges; + int edge_count; +} WorkComponent; + +typedef struct { + Graph graph; + EdgeInfo *edges; + EdgeMapEntry *edge_map; + int edge_count; + WorkComponent *components; + int component_count; +} SolverContext; + +static void validate_edge_ownership(const SolverContext *ctx) { + int *owner; + int i; + if (ctx->edge_count == 0) { + return; + } + owner = (int *)malloc(ctx->edge_count * sizeof(int)); + assert(owner); + for (i = 0; i < ctx->edge_count; ++i) { + owner[i] = -1; + } + for (i = 0; i < ctx->component_count; ++i) { + const WorkComponent *comp = &ctx->components[i]; + int j; + for (j = 0; j < comp->edges.size; ++j) { + int idx = comp->edges.data[j]; + assert(idx >= 0 && idx < ctx->edge_count); + assert(owner[idx] == -1); + owner[idx] = i; + assert(ctx->edges[idx].assigned == i); + } + for (j = 1; j < comp->nodesA.size; ++j) { + assert(comp->nodesA.data[j - 1] < comp->nodesA.data[j]); + } + for (j = 1; j < comp->nodesB.size; ++j) { + assert(comp->nodesB.data[j - 1] < comp->nodesB.data[j]); + } + } + for (i = 0; i < ctx->edge_count; ++i) { + int assigned = ctx->edges[i].assigned; + if (assigned >= 0) { + assert(owner[i] == assigned); + } else { + assert(owner[i] == -1); + } + } + free(owner); +} + +static void vec_init(IntVector *v) { + v->data = NULL; + v->size = 0; + v->cap = 0; +} + +static void vec_reserve(IntVector *v, int need) { + if (need > v->cap) { + int cap = v->cap ? v->cap : 8; + while (cap < need) { + cap *= 2; + } + v->data = (int *)realloc(v->data, cap * sizeof(int)); + assert(v->data); + v->cap = cap; + } +} + +static void vec_push(IntVector *v, int value) { + vec_reserve(v, v->size + 1); + v->data[v->size++] = value; +} + +static void vec_clear(IntVector *v) { + v->size = 0; +} + +static void vec_free(IntVector *v) { + free(v->data); + v->data = NULL; + v->size = 0; + v->cap = 0; +} + +static void component_list_init(ComponentList *list) { + list->data = NULL; + list->size = 0; + list->cap = 0; +} + +static void component_list_push(ComponentList *list, ComponentRecord rec) { + if (list->size == list->cap) { + int cap = list->cap ? list->cap * 2 : 4; + list->data = (ComponentRecord *)realloc(list->data, cap * sizeof(ComponentRecord)); + assert(list->data); + list->cap = cap; + } + list->data[list->size++] = rec; +} + +static void component_list_free(ComponentList *list) { + int i; + for (i = 0; i < list->size; ++i) { + free(list->data[i].nodesA); + free(list->data[i].nodesB); + } + free(list->data); + list->data = NULL; + list->size = 0; + list->cap = 0; +} + +static int cmp_int(const void *a, const void *b) { + const int lhs = *(const int *)a; + const int rhs = *(const int *)b; + return (lhs > rhs) - (lhs < rhs); +} + +static int compare_sets(const int *a, int sizeA, const int *b, int sizeB) { + int i; + if (sizeA < sizeB) { + return -1; + } + if (sizeA > sizeB) { + return 1; + } + for (i = 0; i < sizeA; ++i) { + if (a[i] < b[i]) { + return -1; + } + if (a[i] > b[i]) { + return 1; + } + } + return 0; +} + +static int threshold_value(int percent, int count) { + return (percent * count + 99) / 100; +} + +static uint64_t hash_ids(const int *ids, int count) { + uint64_t h = 1469598103934665603ULL; + uint64_t prime = 1099511628211ULL; + int i; + for (i = 0; i < count; ++i) { + h ^= (uint64_t)(uint32_t)ids[i] + 0x9e3779b97f4a7c15ULL; + h *= prime; + } + return h; +} + +static int binary_search_id(const int *ids, int count, int value) { + int lo = 0; + int hi = count - 1; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + if (ids[mid] == value) { + return mid; + } + if (ids[mid] < value) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return -1; +} + +static void graph_free(Graph *g) { + free(g->offset); + free(g->neighbors); + free(g->orig_ids); + g->offset = NULL; + g->neighbors = NULL; + g->orig_ids = NULL; + g->node_count = 0; + g->edge_count = 0; +} + +static void graph_build(Graph *g, int *pairs, int pair_count) { + int *ids; + int id_count = 0; + int unique_ids = 0; + int i; + int edge_capacity; + int *edges_u; + int *edges_v; + int mapped_edges = 0; + int *degree; + int *offset; + int *neighbors; + int total_adj; + int *cursor; + int *new_offsets; + int write_pos; + + g->node_count = 0; + g->edge_count = 0; + g->offset = NULL; + g->neighbors = NULL; + g->orig_ids = NULL; + + if (pair_count == 0) { + g->offset = (int *)calloc(1, sizeof(int)); + assert(g->offset); + return; + } + + assert((pair_count & 1) == 0); + edge_capacity = pair_count / 2; + + ids = (int *)malloc(pair_count * sizeof(int)); + assert(ids); + edges_u = (int *)malloc(edge_capacity * sizeof(int)); + edges_v = (int *)malloc(edge_capacity * sizeof(int)); + assert(edges_u && edges_v); + + for (i = 0; i < pair_count; i += 2) { + ids[id_count++] = pairs[i]; + ids[id_count++] = pairs[i + 1]; + } + + qsort(ids, id_count, sizeof(int), cmp_int); + for (i = 0; i < id_count; ++i) { + if (i == 0 || ids[i] != ids[i - 1]) { + ids[unique_ids++] = ids[i]; + } + } + + g->node_count = unique_ids; + g->orig_ids = (int *)malloc(unique_ids * sizeof(int)); + assert(g->orig_ids); + for (i = 0; i < unique_ids; ++i) { + g->orig_ids[i] = ids[i]; + } + + for (i = 0; i < pair_count; i += 2) { + int a = pairs[i]; + int b = pairs[i + 1]; + int u = binary_search_id(g->orig_ids, unique_ids, a); + int v = binary_search_id(g->orig_ids, unique_ids, b); + if (u == v) { + continue; + } + edges_u[mapped_edges] = u; + edges_v[mapped_edges] = v; + mapped_edges++; + } + + degree = (int *)calloc(unique_ids, sizeof(int)); + assert(degree); + for (i = 0; i < mapped_edges; ++i) { + int u = edges_u[i]; + int v = edges_v[i]; + degree[u]++; + degree[v]++; + } + + offset = (int *)malloc((unique_ids + 1) * sizeof(int)); + assert(offset); + offset[0] = 0; + for (i = 0; i < unique_ids; ++i) { + offset[i + 1] = offset[i] + degree[i]; + } + total_adj = offset[unique_ids]; + neighbors = (int *)malloc(total_adj * sizeof(int)); + assert(neighbors); + + cursor = (int *)malloc(unique_ids * sizeof(int)); + assert(cursor); + memcpy(cursor, offset, unique_ids * sizeof(int)); + for (i = 0; i < mapped_edges; ++i) { + int u = edges_u[i]; + int v = edges_v[i]; + neighbors[cursor[u]++] = v; + neighbors[cursor[v]++] = u; + } + free(cursor); + free(edges_u); + free(edges_v); + free(degree); + + new_offsets = (int *)malloc((unique_ids + 1) * sizeof(int)); + assert(new_offsets); + new_offsets[0] = 0; + write_pos = 0; + for (i = 0; i < unique_ids; ++i) { + int start = offset[i]; + int end = offset[i + 1]; + int len = end - start; + int j; + if (len > 1) { + qsort(neighbors + start, len, sizeof(int), cmp_int); + } + { + int last = -1; + for (j = start; j < end; ++j) { + int v = neighbors[j]; + if (v == i) { + continue; + } + if (last != -1 && v == last) { + continue; + } + neighbors[write_pos++] = v; + last = v; + } + } + new_offsets[i + 1] = write_pos; + } + + free(offset); + free(ids); + + g->offset = new_offsets; + g->neighbors = neighbors; + g->edge_count = write_pos / 2; +} + +static int count_edges_to_mark(const Graph *g, int node, const unsigned char *mark) { + int start = g->offset[node]; + int end = g->offset[node + 1]; + int count = 0; + int i; + for (i = start; i < end; ++i) { + int v = g->neighbors[i]; + if (mark[v]) { + count++; + } + } + return count; +} + +static int component_exists(const ComponentList *list, uint64_t hashA, uint64_t hashB, const int *nodesA, int sizeA, const int *nodesB, int sizeB) { + int i; + for (i = 0; i < list->size; ++i) { + const ComponentRecord *rec = &list->data[i]; + if (rec->sizeA != sizeA || rec->sizeB != sizeB) { + continue; + } + if (rec->hashA != hashA || rec->hashB != hashB) { + continue; + } + if (memcmp(rec->nodesA, nodesA, sizeA * sizeof(int)) != 0) { + continue; + } + if (memcmp(rec->nodesB, nodesB, sizeB * sizeof(int)) != 0) { + continue; + } + return 1; + } + return 0; +} + +static void detect_components(const Graph *g, int min_con, int min_part, ComponentList *out) { + unsigned char *markA; + unsigned char *markB; + int *counts; + IntVector setA; + IntVector setB; + IntVector touchedA; + IntVector touchedB; + IntVector touchedCounts; + int seed; + + if (g->node_count == 0) { + return; + } + + markA = (unsigned char *)calloc(g->node_count, sizeof(unsigned char)); + markB = (unsigned char *)calloc(g->node_count, sizeof(unsigned char)); + counts = (int *)calloc(g->node_count, sizeof(int)); + assert(markA && markB && counts); + + vec_init(&setA); + vec_init(&setB); + vec_init(&touchedA); + vec_init(&touchedB); + vec_init(&touchedCounts); + + for (seed = 0; seed < g->node_count; ++seed) { + int start = g->offset[seed]; + int end = g->offset[seed + 1]; + int iter = 0; + int valid = 1; + int changed; + int thresholdA; + int thresholdB; + int i; + + if (end - start == 0) { + continue; + } + + vec_clear(&setA); + vec_clear(&setB); + vec_clear(&touchedA); + vec_clear(&touchedB); + vec_clear(&touchedCounts); + + markA[seed] = 1; + vec_push(&touchedA, seed); + vec_push(&setA, seed); + + for (i = start; i < end; ++i) { + int v = g->neighbors[i]; + if (!markB[v]) { + markB[v] = 1; + vec_push(&touchedB, v); + vec_push(&setB, v); + } + } + + if (setB.size == 0) { + goto cleanup_seed; + } + + while (valid) { + changed = 0; + thresholdA = threshold_value(min_con, setB.size); + if (thresholdA == 0 && setB.size > 0) { + thresholdA = 1; + } + + for (i = 0; i < setA.size;) { + int node = setA.data[i]; + int cnt = count_edges_to_mark(g, node, markB); + if (cnt < thresholdA) { + markA[node] = 0; + setA.data[i] = setA.data[setA.size - 1]; + setA.size--; + changed = 1; + continue; + } + ++i; + } + + if (setA.size == 0) { + valid = 0; + break; + } + + thresholdB = threshold_value(min_con, setA.size); + if (thresholdB == 0 && setA.size > 0) { + thresholdB = 1; + } + + for (i = 0; i < setB.size;) { + int node = setB.data[i]; + int cnt = count_edges_to_mark(g, node, markA); + if (cnt < thresholdB) { + markB[node] = 0; + setB.data[i] = setB.data[setB.size - 1]; + setB.size--; + changed = 1; + continue; + } + ++i; + } + + if (setB.size == 0) { + valid = 0; + break; + } + + if (setB.size > 0 && thresholdA > 0) { + for (i = 0; i < setB.size; ++i) { + int node = setB.data[i]; + int n; + for (n = g->offset[node]; n < g->offset[node + 1]; ++n) { + int v = g->neighbors[n]; + if (markA[v] || markB[v]) { + continue; + } + if (counts[v] == 0) { + vec_push(&touchedCounts, v); + } + counts[v]++; + } + } + + for (i = 0; i < touchedCounts.size; ++i) { + int node = touchedCounts.data[i]; + if (counts[node] >= thresholdA) { + markA[node] = 1; + vec_push(&touchedA, node); + vec_push(&setA, node); + changed = 1; + } + counts[node] = 0; + } + vec_clear(&touchedCounts); + } + + thresholdB = threshold_value(min_con, setA.size); + if (thresholdB == 0 && setA.size > 0) { + thresholdB = 1; + } + + if (setA.size > 0 && thresholdB > 0) { + for (i = 0; i < setA.size; ++i) { + int node = setA.data[i]; + int n; + for (n = g->offset[node]; n < g->offset[node + 1]; ++n) { + int v = g->neighbors[n]; + if (markA[v] || markB[v]) { + continue; + } + if (counts[v] == 0) { + vec_push(&touchedCounts, v); + } + counts[v]++; + } + } + + for (i = 0; i < touchedCounts.size; ++i) { + int node = touchedCounts.data[i]; + if (counts[node] >= thresholdB) { + markB[node] = 1; + vec_push(&touchedB, node); + vec_push(&setB, node); + changed = 1; + } + counts[node] = 0; + } + vec_clear(&touchedCounts); + } + + if (!changed) { + break; + } + + ++iter; + if (iter > 64) { + break; + } + } + + if (valid && setA.size >= min_part && setB.size >= min_part) { + int sizeA = setA.size; + int sizeB = setB.size; + int64_t edges = 0; + int *idsA = (int *)malloc(sizeA * sizeof(int)); + int *idsB = (int *)malloc(sizeB * sizeof(int)); + uint64_t hashA; + uint64_t hashB; + + assert(idsA && idsB); + + for (i = 0; i < sizeA; ++i) { + int node = setA.data[i]; + edges += count_edges_to_mark(g, node, markB); + idsA[i] = node; + } + + for (i = 0; i < sizeB; ++i) { + idsB[i] = setB.data[i]; + } + + if (edges * 100 >= (int64_t)min_con * sizeA * sizeB) { + qsort(idsA, sizeA, sizeof(int), cmp_int); + qsort(idsB, sizeB, sizeof(int), cmp_int); + if (compare_sets(idsA, sizeA, idsB, sizeB) > 0) { + int *tmp = idsA; + int tmp_size = sizeA; + idsA = idsB; + idsB = tmp; + sizeA = sizeB; + sizeB = tmp_size; + } + hashA = hash_ids(idsA, sizeA); + hashB = hash_ids(idsB, sizeB); + if (!component_exists(out, hashA, hashB, idsA, sizeA, idsB, sizeB)) { + ComponentRecord rec; + rec.sizeA = sizeA; + rec.sizeB = sizeB; + rec.nodesA = idsA; + rec.nodesB = idsB; + rec.hashA = hashA; + rec.hashB = hashB; + component_list_push(out, rec); + } else { + free(idsA); + free(idsB); + } + } else { + free(idsA); + free(idsB); + } + } + +cleanup_seed: + for (i = 0; i < touchedA.size; ++i) { + markA[touchedA.data[i]] = 0; + } + for (i = 0; i < touchedB.size; ++i) { + markB[touchedB.data[i]] = 0; + } + for (i = 0; i < touchedCounts.size; ++i) { + counts[touchedCounts.data[i]] = 0; + } + } + + vec_free(&setA); + vec_free(&setB); + vec_free(&touchedA); + vec_free(&touchedB); + vec_free(&touchedCounts); + free(markA); + free(markB); + free(counts); +} + +static uint64_t make_edge_key(int a, int b) { + uint32_t ua = (uint32_t)a; + uint32_t ub = (uint32_t)b; + if (ua < ub) { + return ((uint64_t)ua << 32) | (uint64_t)ub; + } + return ((uint64_t)ub << 32) | (uint64_t)ua; +} + +static int cmp_edge_map(const void *a, const void *b) { + const EdgeMapEntry *ea = (const EdgeMapEntry *)a; + const EdgeMapEntry *eb = (const EdgeMapEntry *)b; + if (ea->key < eb->key) { + return -1; + } + if (ea->key > eb->key) { + return 1; + } + return 0; +} + +static int edge_map_find(const EdgeMapEntry *map, int size, int u, int v) { + uint64_t key = make_edge_key(u, v); + int lo = 0; + int hi = size - 1; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + if (map[mid].key == key) { + return map[mid].index; + } + if (map[mid].key < key) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return -1; +} + +static void work_component_init(WorkComponent *comp) { + vec_init(&comp->nodesA); + vec_init(&comp->nodesB); + vec_init(&comp->edges); + comp->edge_count = 0; +} + +static void work_component_free(WorkComponent *comp) { + vec_free(&comp->nodesA); + vec_free(&comp->nodesB); + vec_free(&comp->edges); + comp->edge_count = 0; +} + +static int vector_contains(const IntVector *vec, int value) { + int lo = 0; + int hi = vec->size - 1; + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + int mid_val = vec->data[mid]; + if (mid_val == value) { + return 1; + } + if (mid_val < value) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return 0; +} + +static void vector_insert_sorted(IntVector *vec, int value) { + int lo = 0; + int hi = vec->size; + while (lo < hi) { + int mid = lo + (hi - lo) / 2; + if (vec->data[mid] < value) { + lo = mid + 1; + } else { + hi = mid; + } + } + vec_reserve(vec, vec->size + 1); + if (lo < vec->size) { + memmove(&vec->data[lo + 1], &vec->data[lo], (vec->size - lo) * sizeof(int)); + } + vec->data[lo] = value; + vec->size++; +} + +static EdgeInfo *build_edge_list(const Graph *g, int *out_count) { + int total = g->edge_count; + EdgeInfo *edges; + int idx = 0; + int u; + + if (total == 0) { + *out_count = 0; + return NULL; + } + + edges = (EdgeInfo *)malloc(total * sizeof(EdgeInfo)); + assert(edges); + + for (u = 0; u < g->node_count; ++u) { + int start = g->offset[u]; + int end = g->offset[u + 1]; + int i; + for (i = start; i < end; ++i) { + int v = g->neighbors[i]; + if (u < v) { + edges[idx].u = u; + edges[idx].v = v; + edges[idx].assigned = -1; + idx++; + } + } + } + + assert(idx == total); + *out_count = total; + return edges; +} + +static EdgeMapEntry *build_edge_map(const EdgeInfo *edges, int edge_count) { + EdgeMapEntry *map; + int i; + if (edge_count == 0) { + return NULL; + } + map = (EdgeMapEntry *)malloc(edge_count * sizeof(EdgeMapEntry)); + assert(map); + for (i = 0; i < edge_count; ++i) { + map[i].key = make_edge_key(edges[i].u, edges[i].v); + map[i].index = i; + } + qsort(map, edge_count, sizeof(EdgeMapEntry), cmp_edge_map); + return map; +} + +static int collect_edge_candidate(const EdgeInfo *edges, EdgeMapEntry *map, int map_size, int u, int v, int comp_idx, IntVector *list, int *assigned) { + int idx = edge_map_find(map, map_size, u, v); + if (idx < 0) { + return 0; + } + if (edges[idx].assigned == comp_idx) { + return 0; + } + if (edges[idx].assigned != -1) { + return 0; + } + vec_push(list, idx); + (*assigned)++; + return 1; +} + +static int evaluate_orientation(const EdgeInfo *edges, EdgeMapEntry *map, int map_size, WorkComponent *comp, int comp_idx, int nodeA, int nodeB, int min_con, IntVector *tmp_edges, int *addA, int *addB, int *num, int *den) { + int inA = vector_contains(&comp->nodesA, nodeA); + int inB = vector_contains(&comp->nodesB, nodeB); + int add_u = inA ? 0 : 1; + int add_v = inB ? 0 : 1; + int new_sizeA; + int new_sizeB; + int new_edges = 0; + int numerator; + + if (!inA && vector_contains(&comp->nodesB, nodeA)) { + return 0; + } + if (!inB && vector_contains(&comp->nodesA, nodeB)) { + return 0; + } + + new_sizeA = comp->nodesA.size + add_u; + new_sizeB = comp->nodesB.size + add_v; + if (new_sizeA == 0 || new_sizeB == 0) { + return 0; + } + + vec_clear(tmp_edges); + + if (add_u) { + int i; + for (i = 0; i < comp->nodesB.size; ++i) { + collect_edge_candidate(edges, map, map_size, nodeA, comp->nodesB.data[i], comp_idx, tmp_edges, &new_edges); + } + } + + if (add_v) { + int i; + for (i = 0; i < comp->nodesA.size; ++i) { + collect_edge_candidate(edges, map, map_size, comp->nodesA.data[i], nodeB, comp_idx, tmp_edges, &new_edges); + } + } + + if (add_u && add_v) { + collect_edge_candidate(edges, map, map_size, nodeA, nodeB, comp_idx, tmp_edges, &new_edges); + } + + if (!add_u && !add_v) { + collect_edge_candidate(edges, map, map_size, nodeA, nodeB, comp_idx, tmp_edges, &new_edges); + } + + numerator = comp->edge_count + new_edges; + *den = new_sizeA * new_sizeB; + *num = numerator; + + if ((int64_t)numerator * 100 < (int64_t)min_con * (*den)) { + return 0; + } + + *addA = add_u; + *addB = add_v; + return 1; +} + +static void assign_edges_to_component(EdgeInfo *edges, WorkComponent *comp, IntVector *edge_indices, int comp_idx) { + int i; + for (i = 0; i < edge_indices->size; ++i) { + int idx = edge_indices->data[i]; + edges[idx].assigned = comp_idx; + vec_push(&comp->edges, idx); + comp->edge_count++; + } +} + +static int compare_core_desc(const void *a, const void *b) { + const ComponentRecord *ra = (const ComponentRecord *)a; + const ComponentRecord *rb = (const ComponentRecord *)b; + int64_t ea = (int64_t)ra->sizeA * (int64_t)ra->sizeB; + int64_t eb = (int64_t)rb->sizeA * (int64_t)rb->sizeB; + if (ea > eb) { + return -1; + } + if (ea < eb) { + return 1; + } + return 0; +} + +static void build_core_components(EdgeInfo *edges, EdgeMapEntry *map, int map_size, int min_part_size, ComponentList *cores, WorkComponent **out_components, int *out_count) { + WorkComponent *components; + int comp_count = 0; + int capacity = 4; + int i; + + components = (WorkComponent *)malloc(capacity * sizeof(WorkComponent)); + assert(components); + + for (i = 0; i < cores->size; ++i) { + ComponentRecord *rec = &cores->data[i]; + int ok = 1; + int a; + if (rec->sizeA < min_part_size || rec->sizeB < min_part_size) { + continue; + } + for (a = 0; a < rec->sizeA && ok; ++a) { + int b; + for (b = 0; b < rec->sizeB; ++b) { + int idx = edge_map_find(map, map_size, rec->nodesA[a], rec->nodesB[b]); + if (idx < 0 || edges[idx].assigned != -1) { + ok = 0; + break; + } + } + } + if (!ok) { + continue; + } + if (comp_count == capacity) { + capacity *= 2; + components = (WorkComponent *)realloc(components, capacity * sizeof(WorkComponent)); + assert(components); + } + work_component_init(&components[comp_count]); + for (a = 0; a < rec->sizeA; ++a) { + vector_insert_sorted(&components[comp_count].nodesA, rec->nodesA[a]); + } + for (a = 0; a < rec->sizeB; ++a) { + vector_insert_sorted(&components[comp_count].nodesB, rec->nodesB[a]); + } + { + int ai; + for (ai = 0; ai < rec->sizeA; ++ai) { + int bi; + for (bi = 0; bi < rec->sizeB; ++bi) { + int idx = edge_map_find(map, map_size, rec->nodesA[ai], rec->nodesB[bi]); + assert(idx >= 0 && edges[idx].assigned == -1); + edges[idx].assigned = comp_count; + vec_push(&components[comp_count].edges, idx); + components[comp_count].edge_count++; + } + } + } + comp_count++; + } + + *out_components = components; + *out_count = comp_count; +} + +static void expand_components(EdgeInfo *edges, EdgeMapEntry *map, int map_size, WorkComponent *components, int comp_count, int edge_count, int min_con_value) { + IntVector tmp_edges; + IntVector best_edges; + int progress = 1; + + vec_init(&tmp_edges); + vec_init(&best_edges); + + while (progress) { + int e; + progress = 0; + for (e = 0; e < edge_count; ++e) { + int u; + int v; + int best_comp = -1; + int best_addA = 0; + int best_addB = 0; + int best_num = 0; + int best_den = 1; + int best_nodeA = -1; + int best_nodeB = -1; + int comp_idx; + + if (edges[e].assigned != -1) { + continue; + } + u = edges[e].u; + v = edges[e].v; + vec_clear(&best_edges); + + for (comp_idx = 0; comp_idx < comp_count; ++comp_idx) { + WorkComponent *comp = &components[comp_idx]; + int addA; + int addB; + int num; + int den; + if (evaluate_orientation(edges, map, map_size, comp, comp_idx, u, v, min_con_value, &tmp_edges, &addA, &addB, &num, &den)) { + int better = 0; + if ((int64_t)num * best_den > (int64_t)best_num * den) { + better = 1; + } else if ((int64_t)num * best_den == (int64_t)best_num * den && num > best_num) { + better = 1; + } + if (better) { + best_comp = comp_idx; + best_addA = addA; + best_addB = addB; + best_num = num; + best_den = den; + best_nodeA = u; + best_nodeB = v; + vec_clear(&best_edges); + vec_reserve(&best_edges, tmp_edges.size); + memcpy(best_edges.data, tmp_edges.data, tmp_edges.size * sizeof(int)); + best_edges.size = tmp_edges.size; + } + } + if (evaluate_orientation(edges, map, map_size, comp, comp_idx, v, u, min_con_value, &tmp_edges, &addA, &addB, &num, &den)) { + int better = 0; + if ((int64_t)num * best_den > (int64_t)best_num * den) { + better = 1; + } else if ((int64_t)num * best_den == (int64_t)best_num * den && num > best_num) { + better = 1; + } + if (better) { + best_comp = comp_idx; + best_addA = addA; + best_addB = addB; + best_num = num; + best_den = den; + best_nodeA = v; + best_nodeB = u; + vec_clear(&best_edges); + vec_reserve(&best_edges, tmp_edges.size); + memcpy(best_edges.data, tmp_edges.data, tmp_edges.size * sizeof(int)); + best_edges.size = tmp_edges.size; + } + } + } + + if (best_comp != -1) { + WorkComponent *comp = &components[best_comp]; + if (best_addA && !vector_contains(&comp->nodesA, best_nodeA)) { + vector_insert_sorted(&comp->nodesA, best_nodeA); + } + if (best_addB && !vector_contains(&comp->nodesB, best_nodeB)) { + vector_insert_sorted(&comp->nodesB, best_nodeB); + } + assign_edges_to_component(edges, comp, &best_edges, best_comp); + progress = 1; + } + } + } + + vec_free(&tmp_edges); + vec_free(&best_edges); +} + +static SolverContext * solver_run(int *pairs, int pair_count, int min_con_value, int min_part_size) { + SolverContext *ctx; + ComponentList cores; + ctx = (SolverContext *)calloc(1, sizeof(SolverContext)); + assert(ctx); + + graph_build(&ctx->graph, pairs, pair_count); + ctx->edges = build_edge_list(&ctx->graph, &ctx->edge_count); + ctx->edge_map = build_edge_map(ctx->edges, ctx->edge_count); + + component_list_init(&cores); + detect_components(&ctx->graph, 100, min_part_size, &cores); + if (cores.size > 1) { + qsort(cores.data, cores.size, sizeof(ComponentRecord), compare_core_desc); + } + build_core_components(ctx->edges, ctx->edge_map, ctx->edge_count, min_part_size, &cores, &ctx->components, &ctx->component_count); + expand_components(ctx->edges, ctx->edge_map, ctx->edge_count, ctx->components, ctx->component_count, ctx->edge_count, min_con_value); + validate_edge_ownership(ctx); + + component_list_free(&cores); + return ctx; +} + +static int * solver_build_result_array(const SolverContext *ctx) { + int total_sets = ctx->component_count * 2; + int total_ints = 1; + int *result; + int offset = 1; + int c; + + for (c = 0; c < ctx->component_count; ++c) { + total_ints += 1 + ctx->components[c].nodesA.size; + total_ints += 1 + ctx->components[c].nodesB.size; + } + + result = (int *)malloc(total_ints * sizeof(int)); + assert(result); + result[0] = total_sets; + + for (c = 0; c < ctx->component_count; ++c) { + int i; + result[offset++] = ctx->components[c].nodesA.size; + for (i = 0; i < ctx->components[c].nodesA.size; ++i) { + int node = ctx->components[c].nodesA.data[i]; + result[offset++] = ctx->graph.orig_ids[node]; + } + result[offset++] = ctx->components[c].nodesB.size; + for (i = 0; i < ctx->components[c].nodesB.size; ++i) { + int node = ctx->components[c].nodesB.data[i]; + result[offset++] = ctx->graph.orig_ids[node]; + } + } + + return result; +} + +static void solver_free_context(SolverContext *ctx) { + int i; + if (!ctx) { + return; + } + for (i = 0; i < ctx->component_count; ++i) { + work_component_free(&ctx->components[i]); + } + free(ctx->components); + free(ctx->edges); + free(ctx->edge_map); + graph_free(&ctx->graph); + free(ctx); +} + +static void print_components(const SolverContext *ctx) { + int c; + if (ctx->component_count == 0) { + printf("The number of components found is 0.\n"); + return; + } + printf("The number of components found is %d:\n", ctx->component_count); + for (c = 0; c < ctx->component_count; ++c) { + const WorkComponent *comp = &ctx->components[c]; + int i; + printf("Component %d:\n", c + 1); + printf(" { "); + for (i = 0; i < comp->nodesA.size; ++i) { + printf("%d ", ctx->graph.orig_ids[comp->nodesA.data[i]]); + } + printf("}\n"); + printf(" { "); + for (i = 0; i < comp->nodesB.size; ++i) { + printf("%d ", ctx->graph.orig_ids[comp->nodesB.data[i]]); + } + printf("}\n"); + + printf(" "); + for (i = 0; i < comp->nodesA.size; ++i) { + printf("%6d", ctx->graph.orig_ids[comp->nodesA.data[i]]); + } + printf("\n"); + { + int row; + for (row = 0; row < comp->nodesB.size; ++row) { + int nodeB = comp->nodesB.data[row]; + int col; + printf("%6d", ctx->graph.orig_ids[nodeB]); + for (col = 0; col < comp->nodesA.size; ++col) { + int nodeA = comp->nodesA.data[col]; + int idx = edge_map_find(ctx->edge_map, ctx->edge_count, nodeA, nodeB); + int mark = 0; + if (idx >= 0 && ctx->edges[idx].assigned == c) { + mark = 1; + } + printf("%6c", mark ? 'x' : ' '); + } + printf("\n"); + } + } + printf("\n"); + } +} + +int * compute_bipartite_subgraphs(int *pArray, int nSize, int min_con_value, int min_part_size, int fVerbose) { + SolverContext *ctx = solver_run(pArray, nSize, min_con_value, min_part_size); + int *result = solver_build_result_array(ctx); + if ( fVerbose ) print_components(ctx); + solver_free_context(ctx); + return result; +} + +/* + +static int * read_edge_list(const char *filename, int *out_size) { + FILE *fp = fopen(filename, "r"); + int capacity = 1024; + int count = 0; + int value; + int *data; + assert(fp); + + data = (int *)malloc(capacity * sizeof(int)); + assert(data); + while (fscanf(fp, "%d", &value) == 1) { + if (count == capacity) { + capacity *= 2; + data = (int *)realloc(data, capacity * sizeof(int)); + assert(data); + } + data[count++] = value; + } + fclose(fp); + assert((count & 1) == 0); + *out_size = count; + return data; +} + +static void usage(void) { + printf("Usage: bipart \n"); + printf(" or: bipart -C -M \n"); +} + +int main(int argc, char **argv) { + int min_con_value = 0; + int min_part_size = 0; + const char *filename = NULL; + int i; + int *edges_data; + int edge_count; + SolverContext *ctx; + clock_t start; + clock_t end; + double seconds; + int *result_array; + + if (argc == 4) { + min_con_value = atoi(argv[1]); + min_part_size = atoi(argv[2]); + filename = argv[3]; + } else { + for (i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-C") == 0 && i + 1 < argc) { + min_con_value = atoi(argv[++i]); + } else if (strcmp(argv[i], "-M") == 0 && i + 1 < argc) { + min_part_size = atoi(argv[++i]); + } else if (argv[i][0] != '-') { + filename = argv[i]; + } + } + } + + if (!filename || min_con_value < 50 || min_con_value > 100 || min_part_size <= 0) { + usage(); + return 1; + } + + printf("Computing bi-partite components of the graph \"%s\".\n", filename); + printf("Assuming minimum connectivity %d%%.\n", min_con_value); + printf("Assuming minimum partition size %d nodes.\n\n", min_part_size); + + edges_data = read_edge_list(filename, &edge_count); + + start = clock(); + ctx = solver_run(edges_data, edge_count, min_con_value, min_part_size); + end = clock(); + seconds = (double)(end - start) / (double)CLOCKS_PER_SEC; + + printf("The problem is solved in %.2f sec.\n\n", seconds); + + print_components(ctx); + + result_array = solver_build_result_array(ctx); + free(result_array); + + solver_free_context(ctx); + free(edges_data); + return 0; +} +*/ + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + From 6cab9445352c00632b6f7af12184f5398d5844be Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 9 Nov 2025 11:28:25 -0800 Subject: [PATCH 04/38] New command %gen. --- src/base/wlc/wlcCom.c | 115 ++++++++ src/misc/util/module.make | 1 + src/misc/util/utilMiniver.c | 523 ++++++++++++++++++++++++++++++++++++ src/misc/vec/vecInt.h | 10 + 4 files changed, 649 insertions(+) create mode 100644 src/misc/util/utilMiniver.c diff --git a/src/base/wlc/wlcCom.c b/src/base/wlc/wlcCom.c index a3747fcfd..d024c8323 100644 --- a/src/base/wlc/wlcCom.c +++ b/src/base/wlc/wlcCom.c @@ -32,6 +32,7 @@ ABC_NAMESPACE_IMPL_START static int Abc_CommandReadWlc ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandWriteWlc ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandGenWlc ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandPs ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandCone ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbs ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -79,6 +80,7 @@ void Wlc_Init( Abc_Frame_t * pAbc ) { Cmd_CommandAdd( pAbc, "Word level", "%read", Abc_CommandReadWlc, 0 ); Cmd_CommandAdd( pAbc, "Word level", "%write", Abc_CommandWriteWlc, 0 ); + Cmd_CommandAdd( pAbc, "Word level", "%gen", Abc_CommandGenWlc, 0 ); Cmd_CommandAdd( pAbc, "Word level", "%ps", Abc_CommandPs, 0 ); Cmd_CommandAdd( pAbc, "Word level", "%cone", Abc_CommandCone, 0 ); Cmd_CommandAdd( pAbc, "Word level", "%abs", Abc_CommandAbs, 0 ); @@ -305,6 +307,119 @@ usage: return 1; } + +/**Function******************************************************************** + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +******************************************************************************/ +int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern int miniver_translate(const char *input, char *out, size_t cap); + char * pFileName = NULL; + int c, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "Fvh" ) ) != EOF ) + { + switch ( c ) + { + case 'F': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-L\" should be followed by a file name.\n" ); + goto usage; + } + pFileName = argv[globalUtilOptind]; + globalUtilOptind++; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( argc != globalUtilOptind + 1 ) { + printf( "The input string is not given on the command line.\n" ); + goto usage; + } + else { + int Size = 10000; + char * pStr = argv[globalUtilOptind]; + char * pOutStr = ABC_CALLOC( char, Size+1 ); + int RetValue = miniver_translate( pStr, pOutStr, Size ); + if ( !RetValue ) { + if ( fVerbose ) + printf( "Entered Verilog design:\n%s", pOutStr ); + if ( pFileName ) { + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) + printf( "Cannot open output file \"%s\".\n", pFileName ); + else { + fprintf( pFile, "// Design generated from mini-Verilog string: %s\n\n%s\n", pStr, pOutStr ); + fclose( pFile ); + printf( "Dumped the design generated from mini-Verilog string \"%s\" into file \"%s\".\n", pStr, pFileName ); + } + } + else { + Wlc_Ntk_t * pNtk = Wlc_ReadVer( NULL, pOutStr, 0 ); + if ( pNtk ) { + Wlc_AbcUpdateNtk( pAbc, pNtk ); + //printf( "Read current design using %%read \n" ); + } + else { + printf( "The following design in Verilog, which was generated from string \"%s\",\n", pStr ); + printf( "cannot be read into ABC due to the known limitations of command \"%%read\".\n" ); + printf( "Please try the following \"%%gen -F ; %%yosys -b ; &ps\".\n" ); + printf( "Generated design:\n%s\n", pOutStr ); + } + } + } + ABC_FREE( pOutStr ); + } + return 0; +usage: + Abc_Print( -2, "\nusage: %%gen [-F file] [-vh] \"\"\n" ); + Abc_Print( -2, "\t generates the design from a mini-Verilog string\n" ); + Abc_Print( -2, "\t-F file : optional file name to save the design in standard Verilog [default = unused]\n" ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\n" ); + Abc_Print( -2, "A mini-Verilog design is a single string. Any spaces/tabs/newlines are ignored.\n" ); + Abc_Print( -2, "The string is split into clauses by semicolons ';'.\n" ); + Abc_Print( -2, "\n" ); + Abc_Print( -2, "Clause kinds (first character):\n" ); + Abc_Print( -2, " - 'm' : module name (appear once)\n" ); + Abc_Print( -2, " - '{i|o|w}[s]' : input/output/wire declarations\n" ); + Abc_Print( -2, " where optional 's' = signed, = bit-width (>0), = id[,id]*\n" ); + Abc_Print( -2, " Examples: i4a,b -> input [3:0] a, b;\n" ); + Abc_Print( -2, " is8x,y -> input signed [7:0] x, y;\n" ); + Abc_Print( -2, " w1t -> wire t; (width 1 prints without [0:0])\n" ); + Abc_Print( -2, " - '{o|w}[s]=' : declaration with assignment\n" ); + Abc_Print( -2, " Examples: o8z=a*b -> output [7:0] z; assign z = a*b;\n" ); + Abc_Print( -2, " w4t=a+b -> wire [3:0] t; assign t = a+b;\n" ); + Abc_Print( -2, "\n" ); + Abc_Print( -2, "Default names:\n" ); + Abc_Print( -2, " - Outputs: if an 'o...' assignment omits a name (e.g., 'o8='), the output name defaults to 'o'.\n" ); + Abc_Print( -2, " - Inputs: if an 'i...' clause omits names (e.g., 'i4'), a single input is declared with an\n" ); + Abc_Print( -2, " auto-generated unsigned name 'a', then 'b', then 'c', ... in the order of appearance (skipping\n" ); + Abc_Print( -2, " names already used). This allows for specifying a 4-bit multiplier 'mul' as: 'mmul;i4;i4;o8=a*b'.\n" ); + Abc_Print( -2, "\n" ); + Abc_Print( -2, "Notes:\n" ); + Abc_Print( -2, " * Only a single, non-hierarchical, combinational module is supported.\n" ); + Abc_Print( -2, " * Whitespace anywhere is ignored before parsing (handled internally).\n" ); + Abc_Print( -2, " * RHS expressions are passed through verbatim (must be in valid Verilog).\n" ); + return 1; +} + /**Function******************************************************************** Synopsis [] diff --git a/src/misc/util/module.make b/src/misc/util/module.make index c3b797e7c..991f6f311 100644 --- a/src/misc/util/module.make +++ b/src/misc/util/module.make @@ -6,6 +6,7 @@ SRC += src/misc/util/utilBridge.c \ src/misc/util/utilFile.c \ src/misc/util/utilIsop.c \ src/misc/util/utilLinear.c \ + src/misc/util/utilMiniver.c \ src/misc/util/utilNam.c \ src/misc/util/utilPrefix.cpp \ src/misc/util/utilPth.c \ diff --git a/src/misc/util/utilMiniver.c b/src/misc/util/utilMiniver.c new file mode 100644 index 000000000..53fbb5b2e --- /dev/null +++ b/src/misc/util/utilMiniver.c @@ -0,0 +1,523 @@ +/**CFile**************************************************************** + + FileName [utilMiniver.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Handling counter-examples.] + + Synopsis [Handling counter-examples.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: utilMiniver.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include +#include +#include +#include +#include + +#include "misc/util/abc_global.h" + +ABC_NAMESPACE_IMPL_START + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define MINIVER_LIBRARY_ONLY + +#define MAXSIG 1024 +#define MAXSTR 65536 + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +typedef struct { + char name[128]; + int width; + int is_signed; +} decl_t; + +typedef struct { + char lhs[128]; + char rhs[4096]; +} asn_t; + +// Parsing/collection context (encapsulates all state) +typedef struct { + char modname[128]; + decl_t inputs[MAXSIG]; int ni; + decl_t outputs[MAXSIG]; int no; + decl_t wires[MAXSIG]; int nw; + asn_t assigns[MAXSIG]; int na; + int next_auto_in; // next index for auto-generated input names ('a' + idx) +} mv_ctx; + +// ----------------------------------------------------------------------------- +// Utilities +// ----------------------------------------------------------------------------- + +// Remove all ASCII whitespace from 's' into 'out'. +static void strip_ws(const char *s, char *out) { + while (*s) { + if (!isspace((unsigned char)*s)) { + *out++ = *s; + } + ++s; + } + *out = 0; +} + +static int is_ident_start(char c) { + return isalpha((unsigned char)c) || c == '_' || c == '$'; +} + +static int is_ident_char(char c) { + return isalnum((unsigned char)c) || c == '_' || c == '$'; +} + +// Parse a non-negative decimal integer from 's'; store value in *v and chars consumed in *nch. +static int parse_uint(const char *s, int *v, int *nch) { + int i = 0; + int d = 0; + if (!isdigit((unsigned char)s[0])) return 0; + while (isdigit((unsigned char)s[i])) { + d = d * 10 + (s[i] - '0'); + ++i; + } + *v = d; + *nch = i; + return 1; +} + +// Check if a name is already used in any declaration. +static int name_exists(mv_ctx *ctx, const char *name) { + for (int i = 0; i < ctx->ni; ++i) if (!strcmp(ctx->inputs[i].name, name)) return 1; + for (int i = 0; i < ctx->no; ++i) if (!strcmp(ctx->outputs[i].name, name)) return 1; + for (int i = 0; i < ctx->nw; ++i) if (!strcmp(ctx->wires[i].name, name)) return 1; + return 0; +} + +// Generate next auto input name: 'a','b','c',... then 'a0','a1',... if 26 exhausted. +static void gen_auto_in_name(mv_ctx *ctx, char *out, size_t out_sz) { + // try single letters first + for (; ctx->next_auto_in < 26; ++ctx->next_auto_in) { + char cand[3] = {(char)('a' + ctx->next_auto_in), 0, 0}; + if (!name_exists(ctx, cand)) { strncpy(out, cand, out_sz-1); out[out_sz-1]=0; ++ctx->next_auto_in; return; } + } + // fallback to aN form + for (int n = 0;; ++n) { + char cand[32]; + snprintf(cand, sizeof(cand), "a%d", n); + if (!name_exists(ctx, cand)) { strncpy(out, cand, out_sz-1); out[out_sz-1]=0; return; } + } +} + +// Add (or deduplicate) declaration into an array. +static void add_decl(decl_t *arr, int *cnt, const char *name, int w, int sg) { + for (int k = 0; k < *cnt; ++k) { + if (!strcmp(arr[k].name, name)) return; + } + strncpy(arr[*cnt].name, name, sizeof(arr[*cnt].name) - 1); + arr[*cnt].width = w; + arr[*cnt].is_signed = sg; + ++(*cnt); +} + +// Record an assignment; returns non-zero on overflow. +static int add_asn(mv_ctx *ctx, const char *lhs, const char *rhs) { + if (ctx->na >= MAXSIG) { + printf("Too many assignments.\n"); + return 1; + } + strncpy(ctx->assigns[ctx->na].lhs, lhs, sizeof(ctx->assigns[ctx->na].lhs) - 1); + strncpy(ctx->assigns[ctx->na].rhs, rhs, sizeof(ctx->assigns[ctx->na].rhs) - 1); + ++ctx->na; + return 0; +} + +// Append formatted text to user-provided buffer with capacity checks. +// On insufficient capacity, print message and return 1; otherwise 0. +static int out_cat(char **p, size_t *left, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int need = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + if (need < 0 || (size_t)need >= *left) { + printf("Output exceeds buffer capacity.\n"); + return 1; + } + va_start(ap, fmt); + int wrote = vsnprintf(*p, *left, fmt, ap); + va_end(ap); + *p += wrote; + *left -= (size_t)wrote; + return 0; +} + +// Emit declarations into the output buffer. +static int print_decl_to_buf(char **p, size_t *left, const char *kw, decl_t *arr, int n) { + for (int i = 0; i < n; ++i) { + int w = arr[i].width; + int sg = arr[i].is_signed; + const char *id = arr[i].name; + if (w == 1) { + if (out_cat(p, left, " %s %s%s;\n", kw, sg ? "signed " : "", id)) return 1; + } else { + if (out_cat(p, left, " %s %s[%d:0] %s;\n", kw, sg ? "signed " : "", w - 1, id)) return 1; + } + } + return 0; +} + +// Add spaces around every alphanumeric/underscore sequence for readability. +// Example: "a*b+16'b0" -> " a * b + 16 ' b0 " +static void format_rhs_readable(const char *in, char *out, size_t cap) { + size_t o = 0; + for (size_t i = 0; in[i]; ) { + unsigned char c = (unsigned char)in[i]; + if (isalnum(c) || c == '_') { + // start of a token + if (o + 1 >= cap) { if (o) out[o-1] = 0; else if (cap) out[0] = 0; return; } + out[o++] = ' '; + // copy token + size_t j = i; + while (in[j] && (isalnum((unsigned char)in[j]) || in[j] == '_')) { + if (o + 1 >= cap) { out[o-1] = 0; return; } + out[o++] = in[j++]; + } + if (o + 1 >= cap) { out[o-1] = 0; return; } + out[o++] = ' '; + i = j; + } else { + if (o + 1 >= cap) { if (o) out[o-1] = 0; else if (cap) out[0] = 0; return; } + out[o++] = in[i++]; + } + } + if (o < cap) out[o] = 0; else if (cap) out[cap-1] = 0; +} + +// ----------------------------------------------------------------------------- +// Parsing helpers that quote offending clauses +// ----------------------------------------------------------------------------- + +typedef int (*emit_fn)(mv_ctx *, const char *, int, int); + +static int emit_in(mv_ctx *ctx, const char *id, int w, int sg) { + add_decl(ctx->inputs, &ctx->ni, id, w, sg); + return 0; +} + +static int emit_wi(mv_ctx *ctx, const char *id, int w, int sg) { + add_decl(ctx->wires, &ctx->nw, id, w, sg); + return 0; +} + +// Split an identifier list like "a,b,c" and emit each item. Quotes 'clause' in diagnostics. +static int split_ids(mv_ctx *ctx, const char *clause, const char *s, emit_fn emit, int w, int sg) { + char buf[128]; + int j = 0; + + for (int i = 0;; ++i) { + char c = s[i]; + if (c == ',' || c == 0) { + if (j == 0) { + printf("Syntax error: empty identifier in expression \"%s\".\n", clause); + return 1; + } + buf[j] = 0; + if (emit(ctx, buf, w, sg)) return 1; + j = 0; + if (c == 0) break; + } else { + if (j >= 120) { + printf("Identifier too long in expression \"%s\".\n", clause); + return 1; + } + if (!((j ? is_ident_char(c) : is_ident_start(c)))) { + printf("Illegal identifier in expression \"%s\".\n", clause); + return 1; + } + buf[j++] = c; + } + } + return 0; +} + +// Parse one clause (already whitespace-stripped). On error, prints a message including the clause. +static int parse_clause(mv_ctx *ctx, const char *q) { + if (!q || !*q) return 0; + + if (q[0] == 'm') { + if (!is_ident_start(q[1])) { + printf("Syntax error after 'm' in expression \"%s\".\n", q); + return 1; + } + int i = 1; + while (q[i] && is_ident_char(q[i])) ++i; + if (q[i]) { + printf("Garbage after module name in expression \"%s\".\n", q); + return 1; + } + size_t n = (size_t)(i - 1); + if (n >= sizeof(ctx->modname)) n = sizeof(ctx->modname) - 1; + strncpy(ctx->modname, q + 1, n); + ctx->modname[n] = 0; + return 0; + } + + if (q[0] != 'i' && q[0] != 'o' && q[0] != 'w') { + printf("Unknown clause start in expression \"%s\".\n", q); + return 1; + } + + int kind = q[0]; + int i = 1; + int sg = 0; + int w = 0; + int nconsumed = 0; + + if (q[i] == 's') { + sg = 1; + ++i; + } + if (!parse_uint(q + i, &w, &nconsumed)) { + printf("Width expected in expression \"%s\".\n", q); + return 1; + } + i += nconsumed; + if (w <= 0) { + printf("Non-positive width in expression \"%s\".\n", q); + return 1; + } + + const char *eq = strchr(q + i, '='); + + if (kind == 'i') { + // Support unnamed inputs: 'i4' -> auto-generate one input named a,b,c,... + if (!q[i]) { + char auto_name[32]; + gen_auto_in_name(ctx, auto_name, sizeof(auto_name)); + add_decl(ctx->inputs, &ctx->ni, auto_name, w, sg); + return 0; + } + if (eq) { + printf("Unexpected '=' in input clause in expression \"%s\".\n", q); + return 1; + } + return split_ids(ctx, q, q + i, emit_in, w, sg); + } + + if (kind == 'w' && !eq) { + if (!q[i]) { + printf("Identifiers expected for wires in expression \"%s\".\n", q); + return 1; + } + return split_ids(ctx, q, q + i, emit_wi, w, sg); + } + + if (!eq) { + printf("Assignment expected in expression \"%s\".\n", q); + return 1; + } + + // Parse the LHS name for 'o' or 'w'. For 'o', allow omitted name (defaults to "o"). + char lhs[128]; + int lj = 0; + for (int k = i; k < (int)(eq - q); ++k) { + char c = q[k]; + if (!lj && kind == 'o' && !is_ident_start(c)) { + lhs[0] = 'o'; + lhs[1] = 0; + goto lhs_done; + } + if (!(lj ? is_ident_char(c) : is_ident_start(c))) { + printf("Illegal LHS identifier in expression \"%s\".\n", q); + return 1; + } + if (lj >= 120) { + printf("Identifier too long in expression \"%s\".\n", q); + return 1; + } + lhs[lj++] = c; + } + if (lj == 0) { + if (kind == 'o') { + lhs[0] = 'o'; + lhs[1] = 0; + } else { + printf("Wire assignment needs a name in expression \"%s\".\n", q); + return 1; + } + } else { + lhs[lj] = 0; + } +lhs_done:; + const char *rhs = eq + 1; + if (!*rhs) { + printf("Empty RHS expression in expression \"%s\".\n", q); + return 1; + } + + if (kind == 'o') add_decl(ctx->outputs, &ctx->no, lhs, w, sg); + if (kind == 'w') add_decl(ctx->wires, &ctx->nw, lhs, w, sg); + return add_asn(ctx, lhs, rhs); +} + +// ----------------------------------------------------------------------------- +// Public API +// ----------------------------------------------------------------------------- + +// Translate a raw mini-Verilog string 'input' into standard Verilog. +// The function strips whitespace internally, parses, and writes into 'out' (cap bytes). +// Returns 0 on success, 1 on error. Errors are printed (no exit()). +int miniver_translate(const char *input, char *out, size_t cap) { + if (!input || !out || cap == 0) { + printf("Invalid arguments.\n"); + return 1; + } + + // Step 1: strip whitespace (per spec). + char flat[MAXSTR]; + strip_ws(input, flat); + if (!*flat) { + printf("Empty input.\n"); + return 1; + } + + // Step 2: parse clauses into a context. + mv_ctx *ctx = (mv_ctx*)calloc(1, sizeof(mv_ctx)); + if (!ctx) { + printf("Out of memory.\n"); + return 1; + } + strncpy(ctx->modname, "top", sizeof(ctx->modname) - 1); + ctx->next_auto_in = 0; + + // Make a modifiable copy to split on semicolons. + char *buf = (char*)malloc(strlen(flat) + 1); + if (!buf) { + printf("Out of memory.\n"); + free(ctx); + return 1; + } + strcpy(buf, flat); + + char *s = buf; + while (*s) { + char *semi = strchr(s, ';'); + if (semi) *semi = 0; + if (parse_clause(ctx, s)) { + free(buf); + free(ctx); + return 1; + } + if (!semi) break; + s = semi + 1; + } + free(buf); + + if (!*ctx->modname) { + printf("Module name missing.\n"); + free(ctx); + return 1; + } + if (ctx->no == 0) { + printf("At least one output with assignment is required.\n"); + free(ctx); + return 1; + } + + // Step 3: emit Verilog into caller buffer. + char *p = out; + size_t left = cap; + + if (out_cat(&p, &left, "module %s (", ctx->modname)) { + free(ctx); return 1; + } + for (int i = 0; i < ctx->ni; ++i) { + if (out_cat(&p, &left, "%s%s", i ? ", " : "", ctx->inputs[i].name)) { + free(ctx); return 1; + } + } + for (int i = 0; i < ctx->no; ++i) { + if (out_cat(&p, &left, "%s%s", (ctx->ni || i) ? ", " : "", ctx->outputs[i].name)) { + free(ctx); return 1; + } + } + if (out_cat(&p, &left, ");\n")) { + free(ctx); return 1; + } + + if (print_decl_to_buf(&p, &left, "input", ctx->inputs, ctx->ni)) { free(ctx); return 1; } + if (print_decl_to_buf(&p, &left, "output", ctx->outputs, ctx->no)) { free(ctx); return 1; } + if (print_decl_to_buf(&p, &left, "wire", ctx->wires, ctx->nw)) { free(ctx); return 1; } + + for (int i = 0; i < ctx->na; ++i) { + char rhs_sp[8192]; + format_rhs_readable(ctx->assigns[i].rhs, rhs_sp, sizeof(rhs_sp)); + if (out_cat(&p, &left, " assign %s = %s;\n", ctx->assigns[i].lhs, rhs_sp)) { + free(ctx); return 1; + } + } + if (out_cat(&p, &left, "endmodule\n")) { + free(ctx); return 1; + } + + *p = 0; + free(ctx); + return 0; +} + +// ----------------------------------------------------------------------------- +// Optional CLI wrapper (define MINIVER_LIBRARY_ONLY to omit main) +// ----------------------------------------------------------------------------- +#ifndef MINIVER_LIBRARY_ONLY +int main(int argc, char **argv) { + char in[MAXSTR] = {0}; + + if (argc >= 2) { + size_t L = strlen(argv[1]); + if (L >= MAXSTR - 1) { + printf("Input too long.\n"); + return 1; + } + strcpy(in, argv[1]); + } else { + size_t off = 0; + int c = 0; + while ((c = fgetc(stdin)) != EOF) { + if (off >= MAXSTR - 1) { + printf("Input too long.\n"); + return 1; + } + in[off++] = (char)c; + } + in[off] = 0; + } + + char out[10240]; + int rc = miniver_translate(in, out, sizeof(out)); + if (!rc) { + printf("%s", out); + } + return rc; +} +#endif + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/misc/vec/vecInt.h b/src/misc/vec/vecInt.h index f56f34da4..a03cd30b8 100644 --- a/src/misc/vec/vecInt.h +++ b/src/misc/vec/vecInt.h @@ -1278,6 +1278,16 @@ static inline Vec_Int_t * Vec_IntInvert( Vec_Int_t * p, int Fill ) Vec_IntWriteEntry( vRes, Entry, i ); return vRes; } +static inline Vec_Int_t * Vec_IntInvertSize( Vec_Int_t * p, int Size, int Fill ) +{ + Vec_Int_t * vMap = Vec_IntAlloc( 0 ); + Vec_IntFill( vMap, Size, Fill ); + int i, k; + Vec_IntForEachEntry( p, i, k ) + if ( i != Fill ) + Vec_IntWriteEntry( vMap, i, k ); + return vMap; +} /**Function************************************************************* From 0a650c18cf234fe7e705f9b4cde604e54318866c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 9 Nov 2025 16:06:50 -0800 Subject: [PATCH 05/38] New command "&genlutcas". --- src/aig/gia/giaLutCas.c | 149 ++++++++++++++++++++++++++++ src/aig/gia/module.make | 1 + src/base/abci/abc.c | 122 +++++++++++++++++++++++ src/sat/cadical/cadical_restart.cpp | 8 +- 4 files changed, 276 insertions(+), 4 deletions(-) create mode 100644 src/aig/gia/giaLutCas.c diff --git a/src/aig/gia/giaLutCas.c b/src/aig/gia/giaLutCas.c new file mode 100644 index 000000000..1d1721ab0 --- /dev/null +++ b/src/aig/gia/giaLutCas.c @@ -0,0 +1,149 @@ +/**CFile**************************************************************** + + FileName [giaLutCas.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [Scalable AIG package.] + + Synopsis [LUT cascade generator.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - June 20, 2005.] + + Revision [$Id: giaLutCas.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "gia.h" +#include "sat/cnf/cnf.h" +#include "misc/util/utilTruth.h" +#include "sat/cadical/cadicalSolver.h" + +ABC_NAMESPACE_IMPL_START + + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +/// FUNCTION DEFINITIONS /// +//////////////////////////////////////////////////////////////////////// + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline void Gia_LutCasSort( char * pStr, int iStart, int nChars ) +{ + int i, j; + for ( i = iStart; i < iStart + nChars - 1; i++ ) + for ( j = i + 1; j < iStart + nChars; j++ ) + if ( pStr[i] > pStr[j] ) + ABC_SWAP( char, pStr[i], pStr[j] ); +} +char * Gia_LutCasPerm( int nVars, int nLuts, int LutSize ) +{ + assert( nVars <= 26 && nLuts <= 100 ); + int nStrLen = nLuts * LutSize; + char * pRes = ABC_CALLOC( char, nStrLen+1 ); + int i, j, iVar, pPerm[26], nVarCount[100] = {0}; + // create a random permutation + for ( i = 0; i < nVars; i++ ) + pPerm[i] = i; + for ( i = nVars - 1; i > 0; i-- ) { + j = rand() % (i + 1); + ABC_SWAP( int, pPerm[i], pPerm[j] ); + } + // assign the first variable + for ( i = 0; i < nLuts; i++ ) { + pRes[i * LutSize] = i ? '_' : 'a' + pPerm[0]; + nVarCount[i] = 1; + } + // First pass: distribute each variable (starting from the second in permutation) to at least one LUT + for ( i = 1; i < nVars; i++ ) { + // Find a LUT with space that doesn't have this variable + int Tries = 0, iLut = rand() % nLuts; + while ( nVarCount[iLut] >= LutSize && Tries++ < nLuts ) + iLut = (iLut + 1) % nLuts; + // the variables are unique - no need to check this + pRes[iLut * LutSize + nVarCount[iLut]] = 'a' + pPerm[i]; + nVarCount[iLut]++; + } + // Second pass: fill remaining slots with random variables (cycling through permutation) + for ( i = 0; i < nLuts; i++ ) { + while ( nVarCount[i] < LutSize ) { + iVar = pPerm[rand() % nVars]; + // Check this LUT already has this variable + for ( j = 0; j < nVarCount[i]; j++ ) + if ( pRes[i * LutSize + j] == 'a' + iVar ) + break; + if ( j == nVarCount[i] ) { // does not have + pRes[i * LutSize + nVarCount[i]] = 'a' + iVar; + nVarCount[i]++; + } + } + } + // Sort inputs within each LUT (skip '_' for non-first LUTs) + Gia_LutCasSort( pRes, 0, LutSize ); + for ( i = 1; i < nLuts; i++ ) + Gia_LutCasSort( pRes + i * LutSize, 1, LutSize-1 ); + return pRes; +} +int Gia_ManLutCasGen_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_Int_t * vDatas, int Shift ) +{ + if ( iCtrl-- == 0 ) + return Vec_IntEntry( vDatas, Shift ); + int iLit0 = Gia_ManLutCasGen_rec( pNew, vCtrls, iCtrl, vDatas, Shift ); + int iLit1 = Gia_ManLutCasGen_rec( pNew, vCtrls, iCtrl, vDatas, Shift + (1<pName = Abc_UtilStrsav( pPerm ); + Vec_Int_t * vDatas = Vec_IntAlloc( nParams ); + Vec_Int_t * vCtrls = Vec_IntAlloc( nVars ); + for ( int i = 0; i < nParams; i++ ) + Vec_IntPush( vDatas, Gia_ManAppendCi(pNew) ); + for ( int i = 0; i < nVars; i++ ) + Vec_IntPush( vCtrls, Gia_ManAppendCi(pNew) ); + Vec_Int_t * vLits = Vec_IntStart( LutSize ); + Vec_IntWriteEntry( vLits, 0, Vec_IntEntry(vCtrls, (int)(pPerm[0]-'a')) ); + char * pCur = pPerm; + for ( int i = 0; i < nLuts; i++ ) { + pCur++; + for ( int k = 1; k < LutSize; k++ ) + Vec_IntWriteEntry( vLits, k, Vec_IntEntry(vCtrls, (int)(*pCur++ - 'a')) ); + Vec_IntWriteEntry( vLits, 0, Gia_ManLutCasGen_rec(pNew, vLits, LutSize, vDatas, i * (1 << LutSize)) ); + } + Gia_ManAppendCo( pNew, Vec_IntEntry(vLits, 0) ); + Vec_IntFree( vDatas ); + Vec_IntFree( vCtrls ); + Vec_IntFree( vLits ); + ABC_FREE( pPerm ); + return pNew; +} + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + + +ABC_NAMESPACE_IMPL_END + diff --git a/src/aig/gia/module.make b/src/aig/gia/module.make index dcb30e90a..4aad1385b 100644 --- a/src/aig/gia/module.make +++ b/src/aig/gia/module.make @@ -50,6 +50,7 @@ SRC += src/aig/gia/giaAig.c \ src/aig/gia/giaJf.c \ src/aig/gia/giaKf.c \ src/aig/gia/giaLf.c \ + src/aig/gia/giaLutCas.c \ src/aig/gia/giaMf.c \ src/aig/gia/giaMan.c \ src/aig/gia/giaMem.c \ diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 55e2c2c7e..e75ceadc2 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -580,6 +580,7 @@ static int Abc_CommandAbc9FFTest ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9Qbf ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9QVar ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9GenQbf ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9GenLutCas ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9HomoQbf ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SatFx ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9SatClp ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1402,6 +1403,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&qbf", Abc_CommandAbc9Qbf, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&qvar", Abc_CommandAbc9QVar, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&genqbf", Abc_CommandAbc9GenQbf, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&genlutcas", Abc_CommandAbc9GenLutCas, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&homoqbf", Abc_CommandAbc9HomoQbf, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&satfx", Abc_CommandAbc9SatFx, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&satclp", Abc_CommandAbc9SatClp, 0 ); @@ -51659,6 +51661,126 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern Gia_Man_t * Gia_ManLutCasGen( int nVars, int nLuts, int LutSize, int Seed, int fVerbose ); + int nVars = 8; + int nLuts = 2; + int LutSize = 6; + int Seed = 0; + int fVerbose = 0; + int c; + Gia_Man_t * pTemp; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "NMKSvh" ) ) != EOF ) + { + switch ( c ) + { + case 'N': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-N\" should be followed by an integer.\n" ); + goto usage; + } + nVars = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nVars < 0 ) + goto usage; + break; + case 'M': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer.\n" ); + goto usage; + } + nLuts = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nLuts < 0 ) + goto usage; + break; + case 'K': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-K\" should be followed by an integer.\n" ); + goto usage; + } + LutSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( LutSize < 0 ) + goto usage; + break; + case 'S': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-S\" should be followed by an integer.\n" ); + goto usage; + } + Seed = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( Seed < 0 ) + goto usage; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( nVars <= LutSize ) + { + Abc_Print( -1, "The number of inputs (%d) should be more than LUT size (%d).\n", nVars, LutSize ); + return 1; + } + if ( nVars > 100 ) + { + Abc_Print( -1, "The number of inputs (%d) should be less than 100.\n", nVars ); + return 1; + } + if ( nLuts < 2 || nLuts > 100 ) + { + Abc_Print( -1, "The LUT count (%d) should be morein the range [2;100].\n", nLuts ); + return 1; + } + if ( LutSize < 2 || LutSize > 12 ) + { + Abc_Print( -1, "The LUT size (%d) should be in the range [2;12].\n", LutSize ); + return 1; + } + if ( nVars > (nLuts-1)*(LutSize-1) + LutSize ) + { + Abc_Print( -1, "Function with %d variables is too large for a cascade composed of %d connected %d-LUTs.\n", nVars, nLuts, LutSize ); + return 1; + } + pTemp = Gia_ManLutCasGen( nVars, nLuts, LutSize, Seed, fVerbose ); + Abc_FrameUpdateGia( pAbc, pTemp ); + return 0; + +usage: + Abc_Print( -2, "usage: &genlutcas[-NMKS num] [-vh]\n" ); + Abc_Print( -2, "\t generates single-rail LUT cascade\n" ); + Abc_Print( -2, "\t-N num : the number of primary inputs [default = %d]\n", nVars ); + Abc_Print( -2, "\t-M num : the number of LUTs [default = %d]\n", nLuts ); + Abc_Print( -2, "\t-K num : the LUT size [default = %d]\n", LutSize ); + Abc_Print( -2, "\t-S num : the random seed [default = %d]\n", Seed ); + Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} + /**Function************************************************************* Synopsis [] diff --git a/src/sat/cadical/cadical_restart.cpp b/src/sat/cadical/cadical_restart.cpp index 1c6dc44c8..d309d5f10 100644 --- a/src/sat/cadical/cadical_restart.cpp +++ b/src/sat/cadical/cadical_restart.cpp @@ -35,12 +35,12 @@ bool Internal::stabilizing () { STOP (stable); else STOP (unstable); - const int64_t delta_conflicts = - stats.conflicts - last.stabilize.conflicts; + //const int64_t delta_conflicts = + // stats.conflicts - last.stabilize.conflicts; const int64_t delta_ticks = stats.ticks.search[stable] - last.stabilize.ticks; - const char *current_mode = stable ? "stable" : "unstable"; - const char *next_mode = stable ? "unstable" : "stable"; + //const char *current_mode = stable ? "stable" : "unstable"; + //const char *next_mode = stable ? "unstable" : "stable"; PHASE ("stabilizing", stats.stabphases, "reached %s stabilization limit %" PRId64 " after %" PRId64 " conflicts and %" PRId64 " ticks at %" PRId64 From 677299a52f3b3f3d5bcd1f17aac81a988dd9e53c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 10 Nov 2025 09:40:38 -0800 Subject: [PATCH 06/38] Updating print-outs. --- src/base/abci/abc.c | 2 +- src/base/main/mainReal.c | 2 +- src/base/wlc/wlcCom.c | 28 +++++++++++++++++++--------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index e75ceadc2..d638a6898 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -18575,7 +18575,7 @@ usage: Abc_Print( -2, "\t > 10 1\n" ); Abc_Print( -2, "\t > .end\n\n" ); Abc_Print( -2, "\t > # file i.blif\n" ); - Abc_Print( -2, "\t > .model mux21\n" ); + Abc_Print( -2, "\t > .model mux41\n" ); Abc_Print( -2, "\t > .inputs d0 d1 d2 d3 a b\n" ); Abc_Print( -2, "\t > .outputs F\n" ); Abc_Print( -2, "\t > .names d0 d1 d2 d3 a b F\n" ); diff --git a/src/base/main/mainReal.c b/src/base/main/mainReal.c index 420f2cf10..b838824ba 100644 --- a/src/base/main/mainReal.c +++ b/src/base/main/mainReal.c @@ -293,7 +293,7 @@ int Abc_RealMain( int argc, char * argv[] ) pAbc->pGia = Gia_ManFromBridge( stdin, NULL ); } else if ( fBatch!=INTERACTIVE && fBatch!=BATCH_QUIET && fBatch!=BATCH_QUIET_THEN_INTERACTIVE && Vec_StrSize(sCommandUsr)>0 ) - Abc_Print( 1, "ABC command line: \"%s\".\n\n", Vec_StrArray(sCommandUsr) ); + Abc_Print( 1, "\n======== ABC command line \"%s\"\n", Vec_StrArray(sCommandUsr) ); if ( fBatch!=INTERACTIVE ) { diff --git a/src/base/wlc/wlcCom.c b/src/base/wlc/wlcCom.c index d024c8323..c00488f4b 100644 --- a/src/base/wlc/wlcCom.c +++ b/src/base/wlc/wlcCom.c @@ -370,11 +370,11 @@ int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) } } else { + if ( fVerbose ) + printf( "Reading generated Verilog using using command %%read...\n" ); Wlc_Ntk_t * pNtk = Wlc_ReadVer( NULL, pOutStr, 0 ); - if ( pNtk ) { + if ( pNtk ) Wlc_AbcUpdateNtk( pAbc, pNtk ); - //printf( "Read current design using %%read \n" ); - } else { printf( "The following design in Verilog, which was generated from string \"%s\",\n", pStr ); printf( "cannot be read into ABC due to the known limitations of command \"%%read\".\n" ); @@ -390,13 +390,14 @@ usage: Abc_Print( -2, "\nusage: %%gen [-F file] [-vh] \"\"\n" ); Abc_Print( -2, "\t generates the design from a mini-Verilog string\n" ); Abc_Print( -2, "\t-F file : optional file name to save the design in standard Verilog [default = unused]\n" ); + Abc_Print( -2, "\t-v (if a file name is provided, Verilog is dumped into a file and not read into ABC)\n" ); Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\n" ); - Abc_Print( -2, "A mini-Verilog design is a single string. Any spaces/tabs/newlines are ignored.\n" ); - Abc_Print( -2, "The string is split into clauses by semicolons ';'.\n" ); + Abc_Print( -2, "A mini-Verilog design is a single string. Any spaces/tabs/newlines are ignored\n" ); + Abc_Print( -2, "(handled internally). The string is split into clauses by semicolons ';'.\n" ); Abc_Print( -2, "\n" ); - Abc_Print( -2, "Clause kinds (first character):\n" ); + Abc_Print( -2, "Clause types (first character):\n" ); Abc_Print( -2, " - 'm' : module name (appear once)\n" ); Abc_Print( -2, " - '{i|o|w}[s]' : input/output/wire declarations\n" ); Abc_Print( -2, " where optional 's' = signed, = bit-width (>0), = id[,id]*\n" ); @@ -411,12 +412,21 @@ usage: Abc_Print( -2, " - Outputs: if an 'o...' assignment omits a name (e.g., 'o8='), the output name defaults to 'o'.\n" ); Abc_Print( -2, " - Inputs: if an 'i...' clause omits names (e.g., 'i4'), a single input is declared with an\n" ); Abc_Print( -2, " auto-generated unsigned name 'a', then 'b', then 'c', ... in the order of appearance (skipping\n" ); - Abc_Print( -2, " names already used). This allows for specifying a 4-bit multiplier 'mul' as: 'mmul;i4;i4;o8=a*b'.\n" ); + Abc_Print( -2, " names already used). This allows for specifying a 4-bit multiplier 'mul' as: \"mmul;i4;i4;o8=a*b\".\n" ); Abc_Print( -2, "\n" ); Abc_Print( -2, "Notes:\n" ); Abc_Print( -2, " * Only a single, non-hierarchical, combinational module is supported.\n" ); - Abc_Print( -2, " * Whitespace anywhere is ignored before parsing (handled internally).\n" ); - Abc_Print( -2, " * RHS expressions are passed through verbatim (must be in valid Verilog).\n" ); + Abc_Print( -2, " * RHS expressions are passed through verbatim or with added spaces (must be in valid Verilog).\n" ); + Abc_Print( -2, " * For the design to be readable into ABC, make sure each RHS has only one operator,\n" ); + Abc_Print( -2, " with constant definition, bit-slicing, and concatenation being considered operators.\n" ); + Abc_Print( -2, " * Alternatively, use any RHS style, which make have several operator per line,\n" ); + Abc_Print( -2, " write the design by specifying the file name \"-F file\", and read it back using Yosys.\n" ); + Abc_Print( -2, " Example: \"mtest;i4a,b,c;o4z=a*b+c\" is not readable into ABC directly but readable via Yosys:\n\n" ); + Abc_Print( -2, " abc 01> %%gen \"mtest;i4a,b,c;o4z=a*b+c\"\n" ); + Abc_Print( -2, " Warning: Trailing symbols \"+ c \" in line 6.\n\n" ); + Abc_Print( -2, " abc 01> %%gen -F test.v \"mtest;i4a,b,c;o4z=a*b+c\"; %yosys -b test.v; &ps\n" ); + Abc_Print( -2, " Dumped the design generated from mini-Verilog string \"mtest;i4a,b,c;o4z=a*b+c\" into file \"test.v\".\n" ); + Abc_Print( -2, " test : i/o = 12/ 4 and = 61 lev = 15 (9.00) mem = 0.00 MB\n" ); return 1; } From 1b7912a24759279762ec5b3be6d5d748f1d58af7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 10 Nov 2025 21:03:21 -0800 Subject: [PATCH 07/38] Update to the equation solver. --- src/misc/util/utilLinear.c | 40 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/misc/util/utilLinear.c b/src/misc/util/utilLinear.c index b0f03d4a8..6d9b548db 100644 --- a/src/misc/util/utilLinear.c +++ b/src/misc/util/utilLinear.c @@ -276,7 +276,7 @@ static int verify_solution( } // Checks whether a particular free-variable assignment yields an integer solution. -// Optionally enforces that the first two variables differ once rounded to integers. +// Optionally enforces that the first four variables differ once rounded to integers. static int assign_and_check_integer( const double *rref, int nVars, @@ -292,7 +292,7 @@ static int assign_and_check_integer( double *rounded, double *out_solution, int require_nonzero, - int require_distinct_first_two) { + int require_distinct_first_four) { compute_solution_from_free( rref, nVars, @@ -334,9 +334,13 @@ static int assign_and_check_integer( } } - if (require_distinct_first_two && nVars >= 2) { - if (fabs(rounded[0] - rounded[1]) < INTEGER_TOLERANCE) { - return 0; + if (require_distinct_first_four && nVars >= 4) { + for (int i = 0; i < 4; ++i) { + for (int j = i + 1; j < 4; ++j) { + if (fabs(rounded[i] - rounded[j]) < INTEGER_TOLERANCE) { + return 0; + } + } } } @@ -367,7 +371,7 @@ static int search_integer_solutions( double *rounded, double *out_solution, int require_nonzero, - int require_distinct_first_two, + int require_distinct_first_four, int *explored, int exploration_limit) { if (*explored >= exploration_limit) { @@ -391,7 +395,7 @@ static int search_integer_solutions( rounded, out_solution, require_nonzero, - require_distinct_first_two); + require_distinct_first_four); } for (int i = 0; i < candidate_count; ++i) { @@ -414,7 +418,7 @@ static int search_integer_solutions( rounded, out_solution, require_nonzero, - require_distinct_first_two, + require_distinct_first_four, explored, exploration_limit)) { return 1; @@ -440,7 +444,7 @@ static int try_integer_solution( double *rounded, double *out_solution, int require_nonzero, - int require_distinct_first_two) { + int require_distinct_first_four) { if (free_count == 0) { return 0; } @@ -496,7 +500,7 @@ static int try_integer_solution( rounded, out_solution, require_nonzero, - require_distinct_first_two)) { + require_distinct_first_four)) { free(free_values); return 1; } @@ -519,7 +523,7 @@ static int try_integer_solution( rounded, out_solution, require_nonzero, - require_distinct_first_two, + require_distinct_first_four, &explored, exploration_limit); @@ -548,7 +552,7 @@ double *linear_equation_solver(double *pMatrix, int nEqus, int nVars) { int free_count = 0; int homogeneous_rhs = 0; int require_nonzero_integer = 0; - int require_distinct_first_two = 0; + int require_distinct_first_four = 0; int pivot_row_index = 0; int rank = 0; double max_residual = 0.0; @@ -673,7 +677,7 @@ double *linear_equation_solver(double *pMatrix, int nEqus, int nVars) { // Only demand integer solutions when the system is homogeneous with free variables. require_nonzero_integer = homogeneous_rhs && free_count > 0; // Enforce distinct first two variables whenever multiple variables remain free. - require_distinct_first_two = (free_count > 0 && nVars >= 2); + require_distinct_first_four = (free_count > 0 && nVars >= 4); solution = (double *)malloc((size_t)nVars * sizeof(double)); workspace = (double *)malloc((size_t)nVars * sizeof(double)); @@ -711,7 +715,7 @@ double *linear_equation_solver(double *pMatrix, int nEqus, int nVars) { rounded, solution, require_nonzero_integer, - require_distinct_first_two)) { + require_distinct_first_four)) { for (int i = 0; i < free_count; ++i) { workspace[i] = 0.0; } @@ -724,12 +728,12 @@ double *linear_equation_solver(double *pMatrix, int nEqus, int nVars) { free_count, workspace, solution); - if (require_nonzero_integer && require_distinct_first_two) { - printf("Note: integer solution meeting non-negative and distinct-first-two constraints not found; returning floating-point solution.\n"); + if (require_nonzero_integer && require_distinct_first_four) { + printf("Note: integer solution meeting non-negative and distinct-first-four constraints not found; returning floating-point solution.\n"); } else if (require_nonzero_integer) { printf("Note: non-negative integer solution with mixed zero/positive entries not found; returning floating-point solution.\n"); - } else if (require_distinct_first_two) { - printf("Note: integer solution with distinct first two variables not found; returning floating-point solution.\n"); + } else if (require_distinct_first_four) { + printf("Note: integer solution with distinct first four variables not found; returning floating-point solution.\n"); } else { printf("Note: integer solution not found; returning floating-point solution.\n"); } From 169e288fc474780d4b09fb76ab66118736897fe1 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 10 Nov 2025 22:00:07 -0800 Subject: [PATCH 08/38] Reading the printout. --- src/base/wlc/wlcCom.c | 16 +++-- src/misc/util/utilMiniver.c | 126 +++++++++++++++++++++++++++++++++--- 2 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/base/wlc/wlcCom.c b/src/base/wlc/wlcCom.c index c00488f4b..4382b5319 100644 --- a/src/base/wlc/wlcCom.c +++ b/src/base/wlc/wlcCom.c @@ -321,11 +321,12 @@ usage: ******************************************************************************/ int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern int miniver_translate(const char *input, char *out, size_t cap); + extern int miniver_translate(const char *input, char *out, size_t cap, int fShort); char * pFileName = NULL; + int fShort = 1; int c, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "Fvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "Fsvh" ) ) != EOF ) { switch ( c ) { @@ -338,6 +339,9 @@ int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) pFileName = argv[globalUtilOptind]; globalUtilOptind++; break; + case 's': + fShort ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -355,7 +359,7 @@ int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) int Size = 10000; char * pStr = argv[globalUtilOptind]; char * pOutStr = ABC_CALLOC( char, Size+1 ); - int RetValue = miniver_translate( pStr, pOutStr, Size ); + int RetValue = miniver_translate( pStr, pOutStr, Size, fShort ); if ( !RetValue ) { if ( fVerbose ) printf( "Entered Verilog design:\n%s", pOutStr ); @@ -387,10 +391,11 @@ int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv ) } return 0; usage: - Abc_Print( -2, "\nusage: %%gen [-F file] [-vh] \"\"\n" ); + Abc_Print( -2, "\nusage: %%gen [-F file] [-svh] \"\"\n" ); Abc_Print( -2, "\t generates the design from a mini-Verilog string\n" ); Abc_Print( -2, "\t-F file : optional file name to save the design in standard Verilog [default = unused]\n" ); - Abc_Print( -2, "\t-v (if a file name is provided, Verilog is dumped into a file and not read into ABC)\n" ); + Abc_Print( -2, "\t (if a file name is provided, Verilog is dumped into a file and not read into ABC)\n" ); + Abc_Print( -2, "\t-s : prints Verilog using a shorter format [default = %s]\n", fShort ? "yes": "no" ); Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); Abc_Print( -2, "\n" ); @@ -2129,4 +2134,3 @@ usage: ABC_NAMESPACE_IMPL_END - diff --git a/src/misc/util/utilMiniver.c b/src/misc/util/utilMiniver.c index 53fbb5b2e..d90d992f3 100644 --- a/src/misc/util/utilMiniver.c +++ b/src/misc/util/utilMiniver.c @@ -179,6 +179,67 @@ static int print_decl_to_buf(char **p, size_t *left, const char *kw, decl_t *arr return 0; } +static int print_decl_single(char **p, size_t *left, const char *kw, const decl_t *decl) { + if (out_cat(p, left, " %s ", kw)) return 1; + if (decl->is_signed) { + if (out_cat(p, left, "signed ")) return 1; + } + if (decl->width > 1) { + if (out_cat(p, left, "[%d:0] ", decl->width - 1)) return 1; + } + if (out_cat(p, left, "%s;\n", decl->name)) return 1; + return 0; +} + +static int print_decl_with_assign(char **p, size_t *left, const char *kw, const decl_t *decl, const char *rhs) { + if (out_cat(p, left, " %s ", kw)) return 1; + if (decl->is_signed) { + if (out_cat(p, left, "signed ")) return 1; + } + if (decl->width > 1) { + if (out_cat(p, left, "[%d:0] ", decl->width - 1)) return 1; + } + if (out_cat(p, left, "%s = %s;\n", decl->name, rhs)) return 1; + return 0; +} + +static int print_inputs_short(char **p, size_t *left, decl_t *arr, int n) { + for (int i = 0; i < n; ) { + int w = arr[i].width; + int sg = arr[i].is_signed; + if (out_cat(p, left, " input ")) return 1; + if (sg) { + if (out_cat(p, left, "signed ")) return 1; + } + if (w > 1) { + if (out_cat(p, left, "[%d:0] ", w - 1)) return 1; + } + int j = i; + while (j < n && arr[j].width == w && arr[j].is_signed == sg) { + if (out_cat(p, left, "%s%s", j == i ? "" : ", ", arr[j].name)) return 1; + ++j; + } + if (out_cat(p, left, ";\n")) return 1; + i = j; + } + return 0; +} + +static decl_t *find_decl_by_name(decl_t *arr, int n, const char *name) { + for (int i = 0; i < n; ++i) { + if (!strcmp(arr[i].name, name)) + return &arr[i]; + } + return NULL; +} + +static int has_assignment(const mv_ctx *ctx, const char *name) { + for (int i = 0; i < ctx->na; ++i) + if (!strcmp(ctx->assigns[i].lhs, name)) + return 1; + return 0; +} + // Add spaces around every alphanumeric/underscore sequence for readability. // Example: "a*b+16'b0" -> " a * b + 16 ' b0 " static void format_rhs_readable(const char *in, char *out, size_t cap) { @@ -206,6 +267,20 @@ static void format_rhs_readable(const char *in, char *out, size_t cap) { if (o < cap) out[o] = 0; else if (cap) out[cap-1] = 0; } +static void trim_spaces(char *s) { + if (!s) return; + char *start = s; + while (*start && isspace((unsigned char)*start)) + ++start; + char *end = start + strlen(start); + while (end > start && isspace((unsigned char)*(end - 1))) + --end; + size_t len = (size_t)(end - start); + if (start != s) + memmove(s, start, len); + s[len] = 0; +} + // ----------------------------------------------------------------------------- // Parsing helpers that quote offending clauses // ----------------------------------------------------------------------------- @@ -380,7 +455,7 @@ lhs_done:; // Translate a raw mini-Verilog string 'input' into standard Verilog. // The function strips whitespace internally, parses, and writes into 'out' (cap bytes). // Returns 0 on success, 1 on error. Errors are printed (no exit()). -int miniver_translate(const char *input, char *out, size_t cap) { +int miniver_translate(const char *input, char *out, size_t cap, int fShort) { if (!input || !out || cap == 0) { printf("Invalid arguments.\n"); return 1; @@ -458,15 +533,47 @@ int miniver_translate(const char *input, char *out, size_t cap) { free(ctx); return 1; } - if (print_decl_to_buf(&p, &left, "input", ctx->inputs, ctx->ni)) { free(ctx); return 1; } - if (print_decl_to_buf(&p, &left, "output", ctx->outputs, ctx->no)) { free(ctx); return 1; } - if (print_decl_to_buf(&p, &left, "wire", ctx->wires, ctx->nw)) { free(ctx); return 1; } + if (!fShort) { + if (print_decl_to_buf(&p, &left, "input", ctx->inputs, ctx->ni)) { free(ctx); return 1; } + if (print_decl_to_buf(&p, &left, "output", ctx->outputs, ctx->no)) { free(ctx); return 1; } + if (print_decl_to_buf(&p, &left, "wire", ctx->wires, ctx->nw)) { free(ctx); return 1; } for (int i = 0; i < ctx->na; ++i) { - char rhs_sp[8192]; - format_rhs_readable(ctx->assigns[i].rhs, rhs_sp, sizeof(rhs_sp)); - if (out_cat(&p, &left, " assign %s = %s;\n", ctx->assigns[i].lhs, rhs_sp)) { - free(ctx); return 1; + char rhs_sp[8192]; + format_rhs_readable(ctx->assigns[i].rhs, rhs_sp, sizeof(rhs_sp)); + if (out_cat(&p, &left, " assign %s = %s;\n", ctx->assigns[i].lhs, rhs_sp)) { + free(ctx); return 1; + } + } + } else { + if (print_inputs_short(&p, &left, ctx->inputs, ctx->ni)) { free(ctx); return 1; } + for (int i = 0; i < ctx->nw; ++i) { + if (has_assignment(ctx, ctx->wires[i].name)) + continue; + if (print_decl_single(&p, &left, "wire", &ctx->wires[i])) { + free(ctx); return 1; + } + } + for (int i = 0; i < ctx->na; ++i) { + char rhs_sp[8192]; + format_rhs_readable(ctx->assigns[i].rhs, rhs_sp, sizeof(rhs_sp)); + trim_spaces(rhs_sp); + const char *kw = "wire"; + decl_t *decl = find_decl_by_name(ctx->outputs, ctx->no, ctx->assigns[i].lhs); + if (decl) { + kw = "output"; + } else { + decl = find_decl_by_name(ctx->wires, ctx->nw, ctx->assigns[i].lhs); + } + if (decl) { + if (print_decl_with_assign(&p, &left, kw, decl, rhs_sp)) { + free(ctx); return 1; + } + } else { + if (out_cat(&p, &left, " assign %s = %s;\n", ctx->assigns[i].lhs, rhs_sp)) { + free(ctx); return 1; + } + } } } if (out_cat(&p, &left, "endmodule\n")) { @@ -506,7 +613,7 @@ int main(int argc, char **argv) { } char out[10240]; - int rc = miniver_translate(in, out, sizeof(out)); + int rc = miniver_translate(in, out, sizeof(out), 0); if (!rc) { printf("%s", out); } @@ -520,4 +627,3 @@ int main(int argc, char **argv) { ABC_NAMESPACE_IMPL_END - From 91d2f3d7e8850a1d466a4d9397c5819f688c084e Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 06:55:24 -0800 Subject: [PATCH 09/38] Changes to "lutexact". --- src/base/abci/abc.c | 6 +++++- src/sat/bmc/bmcMaj.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index d638a6898..899058545 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10826,11 +10826,15 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Truth table should be given on the command line.\n" ); return 1; } + if ( pPars->nVars == 0 && pPars->pTtStr ) + pPars->nVars = 2 + Abc_Base2Log((int)strlen(pPars->pTtStr)); if ( pPars->pTtStr && (1 << (pPars->nVars-2)) != (int)strlen(pPars->pTtStr) ) { Abc_Print( -1, "Truth table is expected to have %d hex digits (instead of %d).\n", (1 << (pPars->nVars-2)), strlen(pPars->pTtStr) ); return 1; } + if ( pPars->nVars == 0 && pPars->pSymStr ) + pPars->nVars = (int)strlen(pPars->pSymStr) - 1; if ( pPars->pSymStr && pPars->nVars+1 != strlen(pPars->pSymStr) ) { Abc_Print( -1, "The char string of the %d-variable symmetric function should have %d zeros and ones (instead of %d).\n", pPars->nVars, pPars->nVars+1, strlen(pPars->pSymStr) ); @@ -10843,7 +10847,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) } if ( pPars->nVars > 12 ) { - Abc_Print( -1, "Function should not have more than 10 inputs.\n" ); + Abc_Print( -1, "Function should not have more than 12 inputs.\n" ); return 1; } if ( pPars->nLutSize > 6 ) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index 780271c47..ddb3be453 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1291,7 +1291,7 @@ static void Exa3_ManPrintSolution( Exa3_Man_t * p, int fCompl ) for ( i = p->nObjs - 1; i >= p->nVars; i-- ) { int Val, iVarStart = 1 + p->LutMask*(i - p->nVars); - printf( "%02d = %d\'b", i, 1 << p->nLutSize ); + printf( "%c = %d\'b", 'A'+i-p->nVars, 1 << p->nLutSize ); for ( k = p->LutMask - 1; k >= 0; k-- ) { Val = bmcg_sat_solver_read_cex_varvalue(p->pSat, iVarStart+k); @@ -1311,7 +1311,7 @@ static void Exa3_ManPrintSolution( Exa3_Man_t * p, int fCompl ) if ( iVar >= 0 && iVar < p->nVars ) printf( " %c", 'a'+iVar ); else - printf( " %02d", iVar ); + printf( " %c", 'A'+iVar-p->nVars ); } printf( " )\n" ); } @@ -1332,7 +1332,7 @@ static void Exa3_ManDumpBlif( Exa3_Man_t * p, int fCompl ) { int i, k, b, iVar; char pFileName[1000]; - char * pStr = Abc_UtilStrsav(p->pPars->pTtStr); + char * pStr = Abc_UtilStrsav(p->pPars->pSymStr ? p->pPars->pSymStr : p->pPars->pTtStr); if ( strlen(pStr) > 16 ) { pStr[16] = '_'; pStr[17] = '\0'; From 3d281a1907d366a30a2a39f7bff8794ef806afe6 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 13:24:02 -0800 Subject: [PATCH 10/38] Adding support for Cadical in "lutexact". --- src/base/abci/abc.c | 76 +++- src/sat/bmc/bmc.h | 3 + src/sat/bmc/bmcMaj.c | 48 +- src/sat/bmc/bmcMaj7.c | 767 ++++++++++++++++++++++++++++++++ src/sat/bmc/module.make | 1 + src/sat/cadical/cadicalSolver.c | 9 +- 6 files changed, 869 insertions(+), 35 deletions(-) create mode 100644 src/sat/bmc/bmcMaj7.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 899058545..eb3c24f06 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -7785,6 +7785,7 @@ int Abc_CommandRunScript( Abc_Frame_t * pAbc, int argc, char ** argv ) pSpot = strstr( pScript, "*" ); if ( pSpot == NULL ) { + abctime clkTotal = Abc_Clock(); for ( c = 0; c < nIters; c++ ) { if ( fVerbose ) @@ -7794,27 +7795,33 @@ int Abc_CommandRunScript( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } - printf( "Finished iterating script %d times.\n", nIters ); + printf( "Finished iterating script %d times. ", nIters ); + Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); return 0; } - assert( *pSpot == '*' ); - for ( c = 0; c < nIters; c++ ) + else { - char pCommLine[1000] = {0}; - char pNumber[10] = {0}; - sprintf( pNumber, "%d", fReverse ? nBeg - c*nAdd : nBeg + c*nAdd ); - strcpy( pCommLine, pScript ); - pCommLine[(int)(pSpot - pScript)] = 0; - strcat( pCommLine, pNumber ); - strcat( pCommLine, pSpot+1 ); - if ( fVerbose ) - printf( "ITERATION %3d : %s\n", c, pCommLine ); - if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pCommLine) ) { - Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pCommLine ); - goto usage; - } + abctime clkTotal = Abc_Clock(); + assert( *pSpot == '*' ); + for ( c = 0; c < nIters; c++ ) + { + char pCommLine[1000] = {0}; + char pNumber[10] = {0}; + sprintf( pNumber, "%d", fReverse ? nBeg - c*nAdd : nBeg + c*nAdd ); + strcpy( pCommLine, pScript ); + pCommLine[(int)(pSpot - pScript)] = 0; + strcat( pCommLine, pNumber ); + strcat( pCommLine, pSpot+1 ); + if ( fVerbose ) + printf( "ITERATION %3d : %s\n", c, pCommLine ); + if ( Cmd_CommandExecute(Abc_FrameGetGlobalFrame(), pCommLine) ) { + Abc_Print( 1, "Something did not work out with the command \"%s\".\n", pCommLine ); + goto usage; + } + } + printf( "Finished iterating script %d times. ", nIters ); + Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); } - printf( "Finished iterating script %d times.\n", nIters ); return 0; usage: @@ -10689,6 +10696,7 @@ usage: ***********************************************************************/ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) { + extern int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesis2( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesisRand( Bmc_EsPar_t * pPars ); @@ -10697,7 +10705,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYiaorfgdvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYPiaorfgcdsvh" ) ) != EOF ) { switch ( c ) { @@ -10783,6 +10791,15 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) pPars->pSymStr = argv[globalUtilOptind]; globalUtilOptind++; break; + case 'P': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-P\" should be followed by a string.\n" ); + goto usage; + } + pPars->pPermStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'i': pPars->fUseIncr ^= 1; break; @@ -10801,9 +10818,15 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'g': pPars->fGlucose ^= 1; break; + case 'c': + pPars->fCadical ^= 1; + break; case 'd': pPars->fDumpBlif ^= 1; break; + case 's': + pPars->fSilent ^= 1; + break; case 'v': pPars->fVerbose ^= 1; break; @@ -10813,6 +10836,14 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } + if ( pPars->pPermStr && (pPars->nLutSize * pPars->nNodes != (int)strlen(pPars->pPermStr)) ) + { + Abc_Print( -1, "Permutation \"%s\" has %d symbols instead of expected %d = %d * %d symbols (LutSize * nLuts).\n", + pPars->pPermStr, (int)strlen(pPars->pPermStr), pPars->nLutSize * pPars->nNodes, pPars->nLutSize, pPars->nNodes ); + return 1; + } + if ( pPars->pPermStr && !pPars->fLutCascade ) + Abc_Print( 0, "If LUT mapping is not enabled (switch \"-r\"), permutation has not effect.\n" ); if ( argc == globalUtilOptind + 1 ) pPars->pTtStr = argv[globalUtilOptind]; else if ( argc == globalUtilOptind && Abc_FrameReadNtk(pAbc) ) @@ -10861,6 +10892,8 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) } else if ( pPars->fGlucose ) Exa3_ManExactSynthesis( pPars ); + else if ( pPars->fCadical ) + Exa7_ManExactSynthesis( pPars ); else Exa3_ManExactSynthesis2( pPars ); if ( argc == globalUtilOptind && Abc_FrameReadNtk(pAbc) ) @@ -10868,7 +10901,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-iaorfgdvh] \n" ); + Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-P string] [-iaorfgcdsvh] \n" ); Abc_Print( -2, "\t exact synthesis of I-input function using N K-input gates\n" ); Abc_Print( -2, "\t-N : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-M : the number of K-input nodes [default = %d]\n", pPars->nNodes ); @@ -10877,14 +10910,17 @@ usage: Abc_Print( -2, "\t-F : the number of random functions to try [default = unused]\n" ); Abc_Print( -2, "\t-U : the number of positive minterms in the random function [default = unused]\n" ); Abc_Print( -2, "\t-S : the random seed for random function generation with -F [default = %d]\n", pPars->Seed ); - Abc_Print( -2, "\t-Y : charasteristic string of a symmetric function [default = %d]\n", pPars->pSymStr ); + Abc_Print( -2, "\t-Y : charasteristic string of a symmetric function [default = %s]\n", pPars->pSymStr ? pPars->pSymStr : "unused" ); + Abc_Print( -2, "\t-P : variable permutation (for example, \"abcd_aef\" for S44) [default = %s]\n", pPars->pPermStr ? pPars->pPermStr : "unused" ); Abc_Print( -2, "\t-i : toggle using incremental solving [default = %s]\n", pPars->fUseIncr ? "yes" : "no" ); Abc_Print( -2, "\t-a : toggle using only AND-gates when K = 2 [default = %s]\n", pPars->fOnlyAnd ? "yes" : "no" ); Abc_Print( -2, "\t-o : toggle using additional optimizations [default = %s]\n", pPars->fFewerVars ? "yes" : "no" ); Abc_Print( -2, "\t-r : toggle synthesizing a single-rail cascade [default = %s]\n", pPars->fLutCascade ? "yes" : "no" ); Abc_Print( -2, "\t-f : toggle fixing LUT inputs in cascade mapping [default = %s]\n", pPars->fLutInFixed ? "yes" : "no" ); Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", pPars->fGlucose ? "yes" : "no" ); + Abc_Print( -2, "\t-c : toggle using CaDiCal 2.2.0-rc1 by Armin Biere [default = %s]\n", pPars->fCadical ? "yes" : "no" ); Abc_Print( -2, "\t-d : toggle dumping decomposed networks into BLIF files [default = %s]\n", pPars->fDumpBlif ? "yes" : "no" ); + Abc_Print( -2, "\t-s : toggle silent computation (no messages, except when a solution is found) [default = %s]\n", pPars->fSilent ? "yes" : "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", pPars->fVerbose ? "yes" : "no" ); Abc_Print( -2, "\t-h : print the command usage\n" ); Abc_Print( -2, "\t : truth table in hex notation\n" ); diff --git a/src/sat/bmc/bmc.h b/src/sat/bmc/bmc.h index 3efe5a76d..daf99c4e6 100644 --- a/src/sat/bmc/bmc.h +++ b/src/sat/bmc/bmc.h @@ -57,6 +57,7 @@ struct Bmc_EsPar_t_ int fDynConstr; int fDumpCnf; int fGlucose; + int fCadical; int fCard; int fOrderNodes; int fEnumSols; @@ -71,8 +72,10 @@ struct Bmc_EsPar_t_ int Seed; int fDumpBlif; int fVerbose; + int fSilent; char * pTtStr; char * pSymStr; + char * pPermStr; char * pGuide; }; diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index ddb3be453..b1e0309bb 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1093,6 +1093,18 @@ Vec_Wec_t * Exa3_ChooseInputVars( int nVars, int nLuts, int nLutSize ) assert( 0 ); return NULL; } +Vec_Wec_t * Exa3_ChooseInputVars2( int nVars, int nLuts, int nLutSize, char * pPermStr ) +{ + Vec_Wec_t * p = Vec_WecStart( nLuts ); + Vec_Int_t * vLevel; int i, Pos = 0; + assert( nLuts * nLutSize == (int)strlen(pPermStr) ); + Vec_WecForEachLevel( p, vLevel, i ) { + for ( int k = 0; k < nLutSize; k++, Pos++ ) + if ( pPermStr[Pos] != '_' ) + Vec_IntPush( vLevel, pPermStr[Pos] == '*' ? -1 : (int)(pPermStr[Pos]-'a') ); + } + return p; +} /**Function************************************************************* @@ -1155,16 +1167,20 @@ static int Exa3_ManMarkup( Exa3_Man_t * p ) } } } - printf( "The number of parameter variables = %d.\n", p->iVar ); - if ( p->pPars->fLutCascade && p->pPars->fLutInFixed ) { - p->vInVars = Exa3_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize ); - if ( 1 ) { + if ( !p->pPars->fSilent ) printf( "The number of parameter variables = %d.\n", p->iVar ); + if ( p->pPars->fLutCascade && (p->pPars->fLutInFixed || p->pPars->pPermStr) ) { + if ( p->pPars->pPermStr ) + p->vInVars = Exa3_ChooseInputVars2( p->nVars, p->nNodes, p->nLutSize, p->pPars->pPermStr ); + else + p->vInVars = Exa3_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize ); + if ( !p->pPars->fSilent ) { Vec_Int_t * vLevel; int i, Var; - printf( "Using fixed input assignment:\n" ); + printf( "Using fixed input assignment %s%s:\n", + p->pPars->pPermStr ? "provided by the user " : "generated randomly", p->pPars->pPermStr ? p->pPars->pPermStr : "" ); Vec_WecForEachLevelReverse( p->vInVars, vLevel, i ) { - printf( "%02d : ", p->nVars+i ); + printf( "%c : ", 'A'+p->nVars+i-p->nVars ); Vec_IntForEachEntry( vLevel, Var, k ) - printf( "%c ", 'a'+Var ); + printf( "%c ", Var < 0 ? '*' : 'a'+Var ); printf( "\n" ); } } @@ -1374,7 +1390,7 @@ static void Exa3_ManDumpBlif( Exa3_Man_t * p, int fCompl ) } fprintf( pFile, ".end\n\n" ); fclose( pFile ); - printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + if ( !p->pPars->fSilent ) printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); ABC_FREE( pStr ); } @@ -1472,10 +1488,16 @@ static int Exa3_ManAddCnfStart( Exa3_Man_t * p, int fOnlyAnd ) } if ( p->vInVars ) { Vec_Int_t * vLevel; int Var; + //Vec_WecPrint( p->vInVars, 0 ); Vec_WecForEachLevel( p->vInVars, vLevel, i ) { assert( Vec_IntSize(vLevel) > 0 ); Vec_IntForEachEntry( vLevel, Var, k ) { + if ( Var < 0 ) continue; + if ( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var] == 0 ) { + printf( "Skipping variable %d in place %d because it cannot be constrained.\n", Var, k ); + continue; + } pLits[0] = Abc_Var2Lit( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var], 0 ); assert(pLits[0]); if ( !bmcg_sat_solver_addclause( p->pSat, pLits, 1 ) ) return 0; @@ -1616,7 +1638,7 @@ int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ) word * pFun = Abc_TtSymFunGenerate( pPars->pSymStr, pPars->nVars ); pPars->pTtStr = ABC_CALLOC( char, pPars->nVars > 2 ? (1 << (pPars->nVars-2)) + 1 : 2 ); Extra_PrintHexadecimalString( pPars->pTtStr, (unsigned *)pFun, pPars->nVars ); - printf( "Generated symmetric function: %s\n", pPars->pTtStr ); + if ( !pPars->fSilent ) printf( "Generated symmetric function: %s\n", pPars->pTtStr ); ABC_FREE( pFun ); } if ( pPars->pTtStr ) @@ -1628,7 +1650,7 @@ int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ) if ( pTruth[0] & 1 ) { fCompl = 1; Abc_TtNot( pTruth, p->nWords ); } status = Exa3_ManAddCnfStart( p, pPars->fOnlyAnd ); assert( status ); - printf( "Running exact synthesis for %d-input function with %d %d-input LUTs...\n", p->nVars, p->nNodes, p->nLutSize ); + if ( !pPars->fSilent ) printf( "Running exact synthesis for %d-input function with %d %d-input LUTs...\n", p->nVars, p->nNodes, p->nLutSize ); if ( pPars->fUseIncr ) { bmcg_sat_solver_set_nvars( p->pSat, p->iVar + p->nNodes*(1 << p->nVars) ); @@ -1652,10 +1674,10 @@ int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ) Exa3_ManPrintSolution( p, fCompl ), Res = 1; else if ( status == GLUCOSE_UNDEC ) printf( "The solver timed out after %d sec.\n", pPars->RuntimeLim ); - else + else if ( !p->pPars->fSilent ) printf( "The problem has no solution.\n" ), Res = 2; - printf( "Added = %d. Tried = %d. ", p->nUsed[1], p->nUsed[0] ); - Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); + if ( !pPars->fSilent && (p->nUsed[0] || p->nUsed[1]) ) printf( "Added = %d. Tried = %d. ", p->nUsed[1], p->nUsed[0] ); + if ( !pPars->fSilent ) Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); if ( iMint == -1 && pPars->fDumpBlif ) Exa3_ManDumpBlif( p, fCompl ); if ( pPars->pSymStr ) diff --git a/src/sat/bmc/bmcMaj7.c b/src/sat/bmc/bmcMaj7.c new file mode 100644 index 000000000..9fd6da2fd --- /dev/null +++ b/src/sat/bmc/bmcMaj7.c @@ -0,0 +1,767 @@ +/**CFile**************************************************************** + + FileName [bmcMaj.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [SAT-based bounded model checking.] + + Synopsis [Exact synthesis with majority gates.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - October 1, 2017.] + + Revision [$Id: bmcMaj.c,v 1.00 2017/10/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bmc.h" +#include "misc/extra/extra.h" +#include "misc/util/utilTruth.h" +#include "sat/cadical/cadicalSolver.h" +#include "sat/cadical/ccadical.h" +#include "aig/miniaig/miniaig.h" +#include "base/io/ioResub.h" +#include "base/main/main.h" +#include "base/cmd/cmd.h" + +#define CADICAL_UNSAT -1 +#define CADICAL_SAT 1 +#define CADICAL_UNDEC 0 + +ABC_NAMESPACE_IMPL_START + +static inline void Exa7_CadicalSetRuntimeLimit( cadical_solver * pSat, int nSeconds ) +{ + if ( pSat == NULL || nSeconds <= 0 ) + return; + ccadical_limit( (CCaDiCaL *)pSat->p, "seconds", nSeconds ); +} + + +#ifdef WIN32 +#include +#define unlink _unlink +#else +#include +#endif +#include + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define MAJ_NOBJS 64 // Const0 + Const1 + nVars + nNodes + +typedef struct Exa7_Man_t_ Exa7_Man_t; +struct Exa7_Man_t_ +{ + Bmc_EsPar_t * pPars; // parameters + int nVars; // inputs + int nNodes; // internal nodes + int nLutSize; // lut size + int LutMask; // lut mask + int nObjs; // total objects (nVars inputs + nNodes internal nodes) + int nWords; // the truth table size in 64-bit words + int iVar; // the next available SAT variable + word * pTruth; // truth table + Vec_Wrd_t * vInfo; // nVars + nNodes + 1 + Vec_Bit_t * vUsed2; // bit masks + Vec_Bit_t * vUsed3; // bit masks + int VarMarks[MAJ_NOBJS][6][MAJ_NOBJS]; // variable marks + int VarVals[MAJ_NOBJS]; // values of the first nVars variables + Vec_Wec_t * vOutLits; // output vars + Vec_Wec_t * vInVars; // input vars + cadical_solver * pSat; // SAT solver + int nVarAlloc; // total vars reserved in the solver + int nUsed[2]; +}; + +static inline word * Exa7_ManTruth( Exa7_Man_t * p, int v ) { return Vec_WrdEntryP( p->vInfo, p->nWords * v ); } + +static inline int Exa7_ManIsUsed2( Exa7_Man_t * p, int m, int n, int i, int j ) +{ + int Pos = ((m * p->pPars->nNodes + n - p->pPars->nVars) * p->nObjs + i) * p->nObjs + j; + p->nUsed[0]++; + assert( i < n && j < n && i < j ); + if ( Vec_BitEntry(p->vUsed2, Pos) ) + return 1; + p->nUsed[1]++; + Vec_BitWriteEntry( p->vUsed2, Pos, 1 ); + return 0; +} + +static inline int Exa7_ManIsUsed3( Exa7_Man_t * p, int m, int n, int i, int j, int k ) +{ + int Pos = (((m * p->pPars->nNodes + n - p->pPars->nVars) * p->nObjs + i) * p->nObjs + j) * p->nObjs + k; + p->nUsed[0]++; + assert( i < n && j < n && k < n && i < j && j < k ); + if ( Vec_BitEntry(p->vUsed3, Pos) ) + return 1; + p->nUsed[1]++; + Vec_BitWriteEntry( p->vUsed3, Pos, 1 ); + return 0; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Wec_t * Exa7_ChooseInputVars_int( int nVars, int nLuts, int nLutSize ) +{ + Vec_Wec_t * p = Vec_WecStart( nLuts ); + Vec_Int_t * vLevel; int i; + Vec_WecForEachLevel( p, vLevel, i ) { + do { + int iVar = (Abc_Random(0) ^ Abc_Random(0) ^ Abc_Random(0)) % nVars; + Vec_IntPushUniqueOrder( vLevel, iVar ); + } + while ( Vec_IntSize(vLevel) < nLutSize-(int)(i>0) ); + } + return p; +} +Vec_Int_t * Exa7_CountInputVars( int nVars, Vec_Wec_t * p ) +{ + Vec_Int_t * vLevel; int i, k, Obj; + Vec_Int_t * vCounts = Vec_IntStart( nVars ); + Vec_WecForEachLevel( p, vLevel, i ) + Vec_IntForEachEntry( vLevel, Obj, k ) + Vec_IntAddToEntry( vCounts, Obj, 1 ); + return vCounts; +} +Vec_Wec_t * Exa7_ChooseInputVars( int nVars, int nLuts, int nLutSize ) +{ + for ( int i = 0; i < 1000; i++ ) { + Vec_Wec_t * p = Exa7_ChooseInputVars_int( nVars, nLuts, nLutSize ); + Vec_Int_t * q = Exa7_CountInputVars( nVars, p ); + int RetValue = Vec_IntFind( q, 0 ); + Vec_IntFree( q ); + if ( RetValue == -1 ) + return p; + Vec_WecFree( p ); + } + assert( 0 ); + return NULL; +} +Vec_Wec_t * Exa7_ChooseInputVars2( int nVars, int nLuts, int nLutSize, char * pPermStr ) +{ + Vec_Wec_t * p = Vec_WecStart( nLuts ); + Vec_Int_t * vLevel; int i, Pos = 0; + assert( nLuts * nLutSize == (int)strlen(pPermStr) ); + Vec_WecForEachLevel( p, vLevel, i ) { + for ( int k = 0; k < nLutSize; k++, Pos++ ) + if ( pPermStr[Pos] != '_' ) + Vec_IntPush( vLevel, pPermStr[Pos] == '*' ? -1 : (int)(pPermStr[Pos]-'a') ); + } + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Vec_Wrd_t * Exa7_ManTruthTables( Exa7_Man_t * p ) +{ + Vec_Wrd_t * vInfo = p->vInfo = Vec_WrdStart( p->nWords * (p->nObjs+1) ); int i; + for ( i = 0; i < p->nVars; i++ ) + Abc_TtIthVar( Exa7_ManTruth(p, i), i, p->nVars ); + //Dau_DsdPrintFromTruth( Exa7_ManTruth(p, p->nObjs), p->nVars ); + return vInfo; +} +static int Exa7_ManVarReserve( Exa7_Man_t * p ) +{ + int nMintMax = 1 << p->nVars; + int nVarsPerMint = p->pPars->fUseIncr ? p->nNodes : (p->nLutSize + 1) * p->nNodes; + int64_t nTotal = (int64_t)p->iVar + (int64_t)nVarsPerMint * nMintMax; + if ( nTotal > INT_MAX ) + nTotal = INT_MAX; + return (int)nTotal; +} +static int Exa7_ManMarkup( Exa7_Man_t * p ) +{ + int i, k, j; + assert( p->nObjs <= MAJ_NOBJS ); + // assign functionality variables + p->iVar = 1 + p->LutMask * p->nNodes; + // assign connectivity variables + for ( i = p->nVars; i < p->nObjs; i++ ) + { + if ( p->pPars->fLutCascade ) + { + if ( i > p->nVars ) + { + Vec_WecPush( p->vOutLits, i-1, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][0][i-1] = p->iVar++; + } + for ( k = (int)(i > p->nVars); k < p->nLutSize; k++ ) + { + for ( j = 0; j < p->nVars - k + (int)(i > p->nVars); j++ ) + { + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + } + } + continue; + } + for ( k = 0; k < p->nLutSize; k++ ) + { + if ( p->pPars->fFewerVars && i == p->nObjs - 1 && k == 0 ) + { + j = p->nObjs - 2; + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + continue; + } + for ( j = p->pPars->fFewerVars ? p->nLutSize - 1 - k : 0; j < i - k; j++ ) + { + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + } + } + } + if ( !p->pPars->fSilent ) printf( "The number of parameter variables = %d.\n", p->iVar ); + if ( p->pPars->fLutCascade && (p->pPars->fLutInFixed || p->pPars->pPermStr) ) { + if ( p->pPars->pPermStr ) + p->vInVars = Exa7_ChooseInputVars2( p->nVars, p->nNodes, p->nLutSize, p->pPars->pPermStr ); + else + p->vInVars = Exa7_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize ); + if ( !p->pPars->fSilent ) { + Vec_Int_t * vLevel; int i, Var; + printf( "Using fixed input assignment %s%s:\n", + p->pPars->pPermStr ? "provided by the user " : "generated randomly", p->pPars->pPermStr ? p->pPars->pPermStr : "" ); + Vec_WecForEachLevelReverse( p->vInVars, vLevel, i ) { + printf( "%c : ", 'A'+p->nVars+i-p->nVars ); + Vec_IntForEachEntry( vLevel, Var, k ) + printf( "%c ", Var < 0 ? '*' : 'a'+Var ); + printf( "\n" ); + } + } + } + return p->iVar; + // printout + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + printf( " Node %2d\n", i ); + for ( j = 0; j < p->nObjs; j++ ) + { + printf( "Fanin %2d : ", j ); + for ( k = 0; k < p->nLutSize; k++ ) + printf( "%3d ", p->VarMarks[i][k][j] ); + printf( "\n" ); + } + } + return p->iVar; +} +static Exa7_Man_t * Exa7_ManAlloc( Bmc_EsPar_t * pPars, word * pTruth ) +{ + Exa7_Man_t * p = ABC_CALLOC( Exa7_Man_t, 1 ); + p->pPars = pPars; + p->nVars = pPars->nVars; + p->nNodes = pPars->nNodes; + p->nLutSize = pPars->nLutSize; + p->LutMask = (1 << pPars->nLutSize) - 1; + p->nObjs = pPars->nVars + pPars->nNodes; + p->nWords = Abc_TtWordNum(pPars->nVars); + p->pTruth = pTruth; + p->vOutLits = Vec_WecStart( p->nObjs ); + p->iVar = Exa7_ManMarkup( p ); + p->vInfo = Exa7_ManTruthTables( p ); + if ( p->pPars->nLutSize == 2 ) + p->vUsed2 = Vec_BitStart( (1 << p->pPars->nVars) * p->pPars->nNodes * p->nObjs * p->nObjs ); + else if ( p->pPars->nLutSize == 3 ) + p->vUsed3 = Vec_BitStart( (1 << p->pPars->nVars) * p->pPars->nNodes * p->nObjs * p->nObjs * p->nObjs ); + p->pSat = cadical_solver_new(); + p->nVarAlloc = Exa7_ManVarReserve( p ); + assert( p->nVarAlloc >= p->iVar ); + cadical_solver_setnvars( p->pSat, p->nVarAlloc ); + if ( pPars->RuntimeLim ) + Exa7_CadicalSetRuntimeLimit( p->pSat, pPars->RuntimeLim ); + return p; +} +static void Exa7_ManFree( Exa7_Man_t * p ) +{ + cadical_solver_delete( p->pSat ); + Vec_WrdFree( p->vInfo ); + Vec_BitFreeP( &p->vUsed2 ); + Vec_BitFreeP( &p->vUsed3 ); + Vec_WecFree( p->vOutLits ); + Vec_WecFreeP( &p->vInVars ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Exa7_ManFindFanin( Exa7_Man_t * p, int i, int k ) +{ + int j, Count = 0, iVar = -1; + for ( j = 0; j < p->nObjs; j++ ) + if ( p->VarMarks[i][k][j] && cadical_solver_get_var_value(p->pSat, p->VarMarks[i][k][j]) ) + { + iVar = j; + Count++; + } + assert( Count == 1 ); + return iVar; +} +static inline int Exa7_ManEval( Exa7_Man_t * p ) +{ + static int Flag = 0; + int i, k, j, iMint; word * pFanins[6]; + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + pFanins[k] = Exa7_ManTruth( p, Exa7_ManFindFanin(p, i, k) ); + Abc_TtConst0( Exa7_ManTruth(p, i), p->nWords ); + for ( k = 1; k <= p->LutMask; k++ ) + { + if ( !cadical_solver_get_var_value(p->pSat, iVarStart+k-1) ) + continue; +// Abc_TtAndCompl( Exa7_ManTruth(p, p->nObjs), pFanins[0], !(k&1), pFanins[1], !(k>>1), p->nWords ); + Abc_TtConst1( Exa7_ManTruth(p, p->nObjs), p->nWords ); + for ( j = 0; j < p->nLutSize; j++ ) + Abc_TtAndCompl( Exa7_ManTruth(p, p->nObjs), Exa7_ManTruth(p, p->nObjs), 0, pFanins[j], !((k >> j) & 1), p->nWords ); + Abc_TtOr( Exa7_ManTruth(p, i), Exa7_ManTruth(p, i), Exa7_ManTruth(p, p->nObjs), p->nWords ); + } + } + if ( Flag && p->nVars >= 6 ) + iMint = Abc_TtFindLastDiffBit( Exa7_ManTruth(p, p->nObjs-1), p->pTruth, p->nVars ); + else + iMint = Abc_TtFindFirstDiffBit( Exa7_ManTruth(p, p->nObjs-1), p->pTruth, p->nVars ); + //Flag ^= 1; + assert( iMint < (1 << p->nVars) ); + return iMint; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Exa7_ManPrintSolution( Exa7_Man_t * p, int fCompl ) +{ + int i, k, iVar; + printf( "Realization of given %d-input function using %d %d-input LUTs:\n", p->nVars, p->nNodes, p->nLutSize ); + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + int Val, iVarStart = 1 + p->LutMask*(i - p->nVars); + printf( "%c = %d\'b", 'A'+i-p->nVars, 1 << p->nLutSize ); + for ( k = p->LutMask - 1; k >= 0; k-- ) + { + Val = cadical_solver_get_var_value(p->pSat, iVarStart+k); + if ( i == p->nObjs - 1 && fCompl ) + printf( "%d", !Val ); + else + printf( "%d", Val ); + } + if ( i == p->nObjs - 1 && fCompl ) + printf( "1(" ); + else + printf( "0(" ); + + for ( k = p->nLutSize - 1; k >= 0; k-- ) + { + iVar = Exa7_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + printf( " %c", 'a'+iVar ); + else + printf( " %c", 'A'+iVar-p->nVars ); + } + printf( " )\n" ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Exa7_ManDumpBlif( Exa7_Man_t * p, int fCompl ) +{ + int i, k, b, iVar; + char pFileName[1000]; + char * pStr = Abc_UtilStrsav(p->pPars->pSymStr ? p->pPars->pSymStr : p->pPars->pTtStr); + if ( strlen(pStr) > 16 ) { + pStr[16] = '_'; + pStr[17] = '\0'; + } + sprintf( pFileName, "%s.blif", pStr ); + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) return; + fprintf( pFile, "# Realization of given %d-input function using %d %d-input LUTs synthesized by ABC on %s\n", p->nVars, p->nNodes, p->nLutSize, Extra_TimeStamp() ); + fprintf( pFile, ".model %s\n", pStr ); + fprintf( pFile, ".inputs" ); + for ( k = 0; k < p->nVars; k++ ) + fprintf( pFile, " %c", 'a'+k ); + fprintf( pFile, "\n.outputs F\n" ); + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + fprintf( pFile, ".names" ); + for ( k = 0; k < p->nLutSize; k++ ) + { + iVar = Exa7_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + fprintf( pFile, " %c", 'a'+iVar ); + else + fprintf( pFile, " %02d", iVar ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " F\n" ); + else + fprintf( pFile, " %02d\n", i ); + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->LutMask; k++ ) + { + int Val = cadical_solver_get_var_value(p->pSat, iVarStart+k); + if ( Val == 0 ) + continue; + for ( b = 0; b < p->nLutSize; b++ ) + fprintf( pFile, "%d", ((k+1) >> b) & 1 ); + fprintf( pFile, " %d\n", i != p->nObjs - 1 || !fCompl ); + } + } + fprintf( pFile, ".end\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + ABC_FREE( pStr ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Exa7_ManAddCnfStart( Exa7_Man_t * p, int fOnlyAnd ) +{ + int pLits[MAJ_NOBJS], pLits2[2], i, j, k, n, m; + // input constraints + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + { + int nLits = 0; + for ( j = 0; j < p->nObjs; j++ ) + if ( p->VarMarks[i][k][j] ) + pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][k][j], 0 ); + assert( nLits > 0 ); + // input uniqueness + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + nLits ) ) + return 0; + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + { + pLits2[0] = Abc_LitNot(pLits[n]); + pLits2[1] = Abc_LitNot(pLits[m]); + if ( !cadical_solver_addclause( p->pSat, pLits2, pLits2 + 2 ) ) + return 0; + } + if ( k == p->nLutSize - 1 ) + break; + // symmetry breaking + for ( j = 0; j < p->nObjs; j++ ) if ( p->VarMarks[i][k][j] ) + for ( n = j; n < p->nObjs; n++ ) if ( p->VarMarks[i][k+1][n] ) + { + pLits2[0] = Abc_Var2Lit( p->VarMarks[i][k][j], 1 ); + pLits2[1] = Abc_Var2Lit( p->VarMarks[i][k+1][n], 1 ); + if ( !cadical_solver_addclause( p->pSat, pLits2, pLits2 + 2 ) ) + return 0; + } + } +//#ifdef USE_NODE_ORDER + // node ordering + if ( p->pPars->fOrderNodes ) + { + for ( j = p->nVars; j < i; j++ ) + for ( n = 0; n < p->nObjs; n++ ) if ( p->VarMarks[i][0][n] ) + for ( m = n+1; m < p->nObjs; m++ ) if ( p->VarMarks[j][0][m] ) + { + pLits2[0] = Abc_Var2Lit( p->VarMarks[i][0][n], 1 ); + pLits2[1] = Abc_Var2Lit( p->VarMarks[j][0][m], 1 ); + if ( !cadical_solver_addclause( p->pSat, pLits2, pLits2 + 2 ) ) + return 0; + } + } +//#endif + if ( p->nLutSize != 2 ) + continue; + // two-input functions + for ( k = 0; k < 3; k++ ) + { + pLits[0] = Abc_Var2Lit( iVarStart, k==1 ); + pLits[1] = Abc_Var2Lit( iVarStart+1, k==2 ); + pLits[2] = Abc_Var2Lit( iVarStart+2, k!=0 ); + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + 3 ) ) + return 0; + } + if ( fOnlyAnd ) + { + pLits[0] = Abc_Var2Lit( iVarStart, 1 ); + pLits[1] = Abc_Var2Lit( iVarStart+1, 1 ); + pLits[2] = Abc_Var2Lit( iVarStart+2, 0 ); + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + 3 ) ) + return 0; + } + } + // outputs should be used + for ( i = 0; i < p->nObjs - 1; i++ ) + { + Vec_Int_t * vArray = Vec_WecEntry(p->vOutLits, i); + int * pArray = Vec_IntArray( vArray ); + int nArrayLits = Vec_IntSize( vArray ); + assert( nArrayLits > 0 ); + if ( !cadical_solver_addclause( p->pSat, pArray, pArray + nArrayLits ) ) + return 0; + } + if ( p->vInVars ) { + Vec_Int_t * vLevel; int Var; + //Vec_WecPrint( p->vInVars, 0 ); + Vec_WecForEachLevel( p->vInVars, vLevel, i ) + { + assert( Vec_IntSize(vLevel) > 0 ); + Vec_IntForEachEntry( vLevel, Var, k ) { + if ( Var < 0 ) continue; + if ( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var] == 0 ) { + printf( "Skipping variable %d in place %d because it cannot be constrained.\n", Var, k ); + continue; + } + pLits[0] = Abc_Var2Lit( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var], 0 ); assert(pLits[0]); + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + 1 ) ) + return 0; + } + } + } + return 1; +} +static int Exa7_ManAddCnf( Exa7_Man_t * p, int iMint ) +{ + // save minterm values + int i, k, n, j, Value = Abc_TtGetBit(p->pTruth, iMint); + for ( i = 0; i < p->nVars; i++ ) + p->VarVals[i] = (iMint >> i) & 1; +// sat_solver_setnvars( p->pSat, p->iVar + (p->nLutSize+1)*p->nNodes ); + cadical_solver_setnvars( p->pSat, p->iVar + (p->nLutSize+1)*p->nNodes ); + //printf( "Adding clauses for minterm %d with value %d.\n", iMint, Value ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + // fanin connectivity + int iVarStart = 1 + p->LutMask*(i - p->nVars); + int iBaseSatVarI = p->iVar + (p->nLutSize+1)*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + { + for ( j = 0; j < p->nObjs; j++ ) if ( p->VarMarks[i][k][j] ) + { + int iBaseSatVarJ = p->iVar + (p->nLutSize+1)*(j - p->nVars); + for ( n = 0; n < 2; n++ ) + { + int pLits[3], nLits = 0; + pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][k][j], 1 ); + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + k, n ); + if ( j >= p->nVars ) + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarJ + p->nLutSize, !n ); + else if ( p->VarVals[j] == n ) + continue; + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + nLits ) ) + return 0; + } + } + } + // node functionality + for ( n = 0; n < 2; n++ ) + { + if ( i == p->nObjs - 1 && n == Value ) + continue; + for ( k = 0; k <= p->LutMask; k++ ) + { + int pLits[16], nLits = 0; + if ( k == 0 && n == 1 ) + continue; + //pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 0, (k&1) ); + //pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 1, (k>>1) ); + //if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 2, !n ); + for ( j = 0; j < p->nLutSize; j++ ) + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + j, (k >> j) & 1 ); + if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + j, !n ); + if ( k > 0 ) pLits[nLits++] = Abc_Var2Lit( iVarStart + k-1, n ); + assert( nLits <= p->nLutSize+2 ); + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + nLits ) ) + return 0; + } + } + } + p->iVar += (p->nLutSize+1)*p->nNodes; + assert( p->iVar <= p->nVarAlloc ); + return 1; +} + +static int Exa7_ManAddCnf2( Exa7_Man_t * p, int iMint ) +{ + int iBaseSatVar = p->iVar + p->nNodes*iMint; + assert( iBaseSatVar + p->nNodes <= p->nVarAlloc ); + // save minterm values + int i, k, n, j, Value = Abc_TtGetBit(p->pTruth, iMint); + for ( i = 0; i < p->nVars; i++ ) + p->VarVals[i] = (iMint >> i) & 1; + //printf( "Adding clauses for minterm %d with value %d.\n", iMint, Value ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { +// int iBaseSatVarI = p->iVar + (p->nLutSize+1)*(i - p->nVars); + int iVarStart = 1 + p->LutMask*(i - p->nVars); + // collect fanin variables + int pFanins[16]; + for ( j = 0; j < p->nLutSize; j++ ) + pFanins[j] = Exa7_ManFindFanin(p, i, j); + // check cache + if ( p->pPars->nLutSize == 2 && Exa7_ManIsUsed2(p, iMint, i, pFanins[1], pFanins[0]) ) + continue; + if ( p->pPars->nLutSize == 3 && Exa7_ManIsUsed3(p, iMint, i, pFanins[2], pFanins[1], pFanins[0]) ) + continue; + // node functionality + for ( n = 0; n < 2; n++ ) + { + if ( i == p->nObjs - 1 && n == Value ) + continue; + for ( k = 0; k <= p->LutMask; k++ ) + { + int pLits[16], nLits = 0; + if ( k == 0 && n == 1 ) + continue; + for ( j = 0; j < p->nLutSize; j++ ) + { +// pLits[nLits++] = Abc_Var2Lit( iBaseSatVar + j, (k >> j) & 1 ); + pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][j][pFanins[j]], 1 ); + if ( pFanins[j] >= p->nVars ) + pLits[nLits++] = Abc_Var2Lit( iBaseSatVar + pFanins[j] - p->nVars, (k >> j) & 1 ); + else if ( p->VarVals[pFanins[j]] != ((k >> j) & 1) ) + break; + } + if ( j < p->nLutSize ) + continue; +// if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVar + j, !n ); + if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVar + i - p->nVars, !n ); + if ( k > 0 ) pLits[nLits++] = Abc_Var2Lit( iVarStart + k-1, n ); + assert( nLits <= 2*p->nLutSize+2 ); + if ( !cadical_solver_addclause( p->pSat, pLits, pLits + nLits ) ) + return 0; + } + } + } + return 1; +} +void Exa7_ManPrint( Exa7_Man_t * p, int i, int iMint, abctime clk ) +{ + printf( "Iter%6d : ", i ); + Extra_PrintBinary( stdout, (unsigned *)&iMint, p->nVars ); + printf( " Var =%5d ", cadical_solver_nvars(p->pSat) ); + printf( "Cla =%6d ", cadical_solver_nclauses(p->pSat) ); + printf( "Conf =%9d ", cadical_solver_nconflicts(p->pSat) ); + Abc_PrintTime( 1, "Time", clk ); +} +int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars ) +{ + int i, status, Res = 0, iMint = 1; + abctime clkTotal = Abc_Clock(); + Exa7_Man_t * p; int fCompl = 0; + word pTruth[64]; + if ( pPars->pSymStr ) { + word * pFun = Abc_TtSymFunGenerate( pPars->pSymStr, pPars->nVars ); + pPars->pTtStr = ABC_CALLOC( char, pPars->nVars > 2 ? (1 << (pPars->nVars-2)) + 1 : 2 ); + Extra_PrintHexadecimalString( pPars->pTtStr, (unsigned *)pFun, pPars->nVars ); + if ( !pPars->fSilent ) printf( "Generated symmetric function: %s\n", pPars->pTtStr ); + ABC_FREE( pFun ); + } + if ( pPars->pTtStr ) + Abc_TtReadHex( pTruth, pPars->pTtStr ); + else assert( 0 ); + assert( pPars->nVars <= 12 ); + assert( pPars->nLutSize <= 6 ); + p = Exa7_ManAlloc( pPars, pTruth ); + if ( pTruth[0] & 1 ) { fCompl = 1; Abc_TtNot( pTruth, p->nWords ); } + status = Exa7_ManAddCnfStart( p, pPars->fOnlyAnd ); + assert( status ); + if ( !pPars->fSilent ) printf( "Running exact synthesis for %d-input function with %d %d-input LUTs...\n", p->nVars, p->nNodes, p->nLutSize ); + if ( pPars->fUseIncr ) + { + status = cadical_solver_solve( p->pSat, NULL, NULL, 0, 0, 0, 0 ); + assert( status == CADICAL_SAT ); + } + for ( i = 0; iMint != -1; i++ ) + { + if ( pPars->fUseIncr ? !Exa7_ManAddCnf2( p, iMint ) : !Exa7_ManAddCnf( p, iMint ) ) + break; + status = cadical_solver_solve( p->pSat, NULL, NULL, 0, 0, 0, 0 ); + if ( pPars->fVerbose && (!pPars->fUseIncr || i % 100 == 0) ) + Exa7_ManPrint( p, i, iMint, Abc_Clock() - clkTotal ); + if ( status == CADICAL_UNSAT || status == CADICAL_UNDEC ) + break; + iMint = Exa7_ManEval( p ); + } + if ( pPars->fVerbose && status != CADICAL_UNDEC ) + Exa7_ManPrint( p, i, iMint, Abc_Clock() - clkTotal ); + if ( iMint == -1 ) + Exa7_ManPrintSolution( p, fCompl ), Res = 1; + else if ( status == CADICAL_UNDEC ) + printf( "The solver timed out after %d sec.\n", pPars->RuntimeLim ); + else if ( !p->pPars->fSilent ) + printf( "The problem has no solution.\n" ), Res = 2; + if ( !pPars->fSilent && (p->nUsed[0] || p->nUsed[1]) ) printf( "Added = %d. Tried = %d. ", p->nUsed[1], p->nUsed[0] ); + if ( !pPars->fSilent ) Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); + if ( iMint == -1 && pPars->fDumpBlif ) + Exa7_ManDumpBlif( p, fCompl ); + if ( pPars->pSymStr ) + ABC_FREE( pPars->pTtStr ); + Exa7_ManFree( p ); + return Res; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/bmc/module.make b/src/sat/bmc/module.make index ae254433a..b19c6f69f 100644 --- a/src/sat/bmc/module.make +++ b/src/sat/bmc/module.make @@ -25,6 +25,7 @@ SRC += src/sat/bmc/bmcBCore.c \ src/sat/bmc/bmcMaj.c \ src/sat/bmc/bmcMaj2.c \ src/sat/bmc/bmcMaj3.c \ + src/sat/bmc/bmcMaj7.c \ src/sat/bmc/bmcMaxi.c \ src/sat/bmc/bmcMesh.c \ src/sat/bmc/bmcMesh2.c \ diff --git a/src/sat/cadical/cadicalSolver.c b/src/sat/cadical/cadicalSolver.c index dee2beaf3..3a48344be 100644 --- a/src/sat/cadical/cadicalSolver.c +++ b/src/sat/cadical/cadicalSolver.c @@ -239,10 +239,15 @@ int cadical_solver_addvar(cadical_solver* s) { ***********************************************************************/ void cadical_solver_setnvars(cadical_solver* s,int n) { - s->nVars = n; - if(ccadical_vars((CCaDiCaL*)s->p) == 0) { + if ( n <= s->nVars ) + return; + if ( s->nVars == 0 ) ccadical_reserve((CCaDiCaL*)s->p, n); + else { + assert( 0 ); + ccadical_reserve_difference((CCaDiCaL*)s->p, n - s->nVars); } + s->nVars = n; } /**Function************************************************************* From 38c2bec1ff987e2800d2f4fa8ef01c23e1adf13f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 14:17:48 -0800 Subject: [PATCH 11/38] Adding support for Kissat in "lutexact". --- src/base/abci/abc.c | 11 +- src/sat/bmc/bmc.h | 1 + src/sat/bmc/bmcMaj8.c | 747 ++++++++++++++++++++++++++++++++++++++++ src/sat/bmc/module.make | 1 + 4 files changed, 758 insertions(+), 2 deletions(-) create mode 100644 src/sat/bmc/bmcMaj8.c diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index eb3c24f06..4c712e94b 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10697,6 +10697,7 @@ usage: int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars ); + extern int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesis2( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesisRand( Bmc_EsPar_t * pPars ); @@ -10705,7 +10706,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYPiaorfgcdsvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYPiaorfgckdsvh" ) ) != EOF ) { switch ( c ) { @@ -10821,6 +10822,9 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'c': pPars->fCadical ^= 1; break; + case 'k': + pPars->fKissat ^= 1; + break; case 'd': pPars->fDumpBlif ^= 1; break; @@ -10894,6 +10898,8 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Exa3_ManExactSynthesis( pPars ); else if ( pPars->fCadical ) Exa7_ManExactSynthesis( pPars ); + else if ( pPars->fKissat ) + Exa8_ManExactSynthesis( pPars ); else Exa3_ManExactSynthesis2( pPars ); if ( argc == globalUtilOptind && Abc_FrameReadNtk(pAbc) ) @@ -10901,7 +10907,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-P string] [-iaorfgcdsvh] \n" ); + Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-P string] [-iaorfgckdsvh] \n" ); Abc_Print( -2, "\t exact synthesis of I-input function using N K-input gates\n" ); Abc_Print( -2, "\t-N : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-M : the number of K-input nodes [default = %d]\n", pPars->nNodes ); @@ -10919,6 +10925,7 @@ usage: Abc_Print( -2, "\t-f : toggle fixing LUT inputs in cascade mapping [default = %s]\n", pPars->fLutInFixed ? "yes" : "no" ); Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", pPars->fGlucose ? "yes" : "no" ); Abc_Print( -2, "\t-c : toggle using CaDiCal 2.2.0-rc1 by Armin Biere [default = %s]\n", pPars->fCadical ? "yes" : "no" ); + Abc_Print( -2, "\t-k : toggle using Kissat 4.0.2 by Armin Biere [default = %s]\n", pPars->fKissat ? "yes" : "no" ); Abc_Print( -2, "\t-d : toggle dumping decomposed networks into BLIF files [default = %s]\n", pPars->fDumpBlif ? "yes" : "no" ); Abc_Print( -2, "\t-s : toggle silent computation (no messages, except when a solution is found) [default = %s]\n", pPars->fSilent ? "yes" : "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", pPars->fVerbose ? "yes" : "no" ); diff --git a/src/sat/bmc/bmc.h b/src/sat/bmc/bmc.h index daf99c4e6..85fd0265c 100644 --- a/src/sat/bmc/bmc.h +++ b/src/sat/bmc/bmc.h @@ -58,6 +58,7 @@ struct Bmc_EsPar_t_ int fDumpCnf; int fGlucose; int fCadical; + int fKissat; int fCard; int fOrderNodes; int fEnumSols; diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c new file mode 100644 index 000000000..17073c1d1 --- /dev/null +++ b/src/sat/bmc/bmcMaj8.c @@ -0,0 +1,747 @@ +/**CFile**************************************************************** + + FileName [bmcMaj.c] + + SystemName [ABC: Logic synthesis and verification system.] + + PackageName [SAT-based bounded model checking.] + + Synopsis [Exact synthesis with majority gates.] + + Author [Alan Mishchenko] + + Affiliation [UC Berkeley] + + Date [Ver. 1.0. Started - October 1, 2017.] + + Revision [$Id: bmcMaj.c,v 1.00 2017/10/01 00:00:00 alanmi Exp $] + +***********************************************************************/ + +#include "bmc.h" +#include "misc/extra/extra.h" +#include "misc/util/utilTruth.h" +#include "sat/kissat/kissat.h" +#include "aig/miniaig/miniaig.h" +#include "base/io/ioResub.h" +#include "base/main/main.h" +#include "base/cmd/cmd.h" + +#define KISSAT_UNSAT 20 +#define KISSAT_SAT 10 +#define KISSAT_UNDEC 0 + +ABC_NAMESPACE_IMPL_START + + +#ifdef WIN32 +#include +#define unlink _unlink +#else +#include +#endif +#include + +//////////////////////////////////////////////////////////////////////// +/// DECLARATIONS /// +//////////////////////////////////////////////////////////////////////// + +#define MAJ_NOBJS 64 // Const0 + Const1 + nVars + nNodes + +typedef struct Exa8_Man_t_ Exa8_Man_t; +struct Exa8_Man_t_ +{ + Bmc_EsPar_t * pPars; // parameters + int nVars; // inputs + int nNodes; // internal nodes + int nLutSize; // lut size + int LutMask; // lut mask + int nObjs; // total objects (nVars inputs + nNodes internal nodes) + int nWords; // the truth table size in 64-bit words + int iVar; // the next available SAT variable + word * pTruth; // truth table + Vec_Wrd_t * vInfo; // nVars + nNodes + 1 + Vec_Bit_t * vUsed2; // bit masks + Vec_Bit_t * vUsed3; // bit masks + int VarMarks[MAJ_NOBJS][6][MAJ_NOBJS]; // variable marks + int VarVals[MAJ_NOBJS]; // values of the first nVars variables + Vec_Wec_t * vOutLits; // output vars + Vec_Wec_t * vInVars; // input vars + kissat * pSat; // SAT solver + int nVarAlloc; // total vars reserved in the solver + abctime timeStop; // runtime limit (0 = unlimited) + int nUsed[2]; +}; + +static inline int Exa8_LitToKissat( int Lit ) +{ + return Abc_LitIsCompl( Lit ) ? -(Abc_Lit2Var( Lit ) + 1) : (Abc_Lit2Var( Lit ) + 1); +} +static inline int Exa8_KissatAddClause( Exa8_Man_t * p, int * pLits, int nLits ) +{ + int i; + for ( i = 0; i < nLits; i++ ) + kissat_add( p->pSat, Exa8_LitToKissat( pLits[i] ) ); + kissat_add( p->pSat, 0 ); + return !kissat_is_inconsistent( p->pSat ); +} +static inline int Exa8_KissatVarValue( Exa8_Man_t * p, int v ) +{ + return kissat_value( p->pSat, v + 1 ) > 0; +} +static int Exa8_KissatTerminate( void * pData ) +{ + Exa8_Man_t * p = (Exa8_Man_t *)pData; + return p && p->timeStop && Abc_Clock() > p->timeStop; +} + +static inline word * Exa8_ManTruth( Exa8_Man_t * p, int v ) { return Vec_WrdEntryP( p->vInfo, p->nWords * v ); } + +static inline int Exa8_ManIsUsed2( Exa8_Man_t * p, int m, int n, int i, int j ) +{ + int Pos = ((m * p->pPars->nNodes + n - p->pPars->nVars) * p->nObjs + i) * p->nObjs + j; + p->nUsed[0]++; + assert( i < n && j < n && i < j ); + if ( Vec_BitEntry(p->vUsed2, Pos) ) + return 1; + p->nUsed[1]++; + Vec_BitWriteEntry( p->vUsed2, Pos, 1 ); + return 0; +} + +static inline int Exa8_ManIsUsed3( Exa8_Man_t * p, int m, int n, int i, int j, int k ) +{ + int Pos = (((m * p->pPars->nNodes + n - p->pPars->nVars) * p->nObjs + i) * p->nObjs + j) * p->nObjs + k; + p->nUsed[0]++; + assert( i < n && j < n && k < n && i < j && j < k ); + if ( Vec_BitEntry(p->vUsed3, Pos) ) + return 1; + p->nUsed[1]++; + Vec_BitWriteEntry( p->vUsed3, Pos, 1 ); + return 0; +} + + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +Vec_Wec_t * Exa8_ChooseInputVars_int( int nVars, int nLuts, int nLutSize ) +{ + Vec_Wec_t * p = Vec_WecStart( nLuts ); + Vec_Int_t * vLevel; int i; + Vec_WecForEachLevel( p, vLevel, i ) { + do { + int iVar = (Abc_Random(0) ^ Abc_Random(0) ^ Abc_Random(0)) % nVars; + Vec_IntPushUniqueOrder( vLevel, iVar ); + } + while ( Vec_IntSize(vLevel) < nLutSize-(int)(i>0) ); + } + return p; +} +Vec_Int_t * Exa8_CountInputVars( int nVars, Vec_Wec_t * p ) +{ + Vec_Int_t * vLevel; int i, k, Obj; + Vec_Int_t * vCounts = Vec_IntStart( nVars ); + Vec_WecForEachLevel( p, vLevel, i ) + Vec_IntForEachEntry( vLevel, Obj, k ) + Vec_IntAddToEntry( vCounts, Obj, 1 ); + return vCounts; +} +Vec_Wec_t * Exa8_ChooseInputVars( int nVars, int nLuts, int nLutSize ) +{ + for ( int i = 0; i < 1000; i++ ) { + Vec_Wec_t * p = Exa8_ChooseInputVars_int( nVars, nLuts, nLutSize ); + Vec_Int_t * q = Exa8_CountInputVars( nVars, p ); + int RetValue = Vec_IntFind( q, 0 ); + Vec_IntFree( q ); + if ( RetValue == -1 ) + return p; + Vec_WecFree( p ); + } + assert( 0 ); + return NULL; +} +Vec_Wec_t * Exa8_ChooseInputVars2( int nVars, int nLuts, int nLutSize, char * pPermStr ) +{ + Vec_Wec_t * p = Vec_WecStart( nLuts ); + Vec_Int_t * vLevel; int i, Pos = 0; + assert( nLuts * nLutSize == (int)strlen(pPermStr) ); + Vec_WecForEachLevel( p, vLevel, i ) { + for ( int k = 0; k < nLutSize; k++, Pos++ ) + if ( pPermStr[Pos] != '_' ) + Vec_IntPush( vLevel, pPermStr[Pos] == '*' ? -1 : (int)(pPermStr[Pos]-'a') ); + } + return p; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static Vec_Wrd_t * Exa8_ManTruthTables( Exa8_Man_t * p ) +{ + Vec_Wrd_t * vInfo = p->vInfo = Vec_WrdStart( p->nWords * (p->nObjs+1) ); int i; + for ( i = 0; i < p->nVars; i++ ) + Abc_TtIthVar( Exa8_ManTruth(p, i), i, p->nVars ); + //Dau_DsdPrintFromTruth( Exa8_ManTruth(p, p->nObjs), p->nVars ); + return vInfo; +} +static int Exa8_ManVarReserve( Exa8_Man_t * p ) +{ + int nMintMax = 1 << p->nVars; + int nVarsPerMint = p->pPars->fUseIncr ? p->nNodes : (p->nLutSize + 1) * p->nNodes; + int64_t nTotal = (int64_t)p->iVar + (int64_t)nVarsPerMint * nMintMax; + if ( nTotal > INT_MAX ) + nTotal = INT_MAX; + return (int)nTotal; +} +static int Exa8_ManMarkup( Exa8_Man_t * p ) +{ + int i, k, j; + assert( p->nObjs <= MAJ_NOBJS ); + // assign functionality variables + p->iVar = 1 + p->LutMask * p->nNodes; + // assign connectivity variables + for ( i = p->nVars; i < p->nObjs; i++ ) + { + if ( p->pPars->fLutCascade ) + { + if ( i > p->nVars ) + { + Vec_WecPush( p->vOutLits, i-1, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][0][i-1] = p->iVar++; + } + for ( k = (int)(i > p->nVars); k < p->nLutSize; k++ ) + { + for ( j = 0; j < p->nVars - k + (int)(i > p->nVars); j++ ) + { + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + } + } + continue; + } + for ( k = 0; k < p->nLutSize; k++ ) + { + if ( p->pPars->fFewerVars && i == p->nObjs - 1 && k == 0 ) + { + j = p->nObjs - 2; + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + continue; + } + for ( j = p->pPars->fFewerVars ? p->nLutSize - 1 - k : 0; j < i - k; j++ ) + { + Vec_WecPush( p->vOutLits, j, Abc_Var2Lit(p->iVar, 0) ); + p->VarMarks[i][k][j] = p->iVar++; + } + } + } + if ( !p->pPars->fSilent ) printf( "The number of parameter variables = %d.\n", p->iVar ); + if ( p->pPars->fLutCascade && (p->pPars->fLutInFixed || p->pPars->pPermStr) ) { + if ( p->pPars->pPermStr ) + p->vInVars = Exa8_ChooseInputVars2( p->nVars, p->nNodes, p->nLutSize, p->pPars->pPermStr ); + else + p->vInVars = Exa8_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize ); + if ( !p->pPars->fSilent ) { + Vec_Int_t * vLevel; int i, Var; + printf( "Using fixed input assignment %s%s:\n", + p->pPars->pPermStr ? "provided by the user " : "generated randomly", p->pPars->pPermStr ? p->pPars->pPermStr : "" ); + Vec_WecForEachLevelReverse( p->vInVars, vLevel, i ) { + printf( "%c : ", 'A'+p->nVars+i-p->nVars ); + Vec_IntForEachEntry( vLevel, Var, k ) + printf( "%c ", Var < 0 ? '*' : 'a'+Var ); + printf( "\n" ); + } + } + } + return p->iVar; + // printout + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + printf( " Node %2d\n", i ); + for ( j = 0; j < p->nObjs; j++ ) + { + printf( "Fanin %2d : ", j ); + for ( k = 0; k < p->nLutSize; k++ ) + printf( "%3d ", p->VarMarks[i][k][j] ); + printf( "\n" ); + } + } + return p->iVar; +} +static Exa8_Man_t * Exa8_ManAlloc( Bmc_EsPar_t * pPars, word * pTruth ) +{ + Exa8_Man_t * p = ABC_CALLOC( Exa8_Man_t, 1 ); + p->pPars = pPars; + p->nVars = pPars->nVars; + p->nNodes = pPars->nNodes; + p->nLutSize = pPars->nLutSize; + p->LutMask = (1 << pPars->nLutSize) - 1; + p->nObjs = pPars->nVars + pPars->nNodes; + p->nWords = Abc_TtWordNum(pPars->nVars); + p->pTruth = pTruth; + p->vOutLits = Vec_WecStart( p->nObjs ); + p->iVar = Exa8_ManMarkup( p ); + p->vInfo = Exa8_ManTruthTables( p ); + if ( p->pPars->nLutSize == 2 ) + p->vUsed2 = Vec_BitStart( (1 << p->pPars->nVars) * p->pPars->nNodes * p->nObjs * p->nObjs ); + else if ( p->pPars->nLutSize == 3 ) + p->vUsed3 = Vec_BitStart( (1 << p->pPars->nVars) * p->pPars->nNodes * p->nObjs * p->nObjs * p->nObjs ); + p->pSat = kissat_init(); + p->nVarAlloc = Exa8_ManVarReserve( p ); + assert( p->nVarAlloc >= p->iVar ); + kissat_reserve( p->pSat, p->nVarAlloc ); + p->timeStop = 0; + return p; +} +static void Exa8_ManFree( Exa8_Man_t * p ) +{ + kissat_release( p->pSat ); + Vec_WrdFree( p->vInfo ); + Vec_BitFreeP( &p->vUsed2 ); + Vec_BitFreeP( &p->vUsed3 ); + Vec_WecFree( p->vOutLits ); + Vec_WecFreeP( &p->vInVars ); + ABC_FREE( p ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Exa8_ManFindFanin( Exa8_Man_t * p, int i, int k ) +{ + int j, Count = 0, iVar = -1; + for ( j = 0; j < p->nObjs; j++ ) + if ( p->VarMarks[i][k][j] && Exa8_KissatVarValue(p, p->VarMarks[i][k][j]) ) + { + iVar = j; + Count++; + } + assert( Count == 1 ); + return iVar; +} +static inline int Exa8_ManEval( Exa8_Man_t * p ) +{ + static int Flag = 0; + int i, k, j, iMint; word * pFanins[6]; + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + pFanins[k] = Exa8_ManTruth( p, Exa8_ManFindFanin(p, i, k) ); + Abc_TtConst0( Exa8_ManTruth(p, i), p->nWords ); + for ( k = 1; k <= p->LutMask; k++ ) + { + if ( !Exa8_KissatVarValue(p, iVarStart+k-1) ) + continue; +// Abc_TtAndCompl( Exa8_ManTruth(p, p->nObjs), pFanins[0], !(k&1), pFanins[1], !(k>>1), p->nWords ); + Abc_TtConst1( Exa8_ManTruth(p, p->nObjs), p->nWords ); + for ( j = 0; j < p->nLutSize; j++ ) + Abc_TtAndCompl( Exa8_ManTruth(p, p->nObjs), Exa8_ManTruth(p, p->nObjs), 0, pFanins[j], !((k >> j) & 1), p->nWords ); + Abc_TtOr( Exa8_ManTruth(p, i), Exa8_ManTruth(p, i), Exa8_ManTruth(p, p->nObjs), p->nWords ); + } + } + if ( Flag && p->nVars >= 6 ) + iMint = Abc_TtFindLastDiffBit( Exa8_ManTruth(p, p->nObjs-1), p->pTruth, p->nVars ); + else + iMint = Abc_TtFindFirstDiffBit( Exa8_ManTruth(p, p->nObjs-1), p->pTruth, p->nVars ); + if ( iMint == -1 ) + return -1; + //Flag ^= 1; + assert( iMint < (1 << p->nVars) ); + return iMint; +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Exa8_ManPrintSolution( Exa8_Man_t * p, int fCompl ) +{ + int i, k, iVar; + printf( "Realization of given %d-input function using %d %d-input LUTs:\n", p->nVars, p->nNodes, p->nLutSize ); + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + int Val, iVarStart = 1 + p->LutMask*(i - p->nVars); + printf( "%c = %d\'b", 'A'+i-p->nVars, 1 << p->nLutSize ); + for ( k = p->LutMask - 1; k >= 0; k-- ) + { + Val = Exa8_KissatVarValue(p, iVarStart+k); + if ( i == p->nObjs - 1 && fCompl ) + printf( "%d", !Val ); + else + printf( "%d", Val ); + } + if ( i == p->nObjs - 1 && fCompl ) + printf( "1(" ); + else + printf( "0(" ); + + for ( k = p->nLutSize - 1; k >= 0; k-- ) + { + iVar = Exa8_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + printf( " %c", 'a'+iVar ); + else + printf( " %c", 'A'+iVar-p->nVars ); + } + printf( " )\n" ); + } +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static void Exa8_ManDumpBlif( Exa8_Man_t * p, int fCompl ) +{ + int i, k, b, iVar; + char pFileName[1000]; + char * pStr = Abc_UtilStrsav(p->pPars->pSymStr ? p->pPars->pSymStr : p->pPars->pTtStr); + if ( strlen(pStr) > 16 ) { + pStr[16] = '_'; + pStr[17] = '\0'; + } + sprintf( pFileName, "%s.blif", pStr ); + FILE * pFile = fopen( pFileName, "wb" ); + if ( pFile == NULL ) return; + fprintf( pFile, "# Realization of given %d-input function using %d %d-input LUTs synthesized by ABC on %s\n", p->nVars, p->nNodes, p->nLutSize, Extra_TimeStamp() ); + fprintf( pFile, ".model %s\n", pStr ); + fprintf( pFile, ".inputs" ); + for ( k = 0; k < p->nVars; k++ ) + fprintf( pFile, " %c", 'a'+k ); + fprintf( pFile, "\n.outputs F\n" ); + for ( i = p->nObjs - 1; i >= p->nVars; i-- ) + { + fprintf( pFile, ".names" ); + for ( k = 0; k < p->nLutSize; k++ ) + { + iVar = Exa8_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + fprintf( pFile, " %c", 'a'+iVar ); + else + fprintf( pFile, " %02d", iVar ); + } + if ( i == p->nObjs - 1 ) + fprintf( pFile, " F\n" ); + else + fprintf( pFile, " %02d\n", i ); + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->LutMask; k++ ) + { + int Val = Exa8_KissatVarValue(p, iVarStart+k); + if ( Val == 0 ) + continue; + for ( b = 0; b < p->nLutSize; b++ ) + fprintf( pFile, "%d", ((k+1) >> b) & 1 ); + fprintf( pFile, " %d\n", i != p->nObjs - 1 || !fCompl ); + } + } + fprintf( pFile, ".end\n\n" ); + fclose( pFile ); + if ( !p->pPars->fSilent ) printf( "Finished dumping the resulting LUT network into file \"%s\".\n", pFileName ); + ABC_FREE( pStr ); +} + +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static int Exa8_ManAddCnfStart( Exa8_Man_t * p, int fOnlyAnd ) +{ + int pLits[MAJ_NOBJS], pLits2[2], i, j, k, n, m; + // input constraints + for ( i = p->nVars; i < p->nObjs; i++ ) + { + int iVarStart = 1 + p->LutMask*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + { + int nLits = 0; + for ( j = 0; j < p->nObjs; j++ ) + if ( p->VarMarks[i][k][j] ) + pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][k][j], 0 ); + assert( nLits > 0 ); + // input uniqueness + if ( !Exa8_KissatAddClause( p, pLits, nLits ) ) + return 0; + for ( n = 0; n < nLits; n++ ) + for ( m = n+1; m < nLits; m++ ) + { + pLits2[0] = Abc_LitNot(pLits[n]); + pLits2[1] = Abc_LitNot(pLits[m]); + if ( !Exa8_KissatAddClause( p, pLits2, 2 ) ) + return 0; + } + if ( k == p->nLutSize - 1 ) + break; + // symmetry breaking + for ( j = 0; j < p->nObjs; j++ ) if ( p->VarMarks[i][k][j] ) + for ( n = j; n < p->nObjs; n++ ) if ( p->VarMarks[i][k+1][n] ) + { + pLits2[0] = Abc_Var2Lit( p->VarMarks[i][k][j], 1 ); + pLits2[1] = Abc_Var2Lit( p->VarMarks[i][k+1][n], 1 ); + if ( !Exa8_KissatAddClause( p, pLits2, 2 ) ) + return 0; + } + } +//#ifdef USE_NODE_ORDER + // node ordering + if ( p->pPars->fOrderNodes ) + { + for ( j = p->nVars; j < i; j++ ) + for ( n = 0; n < p->nObjs; n++ ) if ( p->VarMarks[i][0][n] ) + for ( m = n+1; m < p->nObjs; m++ ) if ( p->VarMarks[j][0][m] ) + { + pLits2[0] = Abc_Var2Lit( p->VarMarks[i][0][n], 1 ); + pLits2[1] = Abc_Var2Lit( p->VarMarks[j][0][m], 1 ); + if ( !Exa8_KissatAddClause( p, pLits2, 2 ) ) + return 0; + } + } +//#endif + if ( p->nLutSize != 2 ) + continue; + // two-input functions + for ( k = 0; k < 3; k++ ) + { + pLits[0] = Abc_Var2Lit( iVarStart, k==1 ); + pLits[1] = Abc_Var2Lit( iVarStart+1, k==2 ); + pLits[2] = Abc_Var2Lit( iVarStart+2, k!=0 ); + if ( !Exa8_KissatAddClause( p, pLits, 3 ) ) + return 0; + } + if ( fOnlyAnd ) + { + pLits[0] = Abc_Var2Lit( iVarStart, 1 ); + pLits[1] = Abc_Var2Lit( iVarStart+1, 1 ); + pLits[2] = Abc_Var2Lit( iVarStart+2, 0 ); + if ( !Exa8_KissatAddClause( p, pLits, 3 ) ) + return 0; + } + } + // outputs should be used + for ( i = 0; i < p->nObjs - 1; i++ ) + { + Vec_Int_t * vArray = Vec_WecEntry(p->vOutLits, i); + int * pArray = Vec_IntArray( vArray ); + int nArrayLits = Vec_IntSize( vArray ); + assert( nArrayLits > 0 ); + if ( !Exa8_KissatAddClause( p, pArray, nArrayLits ) ) + return 0; + } + if ( p->vInVars ) { + Vec_Int_t * vLevel; int Var; + //Vec_WecPrint( p->vInVars, 0 ); + Vec_WecForEachLevel( p->vInVars, vLevel, i ) + { + assert( Vec_IntSize(vLevel) > 0 ); + Vec_IntForEachEntry( vLevel, Var, k ) { + if ( Var < 0 ) continue; + if ( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var] == 0 ) { + printf( "Skipping variable %d in place %d because it cannot be constrained.\n", Var, k ); + continue; + } + pLits[0] = Abc_Var2Lit( p->VarMarks[p->nVars+i][p->nLutSize-1-k][Var], 0 ); assert(pLits[0]); + if ( !Exa8_KissatAddClause( p, pLits, 1 ) ) + return 0; + } + } + } + return 1; +} +static int Exa8_ManAddCnf( Exa8_Man_t * p, int iMint ) +{ + // save minterm values + int i, k, n, j, Value = Abc_TtGetBit(p->pTruth, iMint); + for ( i = 0; i < p->nVars; i++ ) + p->VarVals[i] = (iMint >> i) & 1; + //printf( "Adding clauses for minterm %d with value %d.\n", iMint, Value ); + for ( i = p->nVars; i < p->nObjs; i++ ) + { + // fanin connectivity + int iVarStart = 1 + p->LutMask*(i - p->nVars); + int iBaseSatVarI = p->iVar + (p->nLutSize+1)*(i - p->nVars); + for ( k = 0; k < p->nLutSize; k++ ) + { + for ( j = 0; j < p->nObjs; j++ ) if ( p->VarMarks[i][k][j] ) + { + int iBaseSatVarJ = p->iVar + (p->nLutSize+1)*(j - p->nVars); + for ( n = 0; n < 2; n++ ) + { + int pLits[3], nLits = 0; + pLits[nLits++] = Abc_Var2Lit( p->VarMarks[i][k][j], 1 ); + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + k, n ); + if ( j >= p->nVars ) + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarJ + p->nLutSize, !n ); + else if ( p->VarVals[j] == n ) + continue; + if ( !Exa8_KissatAddClause( p, pLits, nLits ) ) + return 0; + } + } + } + // node functionality + for ( n = 0; n < 2; n++ ) + { + if ( i == p->nObjs - 1 && n == Value ) + continue; + for ( k = 0; k <= p->LutMask; k++ ) + { + int pLits[16], nLits = 0; + if ( k == 0 && n == 1 ) + continue; + //pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 0, (k&1) ); + //pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 1, (k>>1) ); + //if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + 2, !n ); + for ( j = 0; j < p->nLutSize; j++ ) + pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + j, (k >> j) & 1 ); + if ( i != p->nObjs - 1 ) pLits[nLits++] = Abc_Var2Lit( iBaseSatVarI + j, !n ); + if ( k > 0 ) pLits[nLits++] = Abc_Var2Lit( iVarStart + k-1, n ); + assert( nLits <= p->nLutSize+2 ); + if ( !Exa8_KissatAddClause( p, pLits, nLits ) ) + return 0; + } + } + } + p->iVar += (p->nLutSize+1)*p->nNodes; + assert( p->iVar <= p->nVarAlloc ); + return 1; +} + +int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) +{ + int status = KISSAT_UNDEC; + int Res = 0; + abctime clkTotal = Abc_Clock(); + Exa8_Man_t * p; + int fCompl = 0; + word pTruth[64]; + if ( pPars->pSymStr ) { + word * pFun = Abc_TtSymFunGenerate( pPars->pSymStr, pPars->nVars ); + pPars->pTtStr = ABC_CALLOC( char, pPars->nVars > 2 ? (1 << (pPars->nVars-2)) + 1 : 2 ); + Extra_PrintHexadecimalString( pPars->pTtStr, (unsigned *)pFun, pPars->nVars ); + if ( !pPars->fSilent ) printf( "Generated symmetric function: %s\n", pPars->pTtStr ); + ABC_FREE( pFun ); + } + if ( pPars->pTtStr ) + Abc_TtReadHex( pTruth, pPars->pTtStr ); + else assert( 0 ); + assert( pPars->nVars <= 12 ); + assert( pPars->nLutSize <= 6 ); + if ( pPars->fUseIncr && !pPars->fSilent ) + printf( "Warning: Ignoring incremental option when using Kissat.\n" ); + pPars->fUseIncr = 0; + p = Exa8_ManAlloc( pPars, pTruth ); + if ( pTruth[0] & 1 ) { fCompl = 1; Abc_TtNot( pTruth, p->nWords ); } + if ( !pPars->fSilent ) + printf( "Running exact synthesis for %d-input function with %d %d-input LUTs...\n", p->nVars, p->nNodes, p->nLutSize ); + if ( Exa8_ManAddCnfStart( p, pPars->fOnlyAnd ) ) + { + int nMints = 1 << p->nVars; + int iMint; + status = KISSAT_UNSAT; + for ( iMint = 0; iMint < nMints; iMint++ ) + { + if ( !Exa8_ManAddCnf( p, iMint ) ) + break; + } + if ( iMint == nMints ) + { + if ( pPars->RuntimeLim ) + { + p->timeStop = Abc_Clock() + pPars->RuntimeLim * CLOCKS_PER_SEC; + kissat_set_terminate( p->pSat, p, Exa8_KissatTerminate ); + } + else + { + p->timeStop = 0; + kissat_set_terminate( p->pSat, NULL, NULL ); + } + status = kissat_solve( p->pSat ); + } + } + else + status = KISSAT_UNSAT; + + if ( status == KISSAT_SAT ) + { + int DiffMint = Exa8_ManEval( p ); + if ( DiffMint != -1 ) + printf( "Warning: Verification detected a mismatch at minterm %d.\n", DiffMint ); + Exa8_ManPrintSolution( p, fCompl ); + if ( pPars->fDumpBlif ) + Exa8_ManDumpBlif( p, fCompl ); + Res = 1; + } + else if ( status == KISSAT_UNSAT ) + { + if ( !p->pPars->fSilent ) + printf( "The problem has no solution.\n" ); + Res = 2; + } + else + { + if ( pPars->RuntimeLim ) + printf( "The solver timed out after %d sec.\n", pPars->RuntimeLim ); + } + if ( !pPars->fSilent && (p->nUsed[0] || p->nUsed[1]) ) + printf( "Added = %d. Tried = %d. ", p->nUsed[1], p->nUsed[0] ); + if ( !pPars->fSilent ) + Abc_PrintTime( 1, "Total runtime", Abc_Clock() - clkTotal ); + if ( pPars->pSymStr ) + ABC_FREE( pPars->pTtStr ); + Exa8_ManFree( p ); + return Res; +} + + +//////////////////////////////////////////////////////////////////////// +/// END OF FILE /// +//////////////////////////////////////////////////////////////////////// + +ABC_NAMESPACE_IMPL_END diff --git a/src/sat/bmc/module.make b/src/sat/bmc/module.make index b19c6f69f..e0e86212b 100644 --- a/src/sat/bmc/module.make +++ b/src/sat/bmc/module.make @@ -26,6 +26,7 @@ SRC += src/sat/bmc/bmcBCore.c \ src/sat/bmc/bmcMaj2.c \ src/sat/bmc/bmcMaj3.c \ src/sat/bmc/bmcMaj7.c \ + src/sat/bmc/bmcMaj8.c \ src/sat/bmc/bmcMaxi.c \ src/sat/bmc/bmcMesh.c \ src/sat/bmc/bmcMesh2.c \ From 3bd528c0bff8c4d48e003c677bfae5881dbb7c33 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 22:41:26 -0800 Subject: [PATCH 12/38] Experiments with exact synthesis. --- src/aig/gia/giaLutCas.c | 77 +++++++++++++++++++++++++++++++++++++---- src/aig/gia/giaQbf.c | 21 +++++++---- src/base/abci/abc.c | 51 +++++++++++++++++++++------ 3 files changed, 125 insertions(+), 24 deletions(-) diff --git a/src/aig/gia/giaLutCas.c b/src/aig/gia/giaLutCas.c index 1d1721ab0..7465ad18c 100644 --- a/src/aig/gia/giaLutCas.c +++ b/src/aig/gia/giaLutCas.c @@ -109,12 +109,21 @@ int Gia_ManLutCasGen_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_I int iLit1 = Gia_ManLutCasGen_rec( pNew, vCtrls, iCtrl, vDatas, Shift + (1<pName = Abc_UtilStrsav( pPerm ); Vec_Int_t * vDatas = Vec_IntAlloc( nParams ); @@ -132,18 +141,72 @@ Gia_Man_t * Gia_ManLutCasGen( int nVars, int nLuts, int LutSize, int Seed, int f Vec_IntWriteEntry( vLits, k, Vec_IntEntry(vCtrls, (int)(*pCur++ - 'a')) ); Vec_IntWriteEntry( vLits, 0, Gia_ManLutCasGen_rec(pNew, vLits, LutSize, vDatas, i * (1 << LutSize)) ); } - Gia_ManAppendCo( pNew, Vec_IntEntry(vLits, 0) ); + // if the AIG is given, create a miter + int iLit = Vec_IntEntry(vLits, 0); + if ( p ) { + assert( Gia_ManCiNum(p) == nVars ); + assert( Gia_ManCoNum(p) == 1 ); + Gia_ManFillValue( p ); + Gia_ManConst0(p)->Value = 0; + Gia_Obj_t * pObj; int i; + Gia_ManForEachCi( p, pObj, i ) + pObj->Value = Vec_IntEntry(vCtrls, i); + Gia_ManForEachAnd( p, pObj, i ) + pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); + iLit = Gia_ManAppendXor( pNew, iLit, Gia_ObjFanin0Copy(Gia_ManCo(p, 0)) ); + iLit = Abc_LitNot(iLit); + } + Gia_ManAppendCo( pNew, iLit ); Vec_IntFree( vDatas ); Vec_IntFree( vCtrls ); Vec_IntFree( vLits ); - ABC_FREE( pPerm ); + if ( fOwnPerm ) + ABC_FREE( pPerm ); return pNew; } +/* +int Gia_ManLutCasGenSolve( int nVars, int nLuts, int LutSize, char * pTtStr, int fVerbose ) +{ + extern Gia_Man_t * Gia_QbfQuantifyAll( Gia_Man_t * p, int nPars, int fAndAll, int fOrAll ); + assert( strlen(pTtStr) <= 1024 ); + word pTruth[64] = {0}; + int i, Id, nVars = Abc_TtReadHex( pTruth, pTtStr ); + assert( nVars <= 12 ); + int nParams = nLuts * (1 << LutSize); + Gia_Man_t * pCas = Gia_ManLutCasGen( NULL, NULL, nVars, nLuts, LutSize, 0, fVerbose ); + Gia_Man_t * pCofs = Gia_QbfQuantifyAll( pCas, nParams, 0, 0 ); + Gia_ManFree( pCas ); + Cnf_Dat_t * pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( pCofs, 8, 0, 0, 0, 0 ); + cadical_solver* pSat = cadical_solver_new(void); + cadical_solver_setnvars( pSat, pCnf->nVars ); + // add output literals + assert( Gia_ManCoNum(pCofs) == (1 << nVars) ); + Gia_ManForEachCoId( pCofs, Id, i ) { + int Lit = Abc_Var2Lit(pCnf->pVarNums[Id], Abc_TtGetBit(pTruth, i)); + int status = cadical_solver_addclause( pSat, &Lit, &Lit+1 ); + } + for ( i = 0; i < pCnf->nClauses; i++ ) + if ( !cadical_solver_addclause( pSat, pCnf->pClauses[i], pCnf->pClauses[i+1] ) ) { + Cnf_DataFree( pCnf ); + return 0; + } + Cnf_DataFree( pCnf ); + Gia_ManFree( pCofs ); + int status = cadical_solver_solve( pSat, NULL, NULL, 0, 0, 0, 0 ); + for ( i = 0; i < nLuts; i++, printf(" ") ) + for ( k = 0; k < (1 << LutSize); k++ ) { + int Value = cadical_solver_get_var_value(pSat, i*(1 << LutSize) + k); + printf( "%d", Value ); + } + cadical_solver_delete( pSat ); + return 1; +} +*/ + //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END - diff --git a/src/aig/gia/giaQbf.c b/src/aig/gia/giaQbf.c index 8af8c6c6f..08bc0bf5f 100644 --- a/src/aig/gia/giaQbf.c +++ b/src/aig/gia/giaQbf.c @@ -893,7 +893,7 @@ void Gia_QbfLearnConstraint( Qbf_Man_t * p, Vec_Int_t * vValues ) SeeAlso [] ***********************************************************************/ -int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fVerbose ) +int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fSilent, int fVerbose ) { Qbf_Man_t * p = Gia_QbfAlloc( pGia, nPars, fGlucose, fCadical, fVerbose ); Gia_Man_t * pCof; @@ -939,9 +939,18 @@ int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, i if ( RetValue == 0 ) { int nZeros = Vec_IntCountZero( p->vValues ); - printf( "Parameters: " ); + printf( "Parameters (%d): 0x", nPars ); assert( Vec_IntSize(p->vValues) == nPars ); - Vec_IntPrintBinary( p->vValues ); + //Vec_IntPrintBinary( p->vValues ); + while ( Vec_IntSize(p->vValues) % 4 ) + Vec_IntPush(p->vValues, 0); + for ( int i = Vec_IntSize(p->vValues)/4 - 1; i >= 0; i-- ) { + int Digit = Vec_IntEntry(p->vValues, 4*i+0); + Digit |= Vec_IntEntry(p->vValues, 4*i+1) << 1; + Digit |= Vec_IntEntry(p->vValues, 4*i+2) << 2; + Digit |= Vec_IntEntry(p->vValues, 4*i+3) << 3; + printf( "%x", Digit ); + } printf( " Statistics: 0=%d 1=%d\n", nZeros, Vec_IntSize(p->vValues) - nZeros ); if ( nEncVars ) { @@ -956,9 +965,9 @@ int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, i printf( "The problem aborted after %d conflicts. ", nConfLimit ); else if ( RetValue == -1 && nIterLimit ) printf( "The problem aborted after %d iterations. ", nIterLimit ); - else if ( RetValue == 1 ) + else if ( RetValue == 1 && !fSilent ) printf( "The problem is UNSAT after %d iterations. ", i ); - else + else if ( !fSilent ) printf( "The problem is SAT after %d iterations. ", i ); if ( fVerbose ) { @@ -967,7 +976,7 @@ int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, i Abc_PrintTime( 1, "Other", Abc_Clock() - p->clkStart - p->clkSat ); Abc_PrintTime( 1, "TOTAL", Abc_Clock() - p->clkStart ); } - else + else if ( !fSilent ) Abc_PrintTime( 1, "Time", Abc_Clock() - p->clkStart ); Gia_QbfFree( p ); return RetValue; diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 4c712e94b..1d2ad8a1a 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10924,7 +10924,7 @@ usage: Abc_Print( -2, "\t-r : toggle synthesizing a single-rail cascade [default = %s]\n", pPars->fLutCascade ? "yes" : "no" ); Abc_Print( -2, "\t-f : toggle fixing LUT inputs in cascade mapping [default = %s]\n", pPars->fLutInFixed ? "yes" : "no" ); Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", pPars->fGlucose ? "yes" : "no" ); - Abc_Print( -2, "\t-c : toggle using CaDiCal 2.2.0-rc1 by Armin Biere [default = %s]\n", pPars->fCadical ? "yes" : "no" ); + Abc_Print( -2, "\t-c : toggle using CaDiCal 2.2.0-rc1 by Armin Biere et al [default = %s]\n", pPars->fCadical ? "yes" : "no" ); Abc_Print( -2, "\t-k : toggle using Kissat 4.0.2 by Armin Biere [default = %s]\n", pPars->fKissat ? "yes" : "no" ); Abc_Print( -2, "\t-d : toggle dumping decomposed networks into BLIF files [default = %s]\n", pPars->fDumpBlif ? "yes" : "no" ); Abc_Print( -2, "\t-s : toggle silent computation (no messages, except when a solution is found) [default = %s]\n", pPars->fSilent ? "yes" : "no" ); @@ -51340,7 +51340,7 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern void Gia_QbfDumpFile( Gia_Man_t * pGia, int nPars ); extern void Gia_QbfDumpFileInv( Gia_Man_t * pGia, int nPars ); - extern int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fVerbose ); + extern int Gia_QbfSolve( Gia_Man_t * pGia, int nPars, int nIterLimit, int nConfLimit, int nTimeOut, int nEncVars, int fGlucose, int fCadical, int fSilent, int fVerbose ); int c, nPars = -1; int nIterLimit = 0; int nConfLimit = 0; @@ -51350,9 +51350,10 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) int fDumpCnf2 = 0; int fGlucose = 0; int fCadical = 0; + int fSilent = 0; int fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "PICTKdegcvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "PICTKdegcsvh" ) ) != EOF ) { switch ( c ) { @@ -51423,6 +51424,9 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'c': fCadical ^= 1; break; + case 's': + fSilent ^= 1; + break; case 'v': fVerbose ^= 1; break; @@ -51457,11 +51461,11 @@ int Abc_CommandAbc9Qbf( Abc_Frame_t * pAbc, int argc, char ** argv ) else if ( fDumpCnf2 ) Gia_QbfDumpFileInv( pAbc->pGia, nPars ); else - Gia_QbfSolve( pAbc->pGia, nPars, nIterLimit, nConfLimit, nTimeOut, nEncVars, fGlucose, fCadical, fVerbose ); + Gia_QbfSolve( pAbc->pGia, nPars, nIterLimit, nConfLimit, nTimeOut, nEncVars, fGlucose, fCadical, fSilent, fVerbose ); return 0; usage: - Abc_Print( -2, "usage: &qbf [-PICTK num] [-degcvh]\n" ); + Abc_Print( -2, "usage: &qbf [-PICTK num] [-degcsvh]\n" ); Abc_Print( -2, "\t solves QBF problem EpVxM(p,x)\n" ); Abc_Print( -2, "\t-P num : number of parameters p (should be the first PIs) [default = %d]\n", nPars ); Abc_Print( -2, "\t-I num : quit after the given iteration even if unsolved [default = %d]\n", nIterLimit ); @@ -51472,6 +51476,7 @@ usage: Abc_Print( -2, "\t-e : toggle dumping QDIMACS file instead of solving (original QBF) [default = %s]\n", fDumpCnf2? "yes": "no" ); Abc_Print( -2, "\t-g : toggle using Glucose 3.0 by Gilles Audemard and Laurent Simon [default = %s]\n", fGlucose? "yes": "no" ); Abc_Print( -2, "\t-c : toggle using CaDiCaL by Armin Biere [default = %s]\n", fCadical? "yes": "no" ); + Abc_Print( -2, "\t-s : no printout except when a solution is found [default = %s]\n", fSilent? "yes": "no" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n\n"); Abc_Print( -2, "\t As an example of using this command, consider specification (the three-input AND-gate) and implementation\n"); @@ -51721,16 +51726,17 @@ usage: ***********************************************************************/ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Gia_Man_t * Gia_ManLutCasGen( int nVars, int nLuts, int LutSize, int Seed, int fVerbose ); - int nVars = 8; + extern Gia_Man_t * Gia_ManLutCasGen( Gia_Man_t * p, char * pPermStr, int nVars, int nLuts, int LutSize, int Seed, int fVerbose ); + int nVars = 0; int nLuts = 2; int LutSize = 6; int Seed = 0; int fVerbose = 0; int c; + char * pPermStr = NULL; Gia_Man_t * pTemp; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NMKSvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NMKSPvh" ) ) != EOF ) { switch ( c ) { @@ -51778,6 +51784,15 @@ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( Seed < 0 ) goto usage; break; + case 'P': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-P\" should be followed by a string.\n" ); + goto usage; + } + pPermStr = argv[globalUtilOptind]; + globalUtilOptind++; + break; case 'v': fVerbose ^= 1; break; @@ -51787,6 +51802,19 @@ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) goto usage; } } + if ( pAbc->pGia == NULL && nVars == 0 ) + { + Abc_Print( -1, "The number of inputs (%d) should be specified on the command line.\n", nVars ); + return 1; + } + if ( pAbc->pGia ) + nVars = Gia_ManCiNum(pAbc->pGia); + if ( pPermStr && (nLuts * LutSize != (int)strlen(pPermStr)) ) + { + Abc_Print( -1, "Permutation \"%s\" has %d symbols instead of expected %d = %d * %d symbols (LutSize * nLuts).\n", + pPermStr, (int)strlen(pPermStr), LutSize * nLuts, LutSize, nLuts ); + return 1; + } if ( nVars <= LutSize ) { Abc_Print( -1, "The number of inputs (%d) should be more than LUT size (%d).\n", nVars, LutSize ); @@ -51812,17 +51840,18 @@ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Function with %d variables is too large for a cascade composed of %d connected %d-LUTs.\n", nVars, nLuts, LutSize ); return 1; } - pTemp = Gia_ManLutCasGen( nVars, nLuts, LutSize, Seed, fVerbose ); + pTemp = Gia_ManLutCasGen( pAbc->pGia, pPermStr, nVars, nLuts, LutSize, Seed, fVerbose ); Abc_FrameUpdateGia( pAbc, pTemp ); return 0; usage: - Abc_Print( -2, "usage: &genlutcas[-NMKS num] [-vh]\n" ); - Abc_Print( -2, "\t generates single-rail LUT cascade\n" ); + Abc_Print( -2, "usage: &genlutcas[-NMKS num] [-P str] [-vh]\n" ); + Abc_Print( -2, "\t generates a miter for synthesizing the LUT cascade\n" ); Abc_Print( -2, "\t-N num : the number of primary inputs [default = %d]\n", nVars ); Abc_Print( -2, "\t-M num : the number of LUTs [default = %d]\n", nLuts ); Abc_Print( -2, "\t-K num : the LUT size [default = %d]\n", LutSize ); Abc_Print( -2, "\t-S num : the random seed [default = %d]\n", Seed ); + Abc_Print( -2, "\t-P str : variable permutation (for example, \"abcd_aef\" for S44) [default = %s]\n", pPermStr ? pPermStr : "unused" ); Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : print the command usage\n"); return 1; From ec70146d5dde9aba470d5da260463788c85d3917 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 22:47:23 -0800 Subject: [PATCH 13/38] Experiments with exact synthesis. --- src/sat/bmc/bmcMaj.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index b1e0309bb..e513861fe 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1063,7 +1063,7 @@ Vec_Wec_t * Exa3_ChooseInputVars_int( int nVars, int nLuts, int nLutSize ) Vec_Int_t * vLevel; int i; Vec_WecForEachLevel( p, vLevel, i ) { do { - int iVar = (Abc_Random(0) ^ Abc_Random(0) ^ Abc_Random(0)) % nVars; + int iVar = rand() % nVars; Vec_IntPushUniqueOrder( vLevel, iVar ); } while ( Vec_IntSize(vLevel) < nLutSize-(int)(i>0) ); @@ -1079,8 +1079,16 @@ Vec_Int_t * Exa3_CountInputVars( int nVars, Vec_Wec_t * p ) Vec_IntAddToEntry( vCounts, Obj, 1 ); return vCounts; } -Vec_Wec_t * Exa3_ChooseInputVars( int nVars, int nLuts, int nLutSize ) +Vec_Wec_t * Exa3_ChooseInputVars( int nVars, int nLuts, int nLutSize, int Seed ) { + if ( Seed ) + srand(Seed); + else { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + unsigned int seed = (unsigned int)(ts.tv_sec ^ ts.tv_nsec); + srand(seed); + } for ( int i = 0; i < 1000; i++ ) { Vec_Wec_t * p = Exa3_ChooseInputVars_int( nVars, nLuts, nLutSize ); Vec_Int_t * q = Exa3_CountInputVars( nVars, p ); @@ -1172,7 +1180,7 @@ static int Exa3_ManMarkup( Exa3_Man_t * p ) if ( p->pPars->pPermStr ) p->vInVars = Exa3_ChooseInputVars2( p->nVars, p->nNodes, p->nLutSize, p->pPars->pPermStr ); else - p->vInVars = Exa3_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize ); + p->vInVars = Exa3_ChooseInputVars( p->nVars, p->nNodes, p->nLutSize, p->pPars->Seed ); if ( !p->pPars->fSilent ) { Vec_Int_t * vLevel; int i, Var; printf( "Using fixed input assignment %s%s:\n", From 9e90e6086d1b35fd56e4c28f46f29de9ff9600a9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 11 Nov 2025 22:48:06 -0800 Subject: [PATCH 14/38] Updating .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9bd049424..bef9a6aa4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ lib/abc* lib/m114* lib/bip* docs/ -.vscode/ .cache/ src/ext* From 28f4ad82812bc83587d021437d159f96d5b3c61c Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 12 Nov 2025 10:04:10 -0800 Subject: [PATCH 15/38] New command &symfun. --- src/aig/gia/giaLutCas.c | 73 ++++++++++++++++++++++--- src/base/abci/abc.c | 111 +++++++++++++++++++++++++++++++++++++- src/misc/util/utilTruth.h | 40 +++++++++++++- 3 files changed, 214 insertions(+), 10 deletions(-) diff --git a/src/aig/gia/giaLutCas.c b/src/aig/gia/giaLutCas.c index 7465ad18c..c8f2026db 100644 --- a/src/aig/gia/giaLutCas.c +++ b/src/aig/gia/giaLutCas.c @@ -34,6 +34,65 @@ ABC_NAMESPACE_IMPL_START /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Gia_ManGenSymFun_rec( Gia_Man_t * p, word Str, int nChars, Vec_Ptr_t * vStrs, Vec_Wec_t * vLits, Vec_Int_t * vIns ) +{ + if ( Str == 0 ) return 0; + if ( Str == Abc_Tt6Mask(nChars) ) return 1; + assert( nChars > 1 ); + Vec_Wrd_t * vStore = (Vec_Wrd_t *)Vec_PtrEntry(vStrs, nChars-1); + Vec_Int_t * vValue = Vec_WecEntry(vLits, nChars-1); + int Index; + if ( (Index = Vec_WrdFind(vStore, Str)) >= 0 ) + return Vec_IntEntry(vValue, Index); + word Str0 = Str & ~Abc_Tt6MaskI(nChars-1); + word Str1 = Str >> 1; + int Lit0 = Gia_ManGenSymFun_rec( p, Str0, nChars-1, vStrs, vLits, vIns ); + int Lit1 = Gia_ManGenSymFun_rec( p, Str1, nChars-1, vStrs, vLits, vIns ); + int Lit = Gia_ManAppendMux2( p, Vec_IntEntry(vIns, nChars-2), Lit1, Lit0 ); + Vec_WrdPush( vStore, Str ); + Vec_WrdPush( vStore, ~Str & Abc_Tt6Mask(nChars) ); + Vec_IntPush( vValue, Lit ); + Vec_IntPush( vValue, Abc_LitNot(Lit) ); + return Lit; +} +Gia_Man_t * Gia_ManGenSymFun( Vec_Wrd_t * vFuns, int nChars, int fVerbose ) +{ + assert( nChars <= 64 ); + word Str; int i; + Vec_Ptr_t * vStrs = Vec_PtrAlloc(nChars); + for ( i = 0; i < nChars; i++ ) + Vec_PtrPush( vStrs, Vec_WrdAlloc(0) ); + Vec_Wec_t * vLits = Vec_WecStart(nChars); + Vec_Int_t * vOuts = Vec_IntAlloc(Vec_WrdSize(vFuns)); + Gia_Man_t * pNew = Gia_ManStart( 10000 ); + pNew->pName = Abc_UtilStrsav( "sym" ); + Vec_Int_t * vIns = Vec_IntAlloc(nChars-1); + for ( i = 0; i < nChars-1; i++ ) + Vec_IntPush(vIns, Gia_ManAppendCi(pNew)); + Vec_WrdForEachEntry( vFuns, Str, i ) + Vec_IntPush( vOuts, Gia_ManGenSymFun_rec(pNew, Str, nChars, vStrs, vLits, vIns ) ); + Vec_WrdForEachEntry( vFuns, Str, i ) + Gia_ManAppendCo(pNew, Vec_IntEntry(vOuts,i) ); + for ( i = 0; i < nChars; i++ ) + Vec_WrdFree( (Vec_Wrd_t *)Vec_PtrEntry(vStrs, i) ); + Vec_PtrFree(vStrs); + Vec_WecFree(vLits); + Vec_IntFree(vOuts); + Vec_IntFree(vIns); + return pNew; +} + /**Function************************************************************* Synopsis [] @@ -101,15 +160,15 @@ char * Gia_LutCasPerm( int nVars, int nLuts, int LutSize ) Gia_LutCasSort( pRes + i * LutSize, 1, LutSize-1 ); return pRes; } -int Gia_ManLutCasGen_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_Int_t * vDatas, int Shift ) +int Gia_ManGenLutCas_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_Int_t * vDatas, int Shift ) { if ( iCtrl-- == 0 ) return Vec_IntEntry( vDatas, Shift ); - int iLit0 = Gia_ManLutCasGen_rec( pNew, vCtrls, iCtrl, vDatas, Shift ); - int iLit1 = Gia_ManLutCasGen_rec( pNew, vCtrls, iCtrl, vDatas, Shift + (1<= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by a file name.\n" ); + goto usage; + } + nMaj = atoi(argv[globalUtilOptind++]); + break; + case 'H': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-H\" should be followed by a file name.\n" ); + goto usage; + } + nHot = atoi(argv[globalUtilOptind++]); + break; + case 'X': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-X\" should be followed by a file name.\n" ); + goto usage; + } + nXor = atoi(argv[globalUtilOptind++]); + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + default: + goto usage; + } + } + if ( nMaj ) { + nChars = nMaj+1; + vFuns = Vec_WrdAlloc(1); + Vec_WrdPush( vFuns, Abc_Tt6Mask(nMaj/2+1) << (nMaj/2+1) ); + } + else if ( nHot ) { + nChars = nHot+1; + vFuns = Vec_WrdAlloc(1); + Vec_WrdPush( vFuns, 2 ); + } + else if ( nXor ) { + nChars = nXor+1; + vFuns = Vec_WrdAlloc(1); + Vec_WrdPush( vFuns, ABC_CONST(0xAAAAAAAAAAAAAAAA) & Abc_Tt6Mask(nXor+1) ); + } + else { + if ( argc == globalUtilOptind ) { + printf( "One or more characteristic strings should be given on the command line.\n" ); + return 0; + } + nChars = (int)strlen(argv[globalUtilOptind]); + for ( c = globalUtilOptind+1; c < argc; c++ ) + if ( nChars != (int)strlen(argv[c]) ) { + printf( "Char strings have different lengths. Quitting.\n" ); + return 0; + } + vFuns = Vec_WrdAlloc( argc ); + for ( c = globalUtilOptind; c < argc; c++ ) + Vec_WrdPush( vFuns, Abc_TtReadBin64(argv[c]) ); + } + if ( nChars > 64 ) { + printf( "Currently can handle functions up to 63 inputs. Quitting.\n" ); + return 0; + } + pNew = Gia_ManGenSymFun( vFuns, nChars, fVerbose ); + Abc_FrameUpdateGia( pAbc, pNew ); + Vec_WrdFree( vFuns ); + return 0; + +usage: + Abc_Print( -2, "usage: &symfun [-MHX num] [-vh] ... \n" ); + Abc_Print( -2, "\t derives AIG of a multi-output symmetric function\n" ); + Abc_Print( -2, "\t-M : generate the majority gate with the given input count [default = unused]\n" ); + Abc_Print( -2, "\t-H : generate the 1-hot condition with the given input count [default = unused]\n" ); + Abc_Print( -2, "\t-X : generate the xor-gate with the given input count [default = unused]\n" ); + Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : prints the command usage\n"); + Abc_Print( -2, "\t ... : char strings in binary notation LSB first\n"); + return 1; +} + /**Function************************************************************* Synopsis [] @@ -51726,7 +51833,7 @@ usage: ***********************************************************************/ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) { - extern Gia_Man_t * Gia_ManLutCasGen( Gia_Man_t * p, char * pPermStr, int nVars, int nLuts, int LutSize, int Seed, int fVerbose ); + extern Gia_Man_t * Gia_ManGenLutCas( Gia_Man_t * p, char * pPermStr, int nVars, int nLuts, int LutSize, int Seed, int fVerbose ); int nVars = 0; int nLuts = 2; int LutSize = 6; @@ -51840,7 +51947,7 @@ int Abc_CommandAbc9GenLutCas( Abc_Frame_t * pAbc, int argc, char ** argv ) Abc_Print( -1, "Function with %d variables is too large for a cascade composed of %d connected %d-LUTs.\n", nVars, nLuts, LutSize ); return 1; } - pTemp = Gia_ManLutCasGen( pAbc->pGia, pPermStr, nVars, nLuts, LutSize, Seed, fVerbose ); + pTemp = Gia_ManGenLutCas( pAbc->pGia, pPermStr, nVars, nLuts, LutSize, Seed, fVerbose ); Abc_FrameUpdateGia( pAbc, pTemp ); return 0; diff --git a/src/misc/util/utilTruth.h b/src/misc/util/utilTruth.h index c9d453d06..d94e9bfe2 100644 --- a/src/misc/util/utilTruth.h +++ b/src/misc/util/utilTruth.h @@ -230,7 +230,8 @@ static inline int Abc_TtHexDigitNum( int nVars ) { return nVars <= 2 ? 1 : 1 << SeeAlso [] ***********************************************************************/ -static inline word Abc_Tt6Mask( int nBits ) { assert( nBits >= 0 && nBits <= 64 ); return (~(word)0) >> (64-nBits); } +static inline word Abc_Tt6MaskI( int iBit ) { assert( iBit >= 0 && iBit <= 64 ); return ((word)1) << iBit; } +static inline word Abc_Tt6Mask( int nBits ) { assert( nBits >= 0 && nBits <= 64 ); return (~(word)0) >> (64-nBits); } static inline void Abc_TtMask( word * pTruth, int nWords, int nBits ) { int w; @@ -1579,6 +1580,43 @@ static inline int Abc_TtReadHexNumber( word * pTruth, char * pString ) } +/**Function************************************************************* + + Synopsis [Reads the integer number as a binary string.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +static inline int Abc_TtReadBin( word * pWords, int nWords, char * pString ) +{ + int i, Len = (int)strlen(pString), nWords2 = (Len+63)/64; + assert( nWords2 <= nWords ); + memset( pWords, 0, sizeof(word)*nWords ); + for ( i = 0; i < Len; i++ ) + if ( pString[i] == '1' ) + Abc_TtSetBit(pWords, i); + else if ( pString[i] != '0' ) + return 0; + return 1; +} +static inline word Abc_TtReadBin64( char * pString ) +{ + word Word = 0; + int Len = (int)strlen(pString); + assert( Len <= 64 ); + int Res = Abc_TtReadBin( &Word, 1, pString ); + if ( Res == 0 ) { + printf( "Reading binary string \"%s\" has failed.\n", pString ); + Word = ~(word)0; + } + return Word; +} + + /**Function************************************************************* Synopsis [] From 5ade9e9dfb4dbdca3a8e233bbeaeb4bec7eccb98 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Wed, 12 Nov 2025 15:19:38 -0800 Subject: [PATCH 16/38] Adding command line option of &symfun. --- src/base/abci/abc.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 563000706..0ddca29d4 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -45535,9 +45535,9 @@ int Abc_CommandAbc9SymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) extern Gia_Man_t * Gia_ManGenSymFun( Vec_Wrd_t * vFuns, int nChars, int fVerbose ); Gia_Man_t * pNew = NULL; Vec_Wrd_t * vFuns = NULL; - int c, nChars = 0, nMaj = 0, nHot = 0, nXor = 0, fVerbose = 0; + int c, nChars = 0, nMaj = 0, nHot = 0, nXor = 0, nWgt = 0, fVerbose = 0; Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "MHXvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "MHXWvh" ) ) != EOF ) { switch ( c ) { @@ -45565,6 +45565,14 @@ int Abc_CommandAbc9SymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) } nXor = atoi(argv[globalUtilOptind++]); break; + case 'W': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-W\" should be followed by a file name.\n" ); + goto usage; + } + nWgt = atoi(argv[globalUtilOptind++]); + break; case 'v': fVerbose ^= 1; break; @@ -45586,7 +45594,14 @@ int Abc_CommandAbc9SymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) else if ( nXor ) { nChars = nXor+1; vFuns = Vec_WrdAlloc(1); - Vec_WrdPush( vFuns, ABC_CONST(0xAAAAAAAAAAAAAAAA) & Abc_Tt6Mask(nXor+1) ); + Vec_WrdPush( vFuns, s_Truths6[0] & Abc_Tt6Mask(nChars) ); + } + else if ( nWgt ) { + int nOuts = Abc_Base2Log(nWgt+1); + nChars = nWgt+1; + vFuns = Vec_WrdAlloc(nOuts); + for ( int i = 0; i < nOuts; i++ ) + Vec_WrdPush( vFuns, s_Truths6[i] & Abc_Tt6Mask(nChars) ); } else { if ( argc == globalUtilOptind ) { @@ -45613,11 +45628,12 @@ int Abc_CommandAbc9SymFun( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: &symfun [-MHX num] [-vh] ... \n" ); + Abc_Print( -2, "usage: &symfun [-MHXW num] [-vh] ... \n" ); Abc_Print( -2, "\t derives AIG of a multi-output symmetric function\n" ); Abc_Print( -2, "\t-M : generate the majority gate with the given input count [default = unused]\n" ); Abc_Print( -2, "\t-H : generate the 1-hot condition with the given input count [default = unused]\n" ); Abc_Print( -2, "\t-X : generate the xor-gate with the given input count [default = unused]\n" ); + Abc_Print( -2, "\t-W : generate the weight(W) function with the given input count [default = unused]\n" ); Abc_Print( -2, "\t-v : toggles verbose output [default = %s]\n", fVerbose? "yes": "no" ); Abc_Print( -2, "\t-h : prints the command usage\n"); Abc_Print( -2, "\t ... : char strings in binary notation LSB first\n"); From b1c73c160c9aeff24f0a2609b2bdb136e4437c70 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Nov 2025 07:32:08 -0800 Subject: [PATCH 17/38] Fixing a valgrind warning. --- src/aig/gia/giaTsim.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/aig/gia/giaTsim.c b/src/aig/gia/giaTsim.c index 7f93c5426..1920cd6d3 100644 --- a/src/aig/gia/giaTsim.c +++ b/src/aig/gia/giaTsim.c @@ -84,9 +84,11 @@ Gia_ManTer_t * Gia_ManTerCreate( Gia_Man_t * pAig ) p = ABC_CALLOC( Gia_ManTer_t, 1 ); p->pAig = Gia_ManFront( pAig ); p->nIters = 300; - p->pDataSim = ABC_ALLOC( unsigned, Abc_BitWordNum(2*p->pAig->nFront) ); - p->pDataSimCis = ABC_ALLOC( unsigned, Abc_BitWordNum(2*Gia_ManCiNum(p->pAig)) ); - p->pDataSimCos = ABC_ALLOC( unsigned, Abc_BitWordNum(2*Gia_ManCoNum(p->pAig)) ); + // these buffers are accessed through XOR-based setters that read the current word first, + // so they must be zero-initialized to avoid touching undefined data on the first update + p->pDataSim = ABC_CALLOC( unsigned, Abc_BitWordNum(2*p->pAig->nFront) ); + p->pDataSimCis = ABC_CALLOC( unsigned, Abc_BitWordNum(2*Gia_ManCiNum(p->pAig)) ); + p->pDataSimCos = ABC_CALLOC( unsigned, Abc_BitWordNum(2*Gia_ManCoNum(p->pAig)) ); // allocate storage for terminary states p->nStateWords = Abc_BitWordNum( 2*Gia_ManRegNum(pAig) ); p->vStates = Vec_PtrAlloc( 1000 ); @@ -754,4 +756,3 @@ Gia_Man_t * Gia_ManReduceConst( Gia_Man_t * pAig, int fVerbose ) ABC_NAMESPACE_IMPL_END - From 6534475fa1bd39a991da4dc113138f80cfab0bc0 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Nov 2025 07:50:10 -0800 Subject: [PATCH 18/38] Fixing a non-reproducibility issue in "lutmin". --- src/base/abci/abcLutmin.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/base/abci/abcLutmin.c b/src/base/abci/abcLutmin.c index 449bbd512..b23b8bfa9 100644 --- a/src/base/abci/abcLutmin.c +++ b/src/base/abci/abcLutmin.c @@ -1083,8 +1083,10 @@ Abc_Obj_t * Abc_NtkBddDecompose( Abc_Ntk_t * pNtkNew, Abc_Obj_t * pNode, int nLu } // cofactor w.r.t. the bound set variables vCofs = Abc_NtkBddCofactors( dd, (DdNode *)pNode->pData, nLutSize ); - vUniq = Vec_PtrDup( vCofs ); - Vec_PtrUniqify( vUniq, (int (*)(const void *, const void *))Vec_PtrSortCompare ); + // collect unique cofactors in the order they appear + vUniq = Vec_PtrAlloc( Vec_PtrSize(vCofs) ); + Vec_PtrForEachEntry( DdNode *, vCofs, bCof, i ) + Vec_PtrPushUnique( vUniq, bCof ); // only perform decomposition which it is support reducing with two less vars if( Vec_PtrSize(vUniq) > (1 << (nLutSize-2)) ) { @@ -1257,4 +1259,3 @@ void Abc_NtkBddDecExplore( Abc_Obj_t * pNode ) {} ABC_NAMESPACE_IMPL_END - From 6f5c46632d74e1e636fe0f4189dae6c53d78c2a5 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 13 Nov 2025 08:12:11 -0800 Subject: [PATCH 19/38] Fixing another non-reproducibility issue. --- src/base/abc/abc.h | 2 +- src/base/abc/abcUtil.c | 30 ++++++++++-------------------- src/base/abci/abcSweep.c | 4 +--- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/base/abc/abc.h b/src/base/abc/abc.h index b23905dd3..0b0376c47 100644 --- a/src/base/abc/abc.h +++ b/src/base/abc/abc.h @@ -1046,7 +1046,7 @@ extern ABC_DLL Vec_Int_t * Abc_NtkFanoutCounts( Abc_Ntk_t * pNtk ); extern ABC_DLL Vec_Ptr_t * Abc_NtkCollectObjects( Abc_Ntk_t * pNtk ); extern ABC_DLL Vec_Int_t * Abc_NtkGetCiIds( Abc_Ntk_t * pNtk ); extern ABC_DLL void Abc_NtkReassignIds( Abc_Ntk_t * pNtk ); -extern ABC_DLL int Abc_ObjPointerCompare( void ** pp1, void ** pp2 ); +// extern ABC_DLL int Abc_ObjPointerCompare( void ** pp1, void ** pp2 ); extern ABC_DLL void Abc_NtkTransferCopy( Abc_Ntk_t * pNtk ); extern ABC_DLL void Abc_NtkInvertConstraints( Abc_Ntk_t * pNtk ); extern ABC_DLL void Abc_NtkPrintCiLevels( Abc_Ntk_t * pNtk ); diff --git a/src/base/abc/abcUtil.c b/src/base/abc/abcUtil.c index fddc04beb..e5bf337b2 100644 --- a/src/base/abc/abcUtil.c +++ b/src/base/abc/abcUtil.c @@ -1925,25 +1925,16 @@ void Abc_NtkDetectMatching( Abc_Ntk_t * pNtk ) } -/**Function************************************************************* - - Synopsis [Compares the pointers.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -int Abc_ObjPointerCompare( void ** pp1, void ** pp2 ) -{ - if ( *pp1 < *pp2 ) - return -1; - if ( *pp1 > *pp2 ) - return 1; - return 0; -} +/// The legacy `Abc_ObjPointerCompare()` comparator is unused; keep the code here +/// commented to document its previous behavior without exposing a prototype. +// int Abc_ObjPointerCompare( void ** pp1, void ** pp2 ) +// { +// if ( *pp1 < *pp2 ) +// return -1; +// if ( *pp1 > *pp2 ) +// return 1; +// return 0; +// } /**Function************************************************************* @@ -3564,4 +3555,3 @@ void Abc_NtkATMap( int nXVars, int nYVars, int nAdder, char ** pGPCs0, int nGPCs ABC_NAMESPACE_IMPL_END - diff --git a/src/base/abci/abcSweep.c b/src/base/abci/abcSweep.c index 3306a6af8..2709bc458 100644 --- a/src/base/abci/abcSweep.c +++ b/src/base/abci/abcSweep.c @@ -885,10 +885,9 @@ int Abc_NtkReplaceAutonomousLogic( Abc_Ntk_t * pNtk ) continue; } assert( !Abc_ObjIsLatch(pFanin) ); - Vec_PtrPush( vNodes, pFanin ); + Vec_PtrPushUnique( vNodes, pFanin ); } } - Vec_PtrUniqify( vNodes, (int (*)(const void *, const void *))Abc_ObjPointerCompare ); // replace these nodes by the PIs Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i ) { @@ -1027,4 +1026,3 @@ int Abc_NtkSweepBufsInvs( Abc_Ntk_t * pNtk, int fVerbose ) ABC_NAMESPACE_IMPL_END - From b319f57dde0f41bb4119de65f3553dfbbf4c3e50 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 17 Nov 2025 16:39:13 -0800 Subject: [PATCH 20/38] Addressing platform-dependent computations in the CUDD package. --- src/bdd/cudd/cuddGroup.c | 5 ++--- src/bdd/cudd/cuddLinear.c | 5 ++--- src/bdd/cudd/cuddReorder.c | 5 ++--- src/bdd/cudd/cuddSymmetry.c | 5 ++--- src/bdd/cudd/cuddZddGroup.c | 5 ++--- src/bdd/cudd/cuddZddReord.c | 6 +++++- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bdd/cudd/cuddGroup.c b/src/bdd/cudd/cuddGroup.c index d916ed5a3..4d5308a3c 100644 --- a/src/bdd/cudd/cuddGroup.c +++ b/src/bdd/cudd/cuddGroup.c @@ -679,11 +679,11 @@ ddUniqueCompareGroup( int * ptrX, int * ptrY) { -#if 0 +//#if 0 if (entry[*ptrY] == entry[*ptrX]) { return((*ptrX) - (*ptrY)); } -#endif +//#endif return(entry[*ptrY] - entry[*ptrX]); } /* end of ddUniqueCompareGroup */ @@ -2170,4 +2170,3 @@ ddIsVarHandled( ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/cudd/cuddLinear.c b/src/bdd/cudd/cuddLinear.c index b38ea7294..6ac8ef833 100644 --- a/src/bdd/cudd/cuddLinear.c +++ b/src/bdd/cudd/cuddLinear.c @@ -873,11 +873,11 @@ ddLinearUniqueCompare( int * ptrX, int * ptrY) { -#if 0 +//#if 0 if (entry[*ptrY] == entry[*ptrX]) { return((*ptrX) - (*ptrY)); } -#endif +//#endif return(entry[*ptrY] - entry[*ptrX]); } /* end of ddLinearUniqueCompare */ @@ -1370,4 +1370,3 @@ cuddXorLinear( ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/cudd/cuddReorder.c b/src/bdd/cudd/cuddReorder.c index e5aa86716..aac99b5ff 100644 --- a/src/bdd/cudd/cuddReorder.c +++ b/src/bdd/cudd/cuddReorder.c @@ -1325,11 +1325,11 @@ ddUniqueCompare( int * ptrX, int * ptrY) { -#if 0 +//#if 0 if (entry[*ptrY] == entry[*ptrX]) { return((*ptrX) - (*ptrY)); } -#endif +//#endif return(entry[*ptrY] - entry[*ptrX]); } /* end of ddUniqueCompare */ @@ -2140,4 +2140,3 @@ ddCheckPermuation( ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/cudd/cuddSymmetry.c b/src/bdd/cudd/cuddSymmetry.c index 310286c4a..490428f06 100644 --- a/src/bdd/cudd/cuddSymmetry.c +++ b/src/bdd/cudd/cuddSymmetry.c @@ -609,11 +609,11 @@ ddSymmUniqueCompare( int * ptrX, int * ptrY) { -#if 0 +//#if 0 if (entry[*ptrY] == entry[*ptrX]) { return((*ptrX) - (*ptrY)); } -#endif +//#endif return(entry[*ptrY] - entry[*ptrX]); } /* end of ddSymmUniqueCompare */ @@ -1703,4 +1703,3 @@ ddSymmSummary( ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/cudd/cuddZddGroup.c b/src/bdd/cudd/cuddZddGroup.c index 67f9472f1..fc57132fa 100644 --- a/src/bdd/cudd/cuddZddGroup.c +++ b/src/bdd/cudd/cuddZddGroup.c @@ -610,11 +610,11 @@ zddUniqueCompareGroup( int * ptrX, int * ptrY) { -#if 0 +//#if 0 if (entry[*ptrY] == entry[*ptrX]) { return((*ptrX) - (*ptrY)); } -#endif +//#endif return(entry[*ptrY] - entry[*ptrX]); } /* end of zddUniqueCompareGroup */ @@ -1341,4 +1341,3 @@ zddMergeGroups( ABC_NAMESPACE_IMPL_END - diff --git a/src/bdd/cudd/cuddZddReord.c b/src/bdd/cudd/cuddZddReord.c index c195f5b56..6943cbc89 100644 --- a/src/bdd/cudd/cuddZddReord.c +++ b/src/bdd/cudd/cuddZddReord.c @@ -460,6 +460,11 @@ cuddZddUniqueCompare( int * ptr_x, int * ptr_y) { +//#if 0 + if (zdd_entry[*ptr_y] == zdd_entry[*ptr_x]) { + return((*ptr_x) - (*ptr_y)); + } +//#endif return(zdd_entry[*ptr_y] - zdd_entry[*ptr_x]); } /* end of cuddZddUniqueCompare */ @@ -1665,4 +1670,3 @@ zddFixTree( ABC_NAMESPACE_IMPL_END - From 309282601e0b8337e982016fe7dbb376177bde56 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Mon, 17 Nov 2025 21:37:51 -0800 Subject: [PATCH 21/38] Experiments with LUT mapping. --- src/aig/gia/giaAiger.c | 12 ++--- src/aig/gia/giaIf.c | 99 +++++++++++++++++------------------------- src/map/if/ifTune.c | 92 +++++++++++++-------------------------- 3 files changed, 78 insertions(+), 125 deletions(-) diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index 3c44a566d..76ae3df3f 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -1583,11 +1583,11 @@ void Gia_AigerWriteS( Gia_Man_t * pInit, char * pFileName, int fWriteSymbols, in { unsigned char CellId = (unsigned char)Vec_StrEntry(p->vConfigs2, i); if ( CellId == 0 ) - i += 4; // 1 byte CellId + 2 bytes truth table + 1 padding + i += 7; // 1 byte CellId + 4 bytes mapping + 2 bytes truth table else if ( CellId == 1 ) - i += 12; // 1 byte CellId + 4 bytes mapping + 4 bytes truth tables + 3 padding + i += 12; // 1 byte CellId + 7 bytes mapping + 4 bytes truth tables else if ( CellId == 2 ) - i += 12; // 1 byte CellId + 5 bytes mapping + 4 bytes truth tables + 2 padding + i += 14; // 1 byte CellId + 9 bytes mapping + 4 bytes truth tables else assert( 0 ); // Unknown cell type nInstances++; @@ -1619,15 +1619,15 @@ void Gia_AigerWriteS( Gia_Man_t * pInit, char * pFileName, int fWriteSymbols, in // Write cell type 0 (LUT4) Gia_FileWriteBufferSize( pFile, 0 ); // CellId fwrite( pCell0, 1, strlen(pCell0) + 1, pFile ); - Gia_FileWriteBufferSize( pFile, 4 ); // 1 byte CellId + 2 bytes truth table, rounded to 4 + Gia_FileWriteBufferSize( pFile, 7 ); // 1 byte CellId + 4 bytes mapping + 2 bytes truth table // Write cell type 1 (S44) Gia_FileWriteBufferSize( pFile, 1 ); // CellId fwrite( pCell1, 1, strlen(pCell1) + 1, pFile ); - Gia_FileWriteBufferSize( pFile, 12 ); // 1 byte CellId + 4 bytes mapping + 4 bytes truth tables, rounded to 12 + Gia_FileWriteBufferSize( pFile, 12 ); // 1 byte CellId + 7 bytes mapping + 4 bytes truth tables // Write cell type 2 (9-input) Gia_FileWriteBufferSize( pFile, 2 ); // CellId fwrite( pCell2, 1, strlen(pCell2) + 1, pFile ); - Gia_FileWriteBufferSize( pFile, 12 ); // 1 byte CellId + 5 bytes mapping + 4 bytes truth tables (LUT4s only), rounded to 12 + Gia_FileWriteBufferSize( pFile, 14 ); // 1 byte CellId + 9 bytes mapping + 4 bytes truth tables // Write total instances Gia_FileWriteBufferSize( pFile, nInstances ); // Write instance data as raw bytes diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index 0ffc015b2..bf8293576 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -2016,73 +2016,73 @@ void Gia_ManConfigPrint( word Truth4, word z, int nLeaves ) ***********************************************************************/ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * pTruth, int nLeaves ) { - int i, CellId, nBytes; + int i, CellId; int startPos = Vec_StrSize(vConfigs2); // Determine cell type based on the number of leaves and configuration - if ( nLeaves <= 4 ) + if ( nLeaves <= 4 ) // 7 bytes = 1 byte CellId + 4 bytes mapping + 2 bytes truth table { // Cell type 0: Simple LUT4 CellId = 0; - nBytes = 3; // 1 byte CellId + 2 bytes truth table (16 bits) // Write CellId Vec_StrPush( vConfigs2, (char)CellId ); + // Write mapping + for ( i = 0; i < nLeaves; i++ ) + Vec_StrPush( vConfigs2, 2+i ); + for ( ; i < 4; i++ ) + Vec_StrPush( vConfigs2, 0 ); // Write truth table (16 bits for LUT4) word Truth = pTruth[0]; - Vec_StrPush( vConfigs2, (char)(Truth & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth >> 8) & 0xFF) ); - // Pad to 4-byte boundary - while ( (Vec_StrSize(vConfigs2) - startPos) % 4 != 0 ) - Vec_StrPush( vConfigs2, 0 ); - //Gia_ManConfigPrint( Truth, 0, pCutBest->nLeaves ); + Vec_StrPush( vConfigs2, (char)(Truth & 0xFF) ); + assert( startPos + 7 == Vec_StrSize(vConfigs2) ); + //Gia_ManConfigPrint( Truth, 0, nLeaves ); } - else + else // 12 bytes = 1 byte CellId + 7 bytes mapping + 4 bytes truth tables { word z = If_CutPerformDeriveJ( pIfMan, (unsigned *)pTruth, nLeaves, nLeaves, NULL, 1 ); - //Gia_ManConfigPrint( 0, z, pCutBest->nLeaves ); + //Gia_ManConfigPrint( 0, z, nLeaves ); if ( ((z >> 63) & 1) == 0 ) { CellId = 1; - unsigned char mappingBytes[4] = {0}; - // Write CellId Vec_StrPush( vConfigs2, (char)CellId ); - // Write input mappings for first LUT4 (4 inputs) + // Write input mapping for ( i = 0; i < 4; i++ ) { int v = (int)((z >> (16 + (i << 2))) & 7); if ( v == 6 && nLeaves == 5 ) - mappingBytes[i / 2] |= (0 << ((i % 2) * 4)); // constant 0 + Vec_StrPush( vConfigs2, 0 ); else - mappingBytes[i / 2] |= ((v+2) << ((i % 2) * 4)); // leaf v (direct mapping) + Vec_StrPush( vConfigs2, 2+v ); } - Vec_StrPush( vConfigs2, (char)mappingBytes[0] ); - Vec_StrPush( vConfigs2, (char)mappingBytes[1] ); - // Write input mappings for second LUT4 (4 inputs) - mappingBytes[0] = mappingBytes[1] = 0; + int iSpecial = -1; for ( i = 0; i < 4; i++ ) { int v = (int)((z >> (48 + (i << 2))) & 7); if ( v == 6 && nLeaves == 5 ) - mappingBytes[i / 2] |= (0 << ((i % 2) * 4)); // constant 0 + Vec_StrPush( vConfigs2, 0 ); + else if ( v != 7 ) + Vec_StrPush( vConfigs2, 2+v ); else if ( v == 7 ) - mappingBytes[i / 2] |= ((7+2) << ((i % 2) * 4)); // output of first LUT at index N+2 where N=7 - else - mappingBytes[i / 2] |= ((v+2) << ((i % 2) * 4)); // leaf v (direct mapping) + iSpecial = i; } - Vec_StrPush( vConfigs2, (char)mappingBytes[0] ); - Vec_StrPush( vConfigs2, (char)mappingBytes[1] ); + // Transform the truth table + assert( iSpecial >= 0 ); + word Truth = (z >> 32) & 0xFFFF; + Truth = Abc_Tt6Stretch( Truth, 4 ); + for ( int v = iSpecial; v < 3; v++ ) + Truth = Abc_Tt6SwapAdjacent( Truth, v ); // Write truth tables word Truth1 = z & 0xFFFF; - word Truth2 = (z >> 32) & 0xFFFF; - Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); + //word Truth2 = (z >> 32) & 0xFFFF; + word Truth2 = Truth & 0xFFFF; Vec_StrPush( vConfigs2, (char)((Truth1 >> 8) & 0xFF) ); - Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); + Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth2 >> 8) & 0xFF) ); - // Pad to 4-byte boundary - while ( (Vec_StrSize(vConfigs2) - startPos) % 4 != 0 ) - Vec_StrPush( vConfigs2, 0 ); + Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); + assert( startPos + 12 == Vec_StrSize(vConfigs2) ); } - else + else // 14 bytes = 1 byte CellId + 9 bytes mapping + 4 bytes truth tables { CellId = 2; int Pla2Var[9]; @@ -2090,39 +2090,22 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p If_PermUnpack( (unsigned)(z >> 32), Pla2Var ); // Write CellId Vec_StrPush( vConfigs2, (char)CellId ); - // Write input mappings (9 inputs, 4 bits each, packed) - unsigned char mappingByte = 0; - int bitPos = 0; + // Write input mapping for ( i = 0; i < 9; i++ ) { - int v; - if ( Pla2Var[i] == 9 ) // constant 0 - v = 0; - else // leaf index - v = Pla2Var[i] + 2; - if ( bitPos == 0 ) { - mappingByte = v & 0xF; - bitPos = 4; - } - else { - mappingByte |= (v & 0xF) << 4; - Vec_StrPush( vConfigs2, (char)mappingByte ); - bitPos = 0; - } - } - // Push last byte if needed - if ( bitPos != 0 ) - Vec_StrPush( vConfigs2, (char)mappingByte ); + if ( Pla2Var[i] == 9 ) + Vec_StrPush( vConfigs2, 0 ); + else + Vec_StrPush( vConfigs2, Pla2Var[i] + 2 ); + } // Write truth tables for the two LUT4s only (MUX is structural, not a LUT) word Truth1 = z & 0xFFFF; word Truth2 = (z >> 16) & 0xFFFF; - Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth1 >> 8) & 0xFF) ); - Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); + Vec_StrPush( vConfigs2, (char)(Truth1 & 0xFF) ); Vec_StrPush( vConfigs2, (char)((Truth2 >> 8) & 0xFF) ); - // Pad to 4-byte boundary - while ( (Vec_StrSize(vConfigs2) - startPos) % 4 != 0 ) - Vec_StrPush( vConfigs2, 0 ); + Vec_StrPush( vConfigs2, (char)(Truth2 & 0xFF) ); + assert( startPos + 14 == Vec_StrSize(vConfigs2) ); } } } diff --git a/src/map/if/ifTune.c b/src/map/if/ifTune.c index 47d90b4fd..98bdf8c25 100644 --- a/src/map/if/ifTune.c +++ b/src/map/if/ifTune.c @@ -911,12 +911,15 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) printf( "[%4d] ", Count++ ); // Print instance number if ( CellId == 0 ) { + assert( nLeaves <= 4 ); // Extract 16-bit truth table - word Truth = ((word)pConfigData[2] << 8) | pConfigData[1]; + word Truth = ((word)pConfigData[5] << 8) | pConfigData[6]; printf( "%04lX{", (unsigned long)Truth ); // Print as simple {abcd} since it's just a direct LUT4 - for ( i = 0; i < nLeaves && i < 4; i++ ) + for ( i = 0; i < nLeaves; i++ ) printf( "%c", 'a' + i ); + for ( ; i < 4; i++ ) + printf( "%c", '0' ); printf( "}" ); // Pad with spaces if less than 4 inputs for ( i = nLeaves; i < 4; i++ ) @@ -926,11 +929,11 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) else if ( CellId == 1 ) { // First LUT4 - word Truth1 = ((word)pConfigData[6] << 8) | pConfigData[5]; + word Truth1 = ((word)pConfigData[8] << 8) | pConfigData[9]; printf( "h=%04lX{", (unsigned long)Truth1 ); for ( i = 0; i < 4; i++ ) { - int v = (pConfigData[1 + i/2] >> ((i%2) * 4)) & 0xF; + int v = pConfigData[1+i]; if ( v == 0 ) printf( "0"); else if ( v == 1 ) @@ -942,11 +945,11 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) } printf( "} "); // Second LUT4 - word Truth2 = ((word)pConfigData[8] << 8) | pConfigData[7]; + word Truth2 = ((word)pConfigData[10] << 8) | pConfigData[11]; printf( "i=%04lX{", (unsigned long)Truth2 ); - for ( i = 0; i < 4; i++ ) + for ( i = 4; i < 7; i++ ) { - int v = (pConfigData[3 + i/2] >> ((i%2) * 4)) & 0xF; + int v = pConfigData[1+i]; if ( v == 0 ) printf( "0"); else if ( v == 1 ) @@ -958,32 +961,16 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) else printf( "?"); } - printf( "} [Cell %d, %d leaves]\n", CellId, nLeaves ); + printf( "h} [Cell %d, %d leaves]\n", CellId, nLeaves ); } else if ( CellId == 2 ) { - // Extract 9 input mappings - int inputs[9]; - int bitPos = 0; - for ( i = 0; i < 9; i++ ) - { - if ( bitPos == 0 ) - { - inputs[i] = pConfigData[1 + i/2] & 0xF; - bitPos = 4; - } - else - { - inputs[i] = (pConfigData[1 + i/2] >> 4) & 0xF; - bitPos = 0; - } - } // First LUT4 - word Truth1 = ((word)pConfigData[7] << 8) | pConfigData[6]; + word Truth1 = ((word)pConfigData[10] << 8) | pConfigData[11]; printf( "j=%04lX{", (unsigned long)Truth1 ); for ( i = 0; i < 4; i++ ) { - int v = inputs[i]; + int v = pConfigData[1+i]; if ( v == 0 ) printf( "0"); else if ( v == 1 ) @@ -995,11 +982,11 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) } printf( "} "); // Second LUT4 - word Truth2 = ((word)pConfigData[9] << 8) | pConfigData[8]; + word Truth2 = ((word)pConfigData[12] << 8) | pConfigData[13]; printf( "k=%04lX{", (unsigned long)Truth2 ); for ( i = 4; i < 8; i++ ) { - int v = inputs[i]; + int v = pConfigData[1+i]; if ( v == 0 ) printf( "0"); else if ( v == 1 ) @@ -1012,7 +999,7 @@ void If_ManConfigPrint( unsigned char * pConfigData, int nLeaves ) printf( "} "); // final node printf( "l=<"); - int v = inputs[8]; + int v = pConfigData[1+8]; if ( v == 0 ) printf( "0"); else if ( v == 1 ) @@ -1087,11 +1074,11 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) if ( CellId == 0 ) { // Extract 16-bit truth table - word Truth = ((word)pConfigData[2] << 8) | pConfigData[1]; + word Truth = ((word)pConfigData[5] << 8) | pConfigData[6]; Truth = Abc_Tt6Stretch( Truth, 4 ); extern int Kit_TruthToGia( Gia_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash ); Gia_ManObj(p, iLut)->Value = Kit_TruthToGia( pNew, (unsigned *)&Truth, Vec_IntSize(vLeaves), vCover, vLeaves, 1 ); - bytePos += 4; // 1 byte CellId + 2 bytes truth table + 1 padding + bytePos += 7; // 1 byte CellId + 4 bytes mapping + 2 bytes truth table } else if ( CellId == 1 ) { @@ -1101,7 +1088,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) Vec_IntClear( vLeavesTemp ); for ( i = 0; i < 4; i++ ) { - int v = (pConfigData[1 + i/2] >> ((i%2) * 4)) & 0xF; + int v = pConfigData[1+i]; if ( v == 0 ) Vec_IntPush( vLeavesTemp, 0 ); // constant 0 else if ( v == 1 ) @@ -1111,58 +1098,41 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) else assert( 0 ); // Invalid value } - word Truth1 = ((word)pConfigData[6] << 8) | pConfigData[5]; + word Truth1 = ((word)pConfigData[8] << 8) | pConfigData[9]; Truth1 = Abc_Tt6Stretch( Truth1, 4 ); extern int Kit_TruthToGia( Gia_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash ); iObjLit1 = Kit_TruthToGia( pNew, (unsigned *)&Truth1, Vec_IntSize(vLeavesTemp), vCover, vLeavesTemp, 1 ); // Second LUT4 - extract inputs and truth table Vec_IntClear( vLeavesTemp ); - for ( i = 0; i < 4; i++ ) + for ( i = 4; i < 7; i++ ) { - int v = (pConfigData[3 + i/2] >> ((i%2) * 4)) & 0xF; + int v = pConfigData[1+i]; if ( v == 0 ) Vec_IntPush( vLeavesTemp, 0 ); // constant 0 else if ( v == 1 ) Vec_IntPush( vLeavesTemp, 1 ); // constant 1 else if ( v >= 2 && v < 2 + Vec_IntSize(vLeaves) ) Vec_IntPush( vLeavesTemp, Vec_IntEntry(vLeaves, v - 2) ); // leaf (v-2) - else if ( v == 9 ) // N+2 where N=7 (number of S44 inputs) - Vec_IntPush( vLeavesTemp, iObjLit1 ); // output of first LUT (internal connection) else assert( 0 ); // Invalid value } - word Truth2 = ((word)pConfigData[8] << 8) | pConfigData[7]; + Vec_IntPush( vLeavesTemp, iObjLit1 ); // output of first LUT (internal connection) + word Truth2 = ((word)pConfigData[10] << 8) | pConfigData[11]; Truth2 = Abc_Tt6Stretch( Truth2, 4 ); iObjLit2 = Kit_TruthToGia( pNew, (unsigned *)&Truth2, Vec_IntSize(vLeavesTemp), vCover, vLeavesTemp, 1 ); Gia_ManObj(p, iLut)->Value = iObjLit2; Vec_IntFree( vLeavesTemp ); - bytePos += 12; // 1 byte CellId + 4 bytes mapping + 4 bytes truth tables + 3 padding + bytePos += 12; // 1 byte CellId + 7 bytes mapping + 4 bytes truth tables } else if ( CellId == 2 ) { Vec_Int_t * vLeavesTemp = Vec_IntAlloc( 4 ); int iObjLit1, iObjLit2, iObjLit3; - // Extract 9 input mappings (4 bits each, packed) - int inputs[9]; - int bitPos = 0; - for ( i = 0; i < 9; i++ ) - { - if ( bitPos == 0 ) - { - inputs[i] = pConfigData[1 + i/2] & 0xF; - bitPos = 4; - } - else - { - inputs[i] = (pConfigData[1 + i/2] >> 4) & 0xF; - bitPos = 0; - } - } // First LUT4 (inputs 0-3) Vec_IntClear( vLeavesTemp ); for ( i = 0; i < 4; i++ ) { - int v = inputs[i]; + int v = pConfigData[1+i]; if ( v == 0 ) Vec_IntPush( vLeavesTemp, 0 ); // constant 0 else if ( v == 1 ) @@ -1172,7 +1142,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) else assert( 0 ); // Invalid value } - word Truth1 = ((word)pConfigData[7] << 8) | pConfigData[6]; + word Truth1 = ((word)pConfigData[10] << 8) | pConfigData[11]; Truth1 = Abc_Tt6Stretch( Truth1, 4 ); extern int Kit_TruthToGia( Gia_Man_t * pMan, unsigned * pTruth, int nVars, Vec_Int_t * vMemory, Vec_Int_t * vLeaves, int fHash ); iObjLit1 = Kit_TruthToGia( pNew, (unsigned *)&Truth1, Vec_IntSize(vLeavesTemp), vCover, vLeavesTemp, 1 ); @@ -1180,7 +1150,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) Vec_IntClear( vLeavesTemp ); for ( i = 4; i < 8; i++ ) { - int v = inputs[i]; + int v = pConfigData[1+i]; if ( v == 0 ) Vec_IntPush( vLeavesTemp, 0 ); // constant 0 else if ( v == 1 ) @@ -1190,12 +1160,12 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) else assert( 0 ); // Invalid value } - word Truth2 = ((word)pConfigData[9] << 8) | pConfigData[8]; + word Truth2 = ((word)pConfigData[12] << 8) | pConfigData[13]; Truth2 = Abc_Tt6Stretch( Truth2, 4 ); iObjLit2 = Kit_TruthToGia( pNew, (unsigned *)&Truth2, Vec_IntSize(vLeavesTemp), vCover, vLeavesTemp, 1 ); // MUX (select is input 8) - structural implementation int iSelectLit; - int v = inputs[8]; + int v = pConfigData[1+8]; if ( v == 0 ) iSelectLit = 0; // constant 0 select else if ( v == 1 ) @@ -1207,7 +1177,7 @@ void * If_ManDeriveGiaFromCells2( void * pGia ) iObjLit3 = Gia_ManHashMux( pNew, iSelectLit, iObjLit2, iObjLit1 ); Gia_ManObj(p, iLut)->Value = iObjLit3; Vec_IntFree( vLeavesTemp ); - bytePos += 12; // 1 byte CellId + 5 bytes mapping + 4 bytes truth tables + 2 padding + bytePos += 14; // 1 byte CellId + 9 bytes mapping + 4 bytes truth tables } else { From d8219265fce8f2c9c95cd20eca416d655fdc71c7 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Nov 2025 12:07:20 -0800 Subject: [PATCH 22/38] Updating LUT cascade generation to support flexible inputs. --- src/aig/gia/giaLutCas.c | 43 ++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/aig/gia/giaLutCas.c b/src/aig/gia/giaLutCas.c index c8f2026db..340996565 100644 --- a/src/aig/gia/giaLutCas.c +++ b/src/aig/gia/giaLutCas.c @@ -160,13 +160,23 @@ char * Gia_LutCasPerm( int nVars, int nLuts, int LutSize ) Gia_LutCasSort( pRes + i * LutSize, 1, LutSize-1 ); return pRes; } -int Gia_ManGenLutCas_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_Int_t * vDatas, int Shift ) +int Gia_ManGenLutCas_rec( Gia_Man_t * pNew, Vec_Int_t * vCtrls, int iCtrl, Vec_Int_t * vDatas, int Shift, int Offset ) { if ( iCtrl-- == 0 ) return Vec_IntEntry( vDatas, Shift ); - int iLit0 = Gia_ManGenLutCas_rec( pNew, vCtrls, iCtrl, vDatas, Shift ); - int iLit1 = Gia_ManGenLutCas_rec( pNew, vCtrls, iCtrl, vDatas, Shift + (1<pName = Abc_UtilStrsav( pPerm ); Vec_Int_t * vDatas = Vec_IntAlloc( nParams ); + Vec_Int_t * vWires = Vec_IntAlloc( nParams2 ); Vec_Int_t * vCtrls = Vec_IntAlloc( nVars ); for ( int i = 0; i < nParams; i++ ) Vec_IntPush( vDatas, Gia_ManAppendCi(pNew) ); + for ( int i = 0; i < nParams2; i++ ) + Vec_IntPush( vWires, Gia_ManAppendCi(pNew) ); for ( int i = 0; i < nVars; i++ ) Vec_IntPush( vCtrls, Gia_ManAppendCi(pNew) ); Vec_Int_t * vLits = Vec_IntStart( LutSize ); - Vec_IntWriteEntry( vLits, 0, Vec_IntEntry(vCtrls, (int)(pPerm[0]-'a')) ); + Vec_IntWriteEntry( vLits, 0, pPerm[0] == '*' ? Gia_ManGenWire(pNew, vCtrls, vWires, 0) : Vec_IntEntry(vCtrls, (int)(pPerm[0]-'a')) ); + int iWireVars = pPerm[0] == '*' ? Abc_Base2Log(nVars) : 0; char * pCur = pPerm; for ( int i = 0; i < nLuts; i++ ) { + assert( i == 0 || *pCur == '_' ); pCur++; - for ( int k = 1; k < LutSize; k++ ) - Vec_IntWriteEntry( vLits, k, Vec_IntEntry(vCtrls, (int)(*pCur++ - 'a')) ); - Vec_IntWriteEntry( vLits, 0, Gia_ManGenLutCas_rec(pNew, vLits, LutSize, vDatas, i * (1 << LutSize)) ); + for ( int k = 1; k < LutSize; k++ ) { + Vec_IntWriteEntry( vLits, k, *pCur == '*' ? Gia_ManGenWire(pNew, vCtrls, vWires, iWireVars) : Vec_IntEntry(vCtrls, (int)(*pCur - 'a')) ); + iWireVars += *pCur++ == '*' ? Abc_Base2Log(nVars) : 0; + } + Vec_IntWriteEntry( vLits, 0, Gia_ManGenLutCas_rec(pNew, vLits, LutSize, vDatas, i * (1 << LutSize), 0) ); } + assert( iWireVars == nParams2 ); // if the AIG is given, create a miter int iLit = Vec_IntEntry(vLits, 0); if ( p ) { @@ -218,6 +242,7 @@ Gia_Man_t * Gia_ManGenLutCas( Gia_Man_t * p, char * pPermStr, int nVars, int nLu Gia_ManAppendCo( pNew, iLit ); Vec_IntFree( vDatas ); Vec_IntFree( vCtrls ); + Vec_IntFree( vWires ); Vec_IntFree( vLits ); if ( fOwnPerm ) ABC_FREE( pPerm ); From 281204f938edefabaf1bf76be3767d35da35be4f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Nov 2025 12:12:09 -0800 Subject: [PATCH 23/38] Renaming "read_dsd" into "read_function". --- src/base/io/io.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/base/io/io.c b/src/base/io/io.c index 6b761347f..4962216ff 100644 --- a/src/base/io/io.c +++ b/src/base/io/io.c @@ -126,8 +126,7 @@ void Io_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "I/O", "read_blif_mv", IoCommandReadBlifMv, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_bench", IoCommandReadBench, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_cex", IoCommandReadCex, 1 ); - Cmd_CommandAdd( pAbc, "I/O", "read_dsd", IoCommandReadDsd, 1 ); - Cmd_CommandAdd( pAbc, "I/O", "read_formula", IoCommandReadDsd, 1 ); + Cmd_CommandAdd( pAbc, "I/O", "read_function", IoCommandReadDsd, 1 ); // Cmd_CommandAdd( pAbc, "I/O", "read_edif", IoCommandReadEdif, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_eqn", IoCommandReadEqn, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_fins", IoCommandReadFins, 0 ); @@ -1078,10 +1077,10 @@ int IoCommandReadDsd( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - fprintf( pAbc->Err, "usage: read_dsd [-h] \n" ); - fprintf( pAbc->Err, "\t parses a formula representing DSD of a function\n" ); + fprintf( pAbc->Err, "usage: read_function [-h] \n" ); + fprintf( pAbc->Err, "\t reads a Boolean function represented by a formula\n" ); fprintf( pAbc->Err, "\t-h : prints the command summary\n" ); - fprintf( pAbc->Err, "\tformula : the formula representing disjoint-support decomposition (DSD)\n" ); + fprintf( pAbc->Err, "\tformula : the formula representing the function\n" ); fprintf( pAbc->Err, "\t Example of a formula: !(a*(b+CA(!d,e*f,c))*79B3(g,h,i,k))\n" ); fprintf( pAbc->Err, "\t where \'!\' is an INV, \'*\' is an AND, \'+\' is an XOR, \n" ); fprintf( pAbc->Err, "\t CA and 79B3 are hexadecimal representations of truth tables\n" ); From 8c27e4bc90e75147e903a1dd4f7cafddf8cc47c9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Nov 2025 18:10:31 -0800 Subject: [PATCH 24/38] Adding permutation printout in "lutexact". --- src/sat/bmc/bmcMaj.c | 22 ++++++++++++++++++++-- src/sat/bmc/bmcMaj8.c | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/sat/bmc/bmcMaj.c b/src/sat/bmc/bmcMaj.c index e513861fe..b82f35777 100644 --- a/src/sat/bmc/bmcMaj.c +++ b/src/sat/bmc/bmcMaj.c @@ -1340,7 +1340,21 @@ static void Exa3_ManPrintSolution( Exa3_Man_t * p, int fCompl ) printf( " )\n" ); } } - +static void Exa3_ManPrintPerm( Exa3_Man_t * p ) +{ + int i, k, iVar; + for ( i = p->nVars; i < p->nObjs; i++ ) + { + if ( i > p->nVars ) + printf( "_" ); + for ( k = p->nLutSize - 1; k >= 0; k-- ) + { + iVar = Exa3_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + printf( "%c", 'a'+iVar ); + } + } +} /**Function************************************************************* Synopsis [] @@ -1678,8 +1692,12 @@ int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ) } if ( pPars->fVerbose && status != GLUCOSE_UNDEC ) Exa3_ManPrint( p, i, iMint, Abc_Clock() - clkTotal ); - if ( iMint == -1 ) + if ( iMint == -1 ) { Exa3_ManPrintSolution( p, fCompl ), Res = 1; + printf( "The variable permutation is \"" ); + Exa3_ManPrintPerm(p); + printf( "\".\n" ); + } else if ( status == GLUCOSE_UNDEC ) printf( "The solver timed out after %d sec.\n", pPars->RuntimeLim ); else if ( !p->pPars->fSilent ) diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c index 17073c1d1..902c5006a 100644 --- a/src/sat/bmc/bmcMaj8.c +++ b/src/sat/bmc/bmcMaj8.c @@ -419,6 +419,21 @@ static void Exa8_ManPrintSolution( Exa8_Man_t * p, int fCompl ) printf( " )\n" ); } } +static void Exa8_ManPrintPerm( Exa8_Man_t * p ) +{ + int i, k, iVar; + for ( i = p->nVars; i < p->nObjs; i++ ) + { + if ( i > p->nVars ) + printf( "_" ); + for ( k = p->nLutSize - 1; k >= 0; k-- ) + { + iVar = Exa8_ManFindFanin( p, i, k ); + if ( iVar >= 0 && iVar < p->nVars ) + printf( "%c", 'a'+iVar ); + } + } +} /**Function************************************************************* @@ -714,6 +729,9 @@ int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) if ( DiffMint != -1 ) printf( "Warning: Verification detected a mismatch at minterm %d.\n", DiffMint ); Exa8_ManPrintSolution( p, fCompl ); + printf( "The variable permutation is \"" ); + Exa8_ManPrintPerm(p); + printf( "\".\n" ); if ( pPars->fDumpBlif ) Exa8_ManDumpBlif( p, fCompl ); Res = 1; From bb52782941746cbd9ed699cf976ac53a2cfb13ac Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Nov 2025 19:41:10 -0800 Subject: [PATCH 25/38] New command "print_npn". --- src/base/abci/abc.c | 57 ++++++++++++++++++++++++++++ src/misc/util/utilTruth.h | 2 +- src/opt/dau/dauNpn.c | 79 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 0ddca29d4..badebec0d 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -89,6 +89,7 @@ static int Abc_CommandPrintMffc ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandPrintFactor ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandPrintLevel ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandPrintSupport ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandPrintNpn ( Abc_Frame_t * pAbc, int argc, char ** argv ); #ifdef ABC_USE_CUDD static int Abc_CommandPrintMint ( Abc_Frame_t * pAbc, int argc, char ** argv ); #endif @@ -910,6 +911,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "Printing", "print_level", Abc_CommandPrintLevel, 0 ); Cmd_CommandAdd( pAbc, "Printing", "psu", Abc_CommandPrintSupport, 0 ); Cmd_CommandAdd( pAbc, "Printing", "print_supp", Abc_CommandPrintSupport, 0 ); + Cmd_CommandAdd( pAbc, "Printing", "print_npn", Abc_CommandPrintNpn, 0 ); #ifdef ABC_USE_CUDD Cmd_CommandAdd( pAbc, "Printing", "print_mint", Abc_CommandPrintMint, 0 ); #endif @@ -2278,6 +2280,61 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandPrintNpn( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Dau_PrintNpnFunctions( word * p, int nVars, int fVerbose ); + char * pTruthStr = NULL; + word pTruth[16] = {0}; + int c, nVars, fVerbose = 0; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF ) + { + switch ( c ) + { + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( globalUtilOptind != argc-1 ) + { + Abc_Print( -1, "The command expects the truth table on the command line.\n" ); + goto usage; + } + pTruthStr = argv[globalUtilOptind]; + nVars = Abc_TtReadHex( pTruth, pTruthStr ); + assert( nVars <= 10 ); + Dau_PrintNpnFunctions( pTruth, nVars, fVerbose ); + return 0; + +usage: + Abc_Print( -2, "usage: print_npn [-vh] \n" ); + Abc_Print( -2, "\t prints the NPN members of the given function\n" ); + Abc_Print( -2, "\t-v : enable verbose output [default = %s].\n", fVerbose? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + Abc_Print( -2, "\t : the truth table in hexadecimal notation\n"); + + return 1; +} + + + + /**Function************************************************************* Synopsis [] diff --git a/src/misc/util/utilTruth.h b/src/misc/util/utilTruth.h index d94e9bfe2..2d0422401 100644 --- a/src/misc/util/utilTruth.h +++ b/src/misc/util/utilTruth.h @@ -1640,7 +1640,7 @@ static inline void Abc_TtPrintBits2( word * pTruth, int nBits ) int k; for ( k = nBits-1; k >= 0; k-- ) printf( "%d", Abc_InfoHasBit( (unsigned *)pTruth, k ) ); - printf( "\n" ); + //printf( "\n" ); } static inline void Abc_TtPrintBinary( word * pTruth, int nVars ) { diff --git a/src/opt/dau/dauNpn.c b/src/opt/dau/dauNpn.c index a654695c5..96f81c508 100644 --- a/src/opt/dau/dauNpn.c +++ b/src/opt/dau/dauNpn.c @@ -859,6 +859,85 @@ Vec_Mem_t * Dau_CollectNpnFunctions( word * p, int nVars, int fVerbose ) return vTtMem; } +/**Function************************************************************* + + Synopsis [Function enumeration.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Dau_PrintNpnFunction( Vec_Mem_t * vTtMem, int nFuncs, word * pCopy, int nVars, int uPhase, int * pPerm, int fVerbose ) +{ + int nWords = Abc_Truth6WordNum(nVars); + if ( fVerbose ) { + printf( "%6d : ", nFuncs ); + Abc_TtPrintBits2((word *)&uPhase, nVars); + printf( " " ); + for ( int v = nVars-1; v >= 0; v-- ) + printf( " %d", pPerm[v] ); + printf( " F = " ); + Abc_TtPrintHexRev( stdout, pCopy, nVars ); + } + int Pos = Vec_MemHashInsert( vTtMem, pCopy ); + Abc_TtNot( pCopy, nWords ); + if ( fVerbose ) { + printf( " (%05d)", Pos ); + printf( " ~F = " ); + Abc_TtPrintHexRev( stdout, pCopy, nVars ); + } + int Neg = Vec_MemHashInsert( vTtMem, pCopy ); + Abc_TtNot( pCopy, nWords ); + if ( fVerbose ) { + printf( " (%05d)", Neg ); + printf( "\n" ); + } +} +void Dau_PrintNpnFunctions( word * p, int nVars, int fVerbose ) +{ + int nWords = Abc_Truth6WordNum(nVars); + Vec_Mem_t * vTtMem = Vec_MemAllocForTTSimple( nVars ); + word * pCopy = ABC_ALLOC( word, nWords ); + word * pBest = ABC_ALLOC( word, nWords ); + Abc_TtCopy( pCopy, p, nWords, 0 ); + Abc_TtCopy( pBest, p, nWords, 0 ); + int nPerms = Extra_Factorial( nVars ); + int nMints = 1 << nVars; + int * pPerm = Extra_PermSchedule( nVars ); + int * pComp = Extra_GreyCodeSchedule( nVars ); + int m, i, k, nFuncs = 0; + int uVarPhase = 0; + int pVarPerm[32]; + printf( "The number of NPN configurations is %d = %d complementations * %d permutations * 2 output polarities.\n", nMints*nPerms*2, nMints, nPerms ); + for ( i = 0; i < nVars; i++ ) + pVarPerm[i] = i; + for ( m = 0; m < nMints; m++ ) { + for ( k = 0; k < nPerms; k++ ) { + if ( Abc_TtCompare(pBest, pCopy, nWords) == 1 ) + Abc_TtCopy( pBest, pCopy, nWords, 0 ); + Dau_PrintNpnFunction( vTtMem, nFuncs++, pCopy, nVars, uVarPhase, pVarPerm, fVerbose ); + Abc_TtSwapAdjacent( pCopy, nWords, pPerm[k] ); + ABC_SWAP( int, pVarPerm[pPerm[k]], pVarPerm[pPerm[k]+1] ); + } + if ( fVerbose ) printf( "\n" ); + Abc_TtFlip( pCopy, nWords, pComp[m] ); + uVarPhase ^= 1 << pComp[m]; + } + assert( Abc_TtEqual(pCopy, p, nWords) ); + printf( "The number of unique functions %d (out of %d). Frequency = %d. Representative: ", Vec_MemEntryNum(vTtMem), nMints*nPerms*2, nMints*nPerms*2/Vec_MemEntryNum(vTtMem) ); + Abc_TtPrintHexRev( stdout, pBest, nVars ); + printf( "\n" ); + ABC_FREE( pPerm ); + ABC_FREE( pComp ); + ABC_FREE( pCopy ); + ABC_FREE( pBest ); + Vec_MemHashFree( vTtMem ); + Vec_MemFree( vTtMem ); +} + /**Function************************************************************* Synopsis [Compute NPN class members.] From 6490bd7da37e9e33d135da5680f297e4abae3aac Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Tue, 18 Nov 2025 20:16:44 -0800 Subject: [PATCH 26/38] Improving print-outs. --- src/aig/gia/giaIf.c | 125 +++++++++++++++++++++++++++++++++++++++++++- src/base/abci/abc.c | 2 +- src/base/io/io.c | 4 +- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/src/aig/gia/giaIf.c b/src/aig/gia/giaIf.c index bf8293576..cfbf01a70 100644 --- a/src/aig/gia/giaIf.c +++ b/src/aig/gia/giaIf.c @@ -2003,6 +2003,127 @@ void Gia_ManConfigPrint( word Truth4, word z, int nLeaves ) } } +/**Function************************************************************* + + Synopsis [Print cell configuration data.] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +void Gia_ManConfigPrint2( unsigned char * pConfigData, int nLeaves ) +{ + unsigned char CellId = pConfigData[0]; + int i; + static int Count = 0; + printf( "%6d : ", Count++ ); // Print instance number + printf( "[Cell %d with %d leaves] ", CellId, nLeaves ); + if ( CellId == 0 ) + { + assert( nLeaves <= 4 ); + // Extract 16-bit truth table + word Truth = ((word)pConfigData[5] << 8) | pConfigData[6]; + printf( "e=%04lX{", (unsigned long)Truth ); + // Print as simple {abcd} since it's just a direct LUT4 + for ( i = 0; i < nLeaves; i++ ) + printf( "%c", 'a' + i ); + for ( ; i < 4; i++ ) + printf( "%c", '0' ); + printf( "}\n" ); + } + else if ( CellId == 1 ) + { + // First LUT4 + word Truth1 = ((word)pConfigData[8] << 8) | pConfigData[9]; + printf( "h=%04lX{", (unsigned long)Truth1 ); + for ( i = 0; i < 4; i++ ) + { + int v = pConfigData[1+i]; + if ( v == 0 ) + printf( "0"); + else if ( v == 1 ) + printf( "1"); + else if ( v >= 2 && v < 2 + nLeaves ) + printf( "%c", 'a' + (v-2)); + else + printf( "?"); + } + printf( "};"); + // Second LUT4 + word Truth2 = ((word)pConfigData[10] << 8) | pConfigData[11]; + printf( "i=%04lX{", (unsigned long)Truth2 ); + for ( i = 4; i < 7; i++ ) + { + int v = pConfigData[1+i]; + if ( v == 0 ) + printf( "0"); + else if ( v == 1 ) + printf( "1"); + else if ( v >= 2 && v < 2 + nLeaves ) + printf( "%c", 'a' + (v-2)); + else if ( v == 9 ) + printf( "h"); // Output of first LUT + else + printf( "?"); + } + printf( "h}\n" ); + } + else if ( CellId == 2 ) + { + // First LUT4 + word Truth1 = ((word)pConfigData[10] << 8) | pConfigData[11]; + printf( "j=%04lX{", (unsigned long)Truth1 ); + for ( i = 0; i < 4; i++ ) + { + int v = pConfigData[1+i]; + if ( v == 0 ) + printf( "0"); + else if ( v == 1 ) + printf( "1"); + else if ( v >= 2 && v < 2 + nLeaves ) + printf( "%c", 'a' + (v-2)); + else + printf( "?"); + } + printf( "};"); + // Second LUT4 + word Truth2 = ((word)pConfigData[12] << 8) | pConfigData[13]; + printf( "k=%04lX{", (unsigned long)Truth2 ); + for ( i = 4; i < 8; i++ ) + { + int v = pConfigData[1+i]; + if ( v == 0 ) + printf( "0"); + else if ( v == 1 ) + printf( "1"); + else if ( v >= 2 && v < 2 + nLeaves ) + printf( "%c", 'a' + (v-2)); + else + printf( "?"); + } + printf( "};"); + // final node + printf( "l=<"); + int v = pConfigData[1+8]; + if ( v == 0 ) + printf( "0"); + else if ( v == 1 ) + printf( "1"); + else if ( v >= 2 && v < 2 + nLeaves ) + printf( "%c", 'a' + (v-2)); + else + printf( "?"); + printf( "jk>\n" ); + } + else + { + printf( "Unknown cell type %d!\n", CellId ); + } +} + /**Function************************************************************* Synopsis [Derive configurations.] @@ -2108,6 +2229,8 @@ void Gia_ManFromIfGetConfig2( Vec_Str_t * vConfigs2, If_Man_t * pIfMan, word * p assert( startPos + 14 == Vec_StrSize(vConfigs2) ); } } + if ( pIfMan->pPars->fVerboseTrace ) + Gia_ManConfigPrint2( (unsigned char*)Vec_StrEntryP(vConfigs2, startPos), nLeaves ); } int Gia_ManFromIfLogicFindCell( If_Man_t * pIfMan, Gia_Man_t * pNew, Gia_Man_t * pTemp, If_Cut_t * pCutBest, Ifn_Ntk_t * pNtkCell, int nLutMax, Vec_Int_t * vLeaves, Vec_Int_t * vLits, Vec_Int_t * vCover, Vec_Int_t * vMapping, Vec_Int_t * vMapping2, Vec_Int_t * vConfigs ) { @@ -2907,7 +3030,7 @@ Gia_Man_t * Gia_ManPerformMappingInt( Gia_Man_t * p, If_Par_t * pPars ) pNew->pSpec = Abc_UtilStrsav( p->pSpec ); Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) ); // print delay trace - if ( pPars->fVerboseTrace ) + if ( pPars->fVerboseTrace && !pPars->fEnableCheck07 ) { pNew->pLutLib = pPars->pLutLib; Gia_ManDelayTraceLutPrint( pNew, 1 ); diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index badebec0d..49a789fcb 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -43683,7 +43683,7 @@ usage: Abc_Print( -2, "\t-u : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck75u? "yes": "no" ); Abc_Print( -2, "\t-i : toggles using cofactoring variables [default = %s]\n", pPars->fUseCofVars? "yes": "no" ); Abc_Print( -2, "\t-j : toggles enabling additional check [default = %s]\n", pPars->fEnableCheck07? "yes": "no" ); - Abc_Print( -2, "\t-j : toggles using AND bi-decomposition [default = %s]\n", pPars->fUseAndVars? "yes": "no" ); +// Abc_Print( -2, "\t-j : toggles using AND bi-decomposition [default = %s]\n", pPars->fUseAndVars? "yes": "no" ); Abc_Print( -2, "\t-k : toggles matching based on precomputed DSD manager [default = %s]\n", pPars->fUseDsdTune? "yes": "no" ); Abc_Print( -2, "\t-z : toggles deriving LUTs when mapping into LUT structures [default = %s]\n", pPars->fDeriveLuts? "yes": "no" ); Abc_Print( -2, "\t-t : toggles optimizing average rather than maximum level [default = %s]\n", pPars->fDoAverage? "yes": "no" ); diff --git a/src/base/io/io.c b/src/base/io/io.c index 4962216ff..7bb789ae6 100644 --- a/src/base/io/io.c +++ b/src/base/io/io.c @@ -126,7 +126,7 @@ void Io_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "I/O", "read_blif_mv", IoCommandReadBlifMv, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_bench", IoCommandReadBench, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_cex", IoCommandReadCex, 1 ); - Cmd_CommandAdd( pAbc, "I/O", "read_function", IoCommandReadDsd, 1 ); + Cmd_CommandAdd( pAbc, "I/O", "read_formula", IoCommandReadDsd, 1 ); // Cmd_CommandAdd( pAbc, "I/O", "read_edif", IoCommandReadEdif, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_eqn", IoCommandReadEqn, 1 ); Cmd_CommandAdd( pAbc, "I/O", "read_fins", IoCommandReadFins, 0 ); @@ -1077,7 +1077,7 @@ int IoCommandReadDsd( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - fprintf( pAbc->Err, "usage: read_function [-h] \n" ); + fprintf( pAbc->Err, "usage: read_formula [-h] \n" ); fprintf( pAbc->Err, "\t reads a Boolean function represented by a formula\n" ); fprintf( pAbc->Err, "\t-h : prints the command summary\n" ); fprintf( pAbc->Err, "\tformula : the formula representing the function\n" ); From 51c5ff3b81df553b7d872cf1c675789e807dc158 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 20 Nov 2025 13:35:47 -0800 Subject: [PATCH 27/38] Updated to "lutexact". --- src/base/abci/abc.c | 9 +++++++-- src/sat/bmc/bmc.h | 1 + src/sat/bmc/bmcMaj8.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index 49a789fcb..fc6592452 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -10757,6 +10757,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) { extern int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ); + extern int Exa8_ManExactSynthesisIter( Bmc_EsPar_t * pPars ); extern int Exa3_ManExactSynthesis( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesis2( Bmc_EsPar_t * pPars ); extern void Exa3_ManExactSynthesisRand( Bmc_EsPar_t * pPars ); @@ -10765,7 +10766,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) Bmc_EsPar_t Pars, * pPars = &Pars; Bmc_EsParSetDefault( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYPiaorfgckdsvh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "NMKTFUSYPiaorfgckdsmvh" ) ) != EOF ) { switch ( c ) { @@ -10890,6 +10891,9 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) case 's': pPars->fSilent ^= 1; break; + case 'm': + pPars->fMinNodes ^= 1; + break; case 'v': pPars->fVerbose ^= 1; break; @@ -10966,7 +10970,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv ) return 0; usage: - Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-P string] [-iaorfgckdsvh] \n" ); + Abc_Print( -2, "usage: lutexact [-NMKTFUS ] [-Y string] [-P string] [-iaorfgckdsmvh] \n" ); Abc_Print( -2, "\t exact synthesis of I-input function using N K-input gates\n" ); Abc_Print( -2, "\t-N : the number of input variables [default = %d]\n", pPars->nVars ); Abc_Print( -2, "\t-M : the number of K-input nodes [default = %d]\n", pPars->nNodes ); @@ -10987,6 +10991,7 @@ usage: Abc_Print( -2, "\t-k : toggle using Kissat 4.0.2 by Armin Biere [default = %s]\n", pPars->fKissat ? "yes" : "no" ); Abc_Print( -2, "\t-d : toggle dumping decomposed networks into BLIF files [default = %s]\n", pPars->fDumpBlif ? "yes" : "no" ); Abc_Print( -2, "\t-s : toggle silent computation (no messages, except when a solution is found) [default = %s]\n", pPars->fSilent ? "yes" : "no" ); + Abc_Print( -2, "\t-m : toggle minimum-node solution possibly smaller than \"-M \" [default = %s]\n", pPars->fMinNodes ? "yes" : "no" ); Abc_Print( -2, "\t-v : toggle verbose printout [default = %s]\n", pPars->fVerbose ? "yes" : "no" ); Abc_Print( -2, "\t-h : print the command usage\n" ); Abc_Print( -2, "\t : truth table in hex notation\n" ); diff --git a/src/sat/bmc/bmc.h b/src/sat/bmc/bmc.h index 85fd0265c..374945039 100644 --- a/src/sat/bmc/bmc.h +++ b/src/sat/bmc/bmc.h @@ -67,6 +67,7 @@ struct Bmc_EsPar_t_ int fUniqFans; int fLutCascade; int fLutInFixed; + int fMinNodes; int RuntimeLim; int nRandFuncs; int nMintNum; diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c index 902c5006a..ae0307994 100644 --- a/src/sat/bmc/bmcMaj8.c +++ b/src/sat/bmc/bmcMaj8.c @@ -670,6 +670,9 @@ static int Exa8_ManAddCnf( Exa8_Man_t * p, int iMint ) int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) { + extern int Exa8_ManExactSynthesisIter( Bmc_EsPar_t * pPars ); + if ( pPars->fMinNodes ) + return Exa8_ManExactSynthesisIter( pPars ); int status = KISSAT_UNDEC; int Res = 0; abctime clkTotal = Abc_Clock(); @@ -744,6 +747,7 @@ int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) } else { + Res = 0; if ( pPars->RuntimeLim ) printf( "The solver timed out after %d sec.\n", pPars->RuntimeLim ); } @@ -757,6 +761,41 @@ int Exa8_ManExactSynthesis( Bmc_EsPar_t * pPars ) return Res; } +int Exa8_ManExactSynthesisIter( Bmc_EsPar_t * pPars ) +{ + pPars->fMinNodes = 0; + int nNodeMin = (pPars->nVars-2)/(pPars->nLutSize-1) + 1; + int nNodeMax = pPars->nNodes, Result = 0; + int fGenPerm = pPars->pPermStr == NULL; + for ( int n = nNodeMin; n <= nNodeMax; n++ ) { + printf( "\nTrying M = %d:\n", n ); + pPars->nNodes = n; + if ( fGenPerm ) { + Vec_Str_t * vStr = Vec_StrAlloc( 100 ); + for ( int v = 0; v < pPars->nLutSize; v++ ) + Vec_StrPush( vStr, 'a'+v ); + int nDupVars = Abc_MaxInt(0, (pPars->nLutSize-1) - (pPars->nVars-pPars->nLutSize)); + Vec_StrPush( vStr, '_' ); + for ( int v = 0; v < nDupVars; v++ ) + Vec_StrPush( vStr, 'a'+v ); + for ( int v = 0; v < pPars->nLutSize-1-nDupVars; v++ ) + Vec_StrPush( vStr, '*' ); + for ( int m = 2; m < pPars->nNodes; m++ ) { + Vec_StrPush( vStr, '_' ); + for ( int v = 0; v < pPars->nLutSize-1; v++ ) + Vec_StrPush( vStr, '*' ); + } + Vec_StrPush( vStr, '\0' ); + ABC_FREE( pPars->pPermStr ); + pPars->pPermStr = Vec_StrReleaseArray(vStr); + Vec_StrFree( vStr ); + } + Result = Exa8_ManExactSynthesis(pPars); + if ( Result != 2 ) + break; + } + return Result; +} //////////////////////////////////////////////////////////////////////// /// END OF FILE /// From 6aaca6a1aff7e3049556ad17cedaf4c31021fe5f Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 20 Nov 2025 22:54:05 -0800 Subject: [PATCH 28/38] Fixing timeout in kissat. --- src/sat/kissat/terminate.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sat/kissat/terminate.h b/src/sat/kissat/terminate.h index 853adecd1..2d85966f3 100644 --- a/src/sat/kissat/terminate.h +++ b/src/sat/kissat/terminate.h @@ -16,6 +16,21 @@ static inline bool kissat_terminated (kissat *solver, int bit, const char *name, const char *file, long lineno, const char *fun) { KISSAT_assert (0 <= bit), KISSAT_assert (bit < 64); +#if defined(COVERAGE) + if (!solver->termination.flagged) { + int (*terminate) (void *) = solver->termination.terminate; + void *state = (void *) solver->termination.state; + if (terminate && terminate (state)) + solver->termination.flagged = ~(uint64_t) 0; + } +#else + if (!solver->termination.flagged) { + int (*terminate) (void *) = solver->termination.terminate; + void *state = (void *) solver->termination.state; + if (terminate && terminate (state)) + solver->termination.flagged = true; + } +#endif #ifdef COVERAGE const uint64_t mask = (uint64_t) 1 << bit; if (!(solver->termination.flagged & mask)) From d72b93c1683d6c33da5262db56b56679f657cf34 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 20 Nov 2025 22:56:32 -0800 Subject: [PATCH 29/38] Updating how history is recorded. --- src/base/cmd/cmdHist.c | 35 ++++++++++++++++++++++++++--------- src/base/main/mainInt.h | 1 + 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/base/cmd/cmdHist.c b/src/base/cmd/cmdHist.c index b0981630c..b66f48c88 100644 --- a/src/base/cmd/cmdHist.c +++ b/src/base/cmd/cmdHist.c @@ -50,7 +50,7 @@ ABC_NAMESPACE_IMPL_START void Cmd_HistoryAddCommand( Abc_Frame_t * p, const char * command ) { int nLastLooked = 10; // do not add history if the same entry appears among the last entries - int nLastSaved = 10000; // when saving a file, save no more than this number of last entries + int nLastSaved = 20000; // when saving a file, save no more than this number of last entries char Buffer[ABC_MAX_STR]; int Len; if ( p->fBatchMode ) @@ -117,6 +117,7 @@ void Cmd_HistoryRead( Abc_Frame_t * p ) Vec_PtrPush( p->aHistory, Extra_UtilStrsav(Buffer) ); } fclose( pFile ); + p->iStartHistory = Vec_PtrSize(p->aHistory); #endif } @@ -137,16 +138,32 @@ void Cmd_HistoryWrite( Abc_Frame_t * p, int Limit ) FILE * pFile; char * pStr; int i; - pFile = fopen( "abc.history", "wb" ); - if ( pFile == NULL ) + if ( 1 ) { - Abc_Print( 0, "Cannot open file \"abc.history\" for writing.\n" ); - return; + pFile = fopen( "abc.history", "ab" ); + if ( pFile == NULL ) + { + Abc_Print( 0, "Cannot open file \"abc.history\" for writing.\n" ); + return; + } + Vec_PtrForEachEntryStart( char *, p->aHistory, pStr, i, p->iStartHistory ) + fprintf( pFile, "%s\n", pStr ); + fclose( pFile ); + p->iStartHistory = Vec_PtrSize(p->aHistory); + } + if ( Vec_PtrSize(p->aHistory) > Limit + 1000 ) + { + pFile = fopen( "abc.history", "wb" ); + if ( pFile == NULL ) + { + Abc_Print( 0, "Cannot open file \"abc.history\" for writing.\n" ); + return; + } + Limit = Abc_MaxInt( 0, Vec_PtrSize(p->aHistory)-Limit ); + Vec_PtrForEachEntryStart( char *, p->aHistory, pStr, i, Limit ) + fprintf( pFile, "%s\n", pStr ); + fclose( pFile ); } - Limit = Abc_MaxInt( 0, Vec_PtrSize(p->aHistory)-Limit ); - Vec_PtrForEachEntryStart( char *, p->aHistory, pStr, i, Limit ) - fprintf( pFile, "%s\n", pStr ); - fclose( pFile ); #endif } diff --git a/src/base/main/mainInt.h b/src/base/main/mainInt.h index db98fbb3e..73b3ad2dd 100644 --- a/src/base/main/mainInt.h +++ b/src/base/main/mainInt.h @@ -67,6 +67,7 @@ struct Abc_Frame_t_ st__table * tAliases; // the alias table st__table * tFlags; // the flag table Vec_Ptr_t * aHistory; // the command history + int iStartHistory; // beginning of the new history file // the functionality Abc_Ntk_t * pNtkCur; // the current network Abc_Ntk_t * pNtkBestDelay; // the current network From 4bba0356fbfec912b74f820dc2954ef1070ecf25 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Thu, 20 Nov 2025 22:57:16 -0800 Subject: [PATCH 30/38] Dumping partial products as an AIG. --- src/base/wlc/wlcBlast.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/base/wlc/wlcBlast.c b/src/base/wlc/wlcBlast.c index 2bcceb2db..8950025d5 100644 --- a/src/base/wlc/wlcBlast.c +++ b/src/base/wlc/wlcBlast.c @@ -1240,6 +1240,17 @@ Vec_Int_t * Wlc_BlastDecoder2( Gia_Man_t * pNew, int * pNum, int nNum, Vec_Int_t Vec_IntFree( vRes2 ); return vRes; } +void Wlc_DumpMatrix( Gia_Man_t * pNew, Vec_Wec_t * vProds ) +{ + char * pFileName = "booth_pps.aig"; + Vec_Int_t * vLevel; int i, k, Entry; + Vec_WecForEachLevel( vProds, vLevel, i ) + Vec_IntForEachEntry( vLevel, Entry, k ) + Gia_ManAppendCo(pNew, Entry); + Gia_AigerWrite( pNew, pFileName, 0, 0, 0 ); + printf( "Finished dumping Booth PPs into \"%s\".\n", pFileName ); + exit(1); +} void Wlc_BlastBooth( Gia_Man_t * pNew, int * pArgA, int * pArgB, int nArgA, int nArgB, Vec_Int_t * vRes, int fSigned, int fCla, Vec_Wec_t ** pvProds, int fVerbose ) { Vec_Wec_t * vProds = Vec_WecStart( nArgA + nArgB + 3 ); @@ -1324,6 +1335,7 @@ void Wlc_BlastBooth( Gia_Man_t * pNew, int * pArgA, int * pArgB, int nArgA, int Vec_WecPrint( vProds, 0 ); if ( fVerbose ) printf( "Total PPs = %d.\n", Vec_WecSizeSize(vProds) ); + //Wlc_DumpMatrix( pNew, vProds ); //Wlc_BlastPrintMatrix( pNew, vProds, 1 ); //printf( "Cutoff ID for partial products = %d.\n", Gia_ManObjNum(pNew) ); if ( pvProds ) From bde60f2a204335f85cacbb33d7e4115bd5841ac6 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 21 Nov 2025 00:49:36 -0800 Subject: [PATCH 31/38] Update to "lutexact". --- src/sat/bmc/bmcMaj8.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c index ae0307994..3aa3bce59 100644 --- a/src/sat/bmc/bmcMaj8.c +++ b/src/sat/bmc/bmcMaj8.c @@ -791,7 +791,8 @@ int Exa8_ManExactSynthesisIter( Bmc_EsPar_t * pPars ) Vec_StrFree( vStr ); } Result = Exa8_ManExactSynthesis(pPars); - if ( Result != 2 ) + fflush( stdout ); + if ( Result == 1 ) break; } return Result; From 48d09e7f936327e8031925dd73b441e3fafff3d3 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 21 Nov 2025 19:49:48 -0800 Subject: [PATCH 32/38] Fixing a corner case crash. --- src/aig/gia/giaSweep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aig/gia/giaSweep.c b/src/aig/gia/giaSweep.c index 8a7fcbd07..e41b619b3 100644 --- a/src/aig/gia/giaSweep.c +++ b/src/aig/gia/giaSweep.c @@ -751,7 +751,7 @@ Gia_Man_t * Gia_ManSweepWithBoxes( Gia_Man_t * p, void * pParsC, void * pParsS, if ( pNew == NULL ) return NULL; Gia_ManTransferTiming( pNew, p ); - nFlops = Vec_IntCountEntry(pNew->vRegClasses, 1); + nFlops = pNew->vRegClasses ? Vec_IntCountEntry(pNew->vRegClasses, 1) : 0; // find global equivalences pClp = Gia_ManDupCollapse( pNew, pNew->pAigExtra, NULL, pParsC ? 0 : 1 ); //Gia_DumpAiger( pClp, p->pSpec, 1, 1 ); @@ -775,7 +775,7 @@ Gia_Man_t * Gia_ManSweepWithBoxes( Gia_Man_t * p, void * pParsC, void * pParsS, pNew = Gia_ManDupWithBoxes( pTemp = pNew, pParsC ? 0 : 1 ); Gia_ManStop( pTemp ); // report - nFlopsNew = Vec_IntCountEntry(pNew->vRegClasses, 1); + nFlopsNew = pNew->vRegClasses ? Vec_IntCountEntry(pNew->vRegClasses, 1) : 0; pFlopTypes[2] = nFlops - nFlopsNew - (pFlopTypes[0] + pFlopTypes[1]); if ( fVerbEquivs ) { From fade76f70ba8b690848cbe44c6abbd6a7a12ae61 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Fri, 21 Nov 2025 20:07:49 -0800 Subject: [PATCH 33/38] Updating how history is recorded. --- src/base/abci/abcSymm.c | 3 +++ src/base/cmd/cmdHist.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/base/abci/abcSymm.c b/src/base/abci/abcSymm.c index 8f6bc9699..d5cf7a44e 100644 --- a/src/base/abci/abcSymm.c +++ b/src/base/abci/abcSymm.c @@ -327,7 +327,10 @@ void Ntk_SymFunGenerate( int nVars, int fVerbose ) if ( fVerbose ) Extra_PrintHex( stdout, (unsigned *)pFun, nVars ); Ntk_SymFunDeriveNpn( pFun, nVars, pComp ); + //int nClasses = Vec_MemEntryNum( vTtMem ); Class = Vec_MemHashInsert( vTtMem, pFun ); + //if ( Class == nClasses ) + //printf( "Class %3d : %s\n", nClasses, Ones ); if ( fVerbose ) { printf( " : NPN " ); diff --git a/src/base/cmd/cmdHist.c b/src/base/cmd/cmdHist.c index b66f48c88..0edd8a686 100644 --- a/src/base/cmd/cmdHist.c +++ b/src/base/cmd/cmdHist.c @@ -160,9 +160,15 @@ void Cmd_HistoryWrite( Abc_Frame_t * p, int Limit ) return; } Limit = Abc_MaxInt( 0, Vec_PtrSize(p->aHistory)-Limit ); - Vec_PtrForEachEntryStart( char *, p->aHistory, pStr, i, Limit ) + Vec_Ptr_t * aHistory= Vec_PtrAlloc(Vec_PtrSize(p->aHistory)); + Vec_PtrForEachEntryStart( char *, p->aHistory, pStr, i, Limit ) { fprintf( pFile, "%s\n", pStr ); + Vec_PtrPush( aHistory, Abc_UtilStrsav(pStr) ); + } fclose( pFile ); + Vec_PtrFreeFree( p->aHistory ); + p->aHistory = aHistory; + p->iStartHistory = Vec_PtrSize(p->aHistory); } #endif } From 148f0e9cac6ac5e1942a15ee2c64b5672823fa02 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 23 Nov 2025 10:55:51 -0800 Subject: [PATCH 34/38] Temporarily undoing recent changes to arrival/required times. --- src/aig/gia/giaAiger.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/aig/gia/giaAiger.c b/src/aig/gia/giaAiger.c index 76ae3df3f..cd35586ea 100644 --- a/src/aig/gia/giaAiger.c +++ b/src/aig/gia/giaAiger.c @@ -652,9 +652,9 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi pNew->vInArrs = Vec_FltStart( nInputs ); memcpy( Vec_FltArray(pNew->vInArrs), pCur, (size_t)4*nInputs ); pCur += 4*nInputs; if ( fVerbose ) printf( "Finished reading extension \"i\".\n" ); - if ( Vec_FltSize(pNew->vInArrs) == Gia_ManPiNum(pNew) ) - Vec_FltFillExtra(pNew->vInArrs, Gia_ManCiNum(pNew), 0); - assert( Vec_FltSize(pNew->vInArrs) == Gia_ManCiNum(pNew) ); + //if ( Vec_FltSize(pNew->vInArrs) == Gia_ManPiNum(pNew) ) + // Vec_FltFillExtra(pNew->vInArrs, Gia_ManCiNum(pNew), 0); + //assert( Vec_FltSize(pNew->vInArrs) == Gia_ManCiNum(pNew) ); } else if ( *pCur == 'o' ) { @@ -663,9 +663,9 @@ Gia_Man_t * Gia_AigerReadFromMemory( char * pContents, int nFileSize, int fGiaSi pNew->vOutReqs = Vec_FltStart( nOutputs ); memcpy( Vec_FltArray(pNew->vOutReqs), pCur, (size_t)4*nOutputs ); pCur += 4*nOutputs; if ( fVerbose ) printf( "Finished reading extension \"o\".\n" ); - if ( Vec_FltSize(pNew->vOutReqs) == Gia_ManPoNum(pNew) ) - Vec_FltFillExtra(pNew->vOutReqs, Gia_ManCoNum(pNew), 0); - assert( Vec_FltSize(pNew->vOutReqs) == Gia_ManCoNum(pNew) ); + //if ( Vec_FltSize(pNew->vOutReqs) == Gia_ManPoNum(pNew) ) + // Vec_FltFillExtra(pNew->vOutReqs, Gia_ManCoNum(pNew), 0); + //assert( Vec_FltSize(pNew->vOutReqs) == Gia_ManCoNum(pNew) ); } // read equivalence classes else if ( *pCur == 'e' ) From c956f02eb01b52229cd12600fb17062971a40fe3 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 23 Nov 2025 11:57:59 -0800 Subject: [PATCH 35/38] Debug features. --- src/sat/bmc/bmcMaj8.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/sat/bmc/bmcMaj8.c b/src/sat/bmc/bmcMaj8.c index 3aa3bce59..4a96af84e 100644 --- a/src/sat/bmc/bmcMaj8.c +++ b/src/sat/bmc/bmcMaj8.c @@ -790,6 +790,48 @@ int Exa8_ManExactSynthesisIter( Bmc_EsPar_t * pPars ) pPars->pPermStr = Vec_StrReleaseArray(vStr); Vec_StrFree( vStr ); } + if ( 0 && fGenPerm ) { + Vec_Str_t * vStr = Vec_StrAlloc( 100 ); + for ( int v = 0; v < pPars->nLutSize; v++ ) + Vec_StrPush( vStr, 'a'+v ); + for ( int m = 1; m < pPars->nNodes; m++ ) { + Vec_StrPush( vStr, '_' ); + if ( m & 1 ) + for ( int v = 0; v < pPars->nLutSize-1; v++ ) + Vec_StrPush( vStr, 'a'+(pPars->nVars-(pPars->nLutSize-1-v)) ); + else + for ( int v = 0; v < pPars->nLutSize-1; v++ ) + Vec_StrPush( vStr, 'a'+v ); + } + Vec_StrPush( vStr, '\0' ); + ABC_FREE( pPars->pPermStr ); + pPars->pPermStr = Vec_StrReleaseArray(vStr); + Vec_StrFree( vStr ); + } + if ( 0 && fGenPerm ) { + Vec_Str_t * vStr = Vec_StrAlloc( 100 ); + for ( int v = 0; v < pPars->nLutSize; v++ ) + Vec_StrPush( vStr, 'a'+v ); + for ( int m = 1; m < pPars->nNodes; m++ ) { + Vec_StrPush( vStr, '_' ); + if ( m & 1 ) { + Vec_StrPush( vStr, '*' ); + Vec_StrPush( vStr, '*' ); + for ( int v = 2; v < pPars->nLutSize-1; v++ ) + Vec_StrPush( vStr, 'a'+(pPars->nVars-(pPars->nLutSize-1-v)) ); + } + else { + for ( int v = 0; v < pPars->nLutSize-3; v++ ) + Vec_StrPush( vStr, 'a'+v ); + Vec_StrPush( vStr, '*' ); + Vec_StrPush( vStr, '*' ); + } + } + Vec_StrPush( vStr, '\0' ); + ABC_FREE( pPars->pPermStr ); + pPars->pPermStr = Vec_StrReleaseArray(vStr); + Vec_StrFree( vStr ); + } Result = Exa8_ManExactSynthesis(pPars); fflush( stdout ); if ( Result == 1 ) From 6d2bedd6097f2fb598d8ff443add5f9856ab28b9 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 23 Nov 2025 11:58:34 -0800 Subject: [PATCH 36/38] Adding command "cuts". --- src/aig/gia/giaCut.c | 143 +++++++++++++++++++++++++++---------------- src/base/abci/abc.c | 110 +++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+), 54 deletions(-) diff --git a/src/aig/gia/giaCut.c b/src/aig/gia/giaCut.c index 61ce665a7..e3a38dabb 100644 --- a/src/aig/gia/giaCut.c +++ b/src/aig/gia/giaCut.c @@ -29,9 +29,9 @@ ABC_NAMESPACE_IMPL_START /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// -#define GIA_MAX_CUTSIZE 8 -#define GIA_MAX_CUTNUM 257 -#define GIA_MAX_TT_WORDS ((GIA_MAX_CUTSIZE > 6) ? 1 << (GIA_MAX_CUTSIZE-6) : 1) +#define GIA_MAX_CUTSIZE 14 +#define GIA_MAX_CUTNUM 257 +#define GIA_MAX_TT_WORDS ((GIA_MAX_CUTSIZE > 6) ? 1 << (GIA_MAX_CUTSIZE-6) : 1) #define GIA_CUT_NO_LEAF 0xF @@ -649,7 +649,7 @@ void Gia_StoComputeCuts( Gia_Man_t * pGia ) printf( "Cut = %.0f (%.2f %%) ", p->CutCount[3], 100.0*p->CutCount[3]/p->CutCount[0] ); printf( "Cut/Node = %.2f ", p->CutCount[3] / Gia_ManAndNum(p->pGia) ); printf( "\n" ); - printf( "The number of nodes with cut count over the limit (%d cuts) = %d nodes (out of %d). ", + printf( "The number of nodes with maximum cut count (%d cuts) = %d nodes (out of %d). ", p->nCutNum, p->nCutsOver, Gia_ManAndNum(pGia) ); Abc_PrintTime( 0, "Time", Abc_Clock() - p->clkStart ); } @@ -724,7 +724,7 @@ Vec_Wec_t * Gia_ManExtractCuts( Gia_Man_t * pGia, int nCutSize0, int nCuts0, int printf( "Cut = %.0f (%.2f %%) ", p->CutCount[3], 100.0*p->CutCount[3]/p->CutCount[0] ); printf( "Cut/Node = %.2f ", p->CutCount[3] / Gia_ManAndNum(p->pGia) ); printf( "\n" ); - printf( "The number of nodes with cut count over the limit (%d cuts) = %d nodes (out of %d). ", + printf( "The number of nodes with maximum cut count (%d cuts) = %d nodes (out of %d). ", p->nCutNum, p->nCutsOver, Gia_ManAndNum(pGia) ); Abc_PrintTime( 0, "Time", Abc_Clock() - p->clkStart ); } @@ -999,7 +999,7 @@ Vec_Wec_t * Gia_ManExploreCuts( Gia_Man_t * pGia, int nCutSize0, int nCuts0, int printf( "Cut = %.0f (%.2f %%) ", p->CutCount[3], 100.0*p->CutCount[3]/p->CutCount[0] ); printf( "Cut/Node = %.2f ", p->CutCount[3] / Gia_ManAndNum(p->pGia) ); printf( "\n" ); - printf( "The number of nodes with cut count over the limit (%d cuts) = %d nodes (out of %d). ", + printf( "The number of nodes with maximum cut count (%d cuts) = %d nodes (out of %d). ", p->nCutNum, p->nCutsOver, Gia_ManAndNum(pGia) ); Abc_PrintTime( 0, "Time", Abc_Clock() - p->clkStart ); } @@ -1027,12 +1027,12 @@ void Gia_ManExploreCutsTest( Gia_Man_t * pGia, int nCutSize0, int nCuts0, int fV SeeAlso [] ***********************************************************************/ -Gia_Sto_t * Gia_ManMatchCutsInt( Gia_Man_t * pGia, int nCutSize0, int nCutNum0, int fVerbose0 ) +Gia_Sto_t * Gia_ManMatchCutsInt( Gia_Man_t * pGia, int nCutSize0, int nCutNum0, int fTruth0, int fVerbose0 ) { int nCutSize = nCutSize0; int nCutNum = nCutNum0; - int fCutMin = 1; - int fTruthMin = 1; + int fCutMin = fTruth0; + int fTruthMin = fTruth0; int fVerbose = fVerbose0; Gia_Sto_t * p = Gia_StoAlloc( pGia, nCutSize, nCutNum, fCutMin, fTruthMin, fVerbose ); Gia_Obj_t * pObj; int i, iObj; @@ -1057,15 +1057,90 @@ Gia_Sto_t * Gia_ManMatchCutsInt( Gia_Man_t * pGia, int nCutSize0, int nCutNum0, printf( "Cut = %.0f (%.2f %%) ", p->CutCount[3], 100.0*p->CutCount[3]/p->CutCount[0] ); printf( "Cut/Node = %.2f ", p->CutCount[3] / Gia_ManAndNum(p->pGia) ); printf( "\n" ); - printf( "The number of nodes with cut count over the limit (%d cuts) = %d nodes (out of %d). ", + printf( "The number of nodes with maximum cut count (%d cuts) = %d nodes (out of %d). ", p->nCutNum, p->nCutsOver, Gia_ManAndNum(pGia) ); Abc_PrintTime( 0, "Time", Abc_Clock() - p->clkStart ); } return p; } +int Gia_ManCountSelfCuts( Gia_Man_t * p, Gia_Sto_t * pSto ) +{ + Vec_Int_t * vLevel; int i, k, * pCut, nNodes = 0; + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { + Gia_Obj_t * pObj = Gia_ManObj(p, i); + if ( !Gia_ObjIsAnd(pObj) ) + continue; + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) + nNodes += pCut[0] == 2 && pCut[1] == Gia_ObjFaninId0p(p, pObj) && pCut[2] == Gia_ObjFaninId1p(p, pObj); + } + return nNodes; +} + +void Gia_ManDumpCuts( Gia_Man_t * p, Gia_Sto_t * pSto, FILE * pFile, int fVerbose, char * pFileName ) +{ + Vec_Int_t * vLevel; int i, k, c, * pCut, nCuts = 0, nNodes = 0; + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { + if ( !Gia_ObjIsAnd(Gia_ManObj(p, i)) ) + continue; + int nNodeCuts = 0; + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { + if ( pCut[0] == 1 ) + continue; + fprintf( pFile, "%d ", i ); + for ( c = 1; c <= pCut[0]; c++ ) + fprintf( pFile, "%d ", pCut[c] ); + fprintf( pFile, "1\n" ); + nNodeCuts++; + nNodes++; + } + nCuts += nNodeCuts; + } + Gia_Obj_t * pObj; + Gia_ManForEachCo( p, pObj, i ) + fprintf( pFile, "%d %d 0\n", Gia_ObjId(p, pObj), Gia_ObjFaninId0p(p, pObj) ); + if ( fVerbose ) + printf( "Dumped %d cuts for %d nodes into file \"%s\".\n", nCuts, nNodes, pFileName ? pFileName : "stdout" ); +} +void Gia_ManComputeCutsCore( Gia_Man_t * pGia, int nCutSize, int nCutNum, int fTruth, int fVerbose, int fDumpText, int fDumpBin, char * pFileName ) +{ + Gia_Sto_t * pSto = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, fTruth, fVerbose ); + if ( fDumpText ) { + FILE * pFile = pFileName ? fopen(pFileName, "wb") : stdout; + if ( !pFile ) return; + Gia_ManDumpCuts( pGia, pSto, pFile, fVerbose, pFileName ); + } + else if ( fDumpBin ) { + FILE * pFile = pFileName ? fopen(pFileName, "wb") : NULL; + if ( !pFile ) return; + Gia_ManDumpCuts( pGia, pSto, pFile, fVerbose, pFileName ); + } + //printf( "The number of nodes with self-cuts = %d (out of %d).\n", Gia_ManCountSelfCuts(pGia, pSto), Gia_ManAndNum(pGia) ); + Gia_StoFree( pSto ); +} + +Vec_Wec_t * Gia_ManCompute54Cuts( Gia_Man_t * pGia, int fVerbose ) +{ + Gia_Sto_t * pSto = Gia_ManMatchCutsInt( pGia, 5, 16, 0, fVerbose ); + Vec_Wec_t * vRes = Vec_WecAlloc( 1000 ); + Vec_Int_t * vLevel; int i, k, c, * pCut; + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { + if ( !Gia_ObjIsAnd(Gia_ManObj(pGia, i)) ) + continue; + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { + if ( pCut[0] != 4 && pCut[0] != 5 ) + continue; + Vec_Int_t * vCut = Vec_WecPushLevel( vRes ); + for ( c = 1; c <= pCut[0]; c++ ) + Vec_IntPush( vCut, pCut[c] ); + Vec_IntPush( vCut, i ); + } + } + Gia_StoFree( pSto ); + return vRes; +} void Gia_ManMatchCuts( Vec_Mem_t * vTtMem, Gia_Man_t * pGia, int nCutSize, int nCutNum, int fVerbose ) { - Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, fVerbose ); + Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, 1, fVerbose ); Vec_Int_t * vLevel; int i, j, k, * pCut; Vec_Int_t * vNodes = Vec_IntAlloc( 100 ); Vec_Wec_t * vCuts = Vec_WecAlloc( 100 ); @@ -1101,7 +1176,7 @@ void Gia_ManMatchCuts( Vec_Mem_t * vTtMem, Gia_Man_t * pGia, int nCutSize, int n Vec_Ptr_t * Gia_ManMatchCutsArray( Vec_Ptr_t * vTtMems, Gia_Man_t * pGia, int nCutSize, int nCutNum, int fVerbose ) { Vec_Ptr_t * vRes = Vec_PtrAlloc( Vec_PtrSize(vTtMems) ); - Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, fVerbose ); + Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, 1, fVerbose ); Vec_Int_t * vLevel, * vTemp; int i, k, c, * pCut; abctime clkStart = Abc_Clock(); for ( i = 0; i < Vec_PtrSize(vTtMems); i++ ) @@ -1136,7 +1211,7 @@ Vec_Ptr_t * Gia_ManMatchCutsArray( Vec_Ptr_t * vTtMems, Gia_Man_t * pGia, int nC } Vec_Ptr_t * Gia_ManMatchCutsMany( Vec_Mem_t * vTtMem, Vec_Int_t * vMap, int nFuncs, Gia_Man_t * pGia, int nCutSize, int nCutNum, int fVerbose ) { - Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, fVerbose ); + Gia_Sto_t * p = Gia_ManMatchCutsInt( pGia, nCutSize, nCutNum, 1, fVerbose ); Vec_Int_t * vLevel; int i, j, k, * pCut; abctime clkStart = Abc_Clock(); assert( Abc_Truth6WordNum(nCutSize) == Vec_MemEntrySize(vTtMem) ); @@ -1168,46 +1243,6 @@ Vec_Ptr_t * Gia_ManMatchCutsMany( Vec_Mem_t * vTtMem, Vec_Int_t * vMap, int nFun return vRes; } -/**Function************************************************************* - - Synopsis [Function enumeration.] - - Description [] - - SideEffects [] - - SeeAlso [] - -***********************************************************************/ -void Gia_ManDumpCuts( Gia_Man_t * p, int nCutSize, int nCutNum, int fVerbose ) -{ - FILE * pFile = fopen( "input.txt", "wb" ); if ( !pFile ) return; - Gia_Sto_t * pSto = Gia_ManMatchCutsInt( p, nCutSize, nCutNum, 0 ); - Vec_Int_t * vLevel; int i, k, c, * pCut, nCuts = 0, nNodes = 0; - Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { - if ( !Gia_ObjIsAnd(Gia_ManObj(p, i)) ) - continue; - Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { - if ( pCut[0] == 1 ) - continue; - fprintf( pFile, "%d ", i ); - for ( c = 1; c <= pCut[0]; c++ ) - fprintf( pFile, "%d ", pCut[c] ); - fprintf( pFile, "1\n" ); - nCuts += pCut[0]; - nNodes++; - } - } - Gia_Obj_t * pObj; - Gia_ManForEachCo( p, pObj, i ) { - fprintf( pFile, "%d %d 0\n", Gia_ObjId(p, pObj), Gia_ObjFaninId0p(p, pObj) ); - } - fclose( pFile ); - Gia_StoFree( pSto ); - if ( fVerbose ) - printf( "Dumped %d cuts for %d nodes into file \"input.txt\".\n", nCuts, nNodes ); -} - /**Function************************************************************* Synopsis [Function enumeration.] @@ -1221,7 +1256,7 @@ void Gia_ManDumpCuts( Gia_Man_t * p, int nCutSize, int nCutNum, int fVerbose ) ***********************************************************************/ Vec_Wrd_t * Gia_ManCollectCutFuncs( Gia_Man_t * p, int nCutSize, int nCutNum, int fVerbose ) { - Gia_Sto_t * pSto = Gia_ManMatchCutsInt( p, nCutSize, nCutNum, 0 ); + Gia_Sto_t * pSto = Gia_ManMatchCutsInt( p, nCutSize, nCutNum, 1, 0 ); Vec_Wrd_t * vFuncs = Vec_WrdAlloc( 1000 ); Vec_Int_t * vLevel; int i, k, * pCut; Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) if ( pCut[0] == nCutSize ) { diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index fc6592452..ca0ff576c 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -649,6 +649,7 @@ static int Abc_CommandAbc9MulFind ( Abc_Frame_t * pAbc, int argc, cha static int Abc_CommandAbc9MulFind3 ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9BsFind ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9AndCare ( Abc_Frame_t * pAbc, int argc, char ** argv ); +static int Abc_CommandAbc9Cuts ( Abc_Frame_t * pAbc, int argc, char ** argv ); static int Abc_CommandAbc9Test ( Abc_Frame_t * pAbc, int argc, char ** argv ); @@ -1480,6 +1481,7 @@ void Abc_Init( Abc_Frame_t * pAbc ) Cmd_CommandAdd( pAbc, "ABC9", "&mulfind3", Abc_CommandAbc9MulFind3, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&bsfind", Abc_CommandAbc9BsFind, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&andcare", Abc_CommandAbc9AndCare, 0 ); + Cmd_CommandAdd( pAbc, "ABC9", "&cuts", Abc_CommandAbc9Cuts, 0 ); Cmd_CommandAdd( pAbc, "ABC9", "&test", Abc_CommandAbc9Test, 0 ); @@ -58195,6 +58197,114 @@ usage: return 1; } +/**Function************************************************************* + + Synopsis [] + + Description [] + + SideEffects [] + + SeeAlso [] + +***********************************************************************/ +int Abc_CommandAbc9Cuts( Abc_Frame_t * pAbc, int argc, char ** argv ) +{ + extern void Gia_ManComputeCutsCore( Gia_Man_t * pGia, int nCutSize0, int nCutNum0, int fTruth0, int fVerbose0, int fDumpText, int fDumpBin, char * pFileName ); + int nCutSize = 6; + int nCutNum = 16; + int fTruth = 1; + int fVerbose = 1; + int fDumpText = 0; + int fDumpBin = 0; + int c; + char * pFileName = NULL; + Extra_UtilGetoptReset(); + while ( ( c = Extra_UtilGetopt( argc, argv, "KCtdbvh" ) ) != EOF ) + { + switch ( c ) + { + case 'K': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-K\" should be followed by an integer.\n" ); + goto usage; + } + nCutSize = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nCutSize < 0 ) + goto usage; + break; + case 'C': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-C\" should be followed by an integer.\n" ); + goto usage; + } + nCutNum = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( nCutNum < 0 ) + goto usage; + break; + case 't': + fTruth ^= 1; + break; + case 'd': + fDumpText ^= 1; + break; + case 'b': + fDumpBin ^= 1; + break; + case 'v': + fVerbose ^= 1; + break; + case 'h': + goto usage; + default: + goto usage; + } + } + if ( pAbc->pGia == NULL ) + { + Abc_Print( -1, "Abc_CommandAbc9Cuts(): There is no AIG.\n" ); + return 0; + } + if ( argc == globalUtilOptind + 1 ) + pFileName = argv[globalUtilOptind]; + else if ( argc != globalUtilOptind ) + { + Abc_Print( 1,"Abc_CommandAbc9Cuts(): Trailing arguments on the command line.\n" ); + return 0; + } + if ( nCutSize < 2 || nCutSize > 14 ) + { + Abc_Print( -1, "The number of cut leaves should belong to the range: %d <= K <= %d.\n", 2, 14 ); + return 1; + } + if ( nCutNum < 2 || nCutNum > 256 ) + { + Abc_Print( -1, "The number of cuts per node should belong to the range: %d <= C <= %d.\n", 2, 256 ); + return 1; + } + if ( fDumpBin && !pFileName ) + { + Abc_Print( -1, "Output binary file name should be provided on the command line.\n" ); + return 1; + } + Gia_ManComputeCutsCore( pAbc->pGia, nCutSize, nCutNum, fTruth, fVerbose, fDumpText, fDumpBin, pFileName ); + return 0; + +usage: + Abc_Print( -2, "usage: cuts [-KC num] [-tdbvh]\n" ); + Abc_Print( -2, "\t computes K-input cuts for the nodes in the current AIG\n" ); + Abc_Print( -2, "\t-K num : max number of leaves (%d <= num <= %d) [default = %d]\n", 2, 14, nCutSize ); + Abc_Print( -2, "\t-C num : max number of cuts at a node (%d <= num <= %d) [default = %d]\n", 2, 256, nCutNum ); + Abc_Print( -2, "\t-t : toggle truth table computation and cut minimization [default = %s]\n", fTruth? "yes": "no" ); + Abc_Print( -2, "\t-d : toggle dumping cuts into a text file [default = %s]\n", fDumpText? "yes": "no" ); + Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fDumpBin? "yes": "no" ); + Abc_Print( -2, "\t-h : print the command usage\n"); + return 1; +} /**Function************************************************************* From 845de6f3681c9cd3cb3a4858cce6e08ad0456897 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 23 Nov 2025 13:18:01 -0800 Subject: [PATCH 37/38] Adding binary cut dump. --- src/aig/gia/giaCut.c | 129 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/src/aig/gia/giaCut.c b/src/aig/gia/giaCut.c index e3a38dabb..35e3c34ee 100644 --- a/src/aig/gia/giaCut.c +++ b/src/aig/gia/giaCut.c @@ -1075,14 +1075,33 @@ int Gia_ManCountSelfCuts( Gia_Man_t * p, Gia_Sto_t * pSto ) } return nNodes; } - -void Gia_ManDumpCuts( Gia_Man_t * p, Gia_Sto_t * pSto, FILE * pFile, int fVerbose, char * pFileName ) +void Gia_ManEvalCutHashing( Gia_Man_t * p, Gia_Sto_t * pSto ) +{ + Hsh_VecMan_t * pHash = Hsh_VecManStart( 100000 ); + Vec_Int_t vTemp = {0}; + Vec_Int_t * vLevel; int i, k, * pCut, nBytes = 0, nCuts = 0; + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { + Gia_Obj_t * pObj = Gia_ManObj(p, i); + if ( !Gia_ObjIsAnd(pObj) ) + continue; + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { + vTemp.nSize = vTemp.nCap = pCut[0]; + vTemp.pArray = pCut+1; + Hsh_VecManAdd( pHash, &vTemp ); + nBytes += 4*(pCut[0]+1); + nCuts++; + } + } + printf( "Total cuts = %d. Unique = %d. Memory = %.2f MB. With hashing = %.2f MB.\n", + nCuts, Hsh_VecSize(pHash), 1.0*nBytes/(1<<20), Hsh_VecManMemory(pHash)/(1<<20) ); + Hsh_VecManStop( pHash ); +} +void Gia_ManDumpCutsText( Gia_Man_t * p, Gia_Sto_t * pSto, FILE * pFile, int fVerbose, char * pFileName ) { Vec_Int_t * vLevel; int i, k, c, * pCut, nCuts = 0, nNodes = 0; Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { if ( !Gia_ObjIsAnd(Gia_ManObj(p, i)) ) continue; - int nNodeCuts = 0; Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { if ( pCut[0] == 1 ) continue; @@ -1090,16 +1109,104 @@ void Gia_ManDumpCuts( Gia_Man_t * p, Gia_Sto_t * pSto, FILE * pFile, int fVerbos for ( c = 1; c <= pCut[0]; c++ ) fprintf( pFile, "%d ", pCut[c] ); fprintf( pFile, "1\n" ); - nNodeCuts++; - nNodes++; + nCuts++; } - nCuts += nNodeCuts; + nNodes++; } Gia_Obj_t * pObj; Gia_ManForEachCo( p, pObj, i ) fprintf( pFile, "%d %d 0\n", Gia_ObjId(p, pObj), Gia_ObjFaninId0p(p, pObj) ); if ( fVerbose ) - printf( "Dumped %d cuts for %d nodes into file \"%s\".\n", nCuts, nNodes, pFileName ? pFileName : "stdout" ); + printf( "Dumped %d cuts for %d nodes into text file \"%s\".\n", nCuts, nNodes, pFileName ? pFileName : "stdout" ); +} +void Gia_ManDumpCutsPrint( Gia_Man_t * p, Vec_Int_t * vStore, int nCutSize, int nCutNum ) +{ + int o, f, c; + int nObjs = Gia_ManObjNum( p ); + int * pStore = Vec_IntArray( vStore ); + if ( nCutSize == 0 || nCutNum == 0 ) + return; + for ( o = 0; o < nObjs; o++ ) { + Gia_Obj_t * pObj = Gia_ManObj( p, o ); + int * pNodeStore; + if ( !Gia_ObjIsAnd(pObj) && !Gia_ObjIsCo(pObj) ) + continue; + pNodeStore = pStore + o * nCutSize * nCutNum; + printf( "Node %d has %d cuts:\n", o, nCutNum ); + for ( f = 0; f < nCutSize; f++ ) { + printf( "Fanin %d:", f ); + for ( c = 0; c < nCutNum; c++ ) + printf( " %4d", pNodeStore[f * nCutNum + c] ); + printf( "\n" ); + } + } +} +void Gia_ManDumpCutsBin( Gia_Man_t * p, Gia_Sto_t * pSto, FILE * pFile, int nCutSize, int nCutNum, int fVerbose, char * pFileName ) +{ + Vec_Int_t * vLevel; int i, k, c, * pCut, Num, RetValue, nCuts = 0, nNodes = 0; + Vec_Int_t * vStore = Vec_IntStart( Gia_ManObjNum(p) * nCutSize * nCutNum ); + int * pStore = Vec_IntArray( vStore ); + Vec_WecForEachLevel( pSto->vCuts, vLevel, i ) if ( Vec_IntSize(vLevel) ) { + Gia_Obj_t * pObj = Gia_ManObj(p, i); + int CutIndex = 0; + int * pNodeStore; + if ( !Gia_ObjIsAnd(pObj) ) + continue; + pNodeStore = pStore + i * nCutSize * nCutNum; + // flatten cuts as [object][leaf][cut], so each leaf spans nCutNum consecutive entries + // add the mandatory two-leaf cut composed of the current node's fanins + if ( nCutNum > 0 ) { + pNodeStore[CutIndex] = Gia_ObjFaninId0p( p, pObj ); + pNodeStore[nCutNum + CutIndex] = Gia_ObjFaninId1p( p, pObj ); + CutIndex++; + nCuts++; + } + Sdb_ForEachCut( Vec_IntArray(vLevel), pCut, k ) { + if ( pCut[0] == 1 ) + continue; + if ( CutIndex >= nCutNum ) + break; + assert( pCut[0] <= nCutSize ); + for ( c = 0; c < pCut[0]; c++ ) + pNodeStore[c * nCutNum + CutIndex] = pCut[c+1]; + CutIndex++; + nCuts++; + } + nNodes++; + } + // add unit cuts for primary outputs driven by arbitrary objects (const, PI, or internal node) + if ( nCutSize > 0 && nCutNum > 0 ) { + Gia_Obj_t * pObj; + Gia_ManForEachCo( p, pObj, i ) { + int ObjId = Gia_ObjId( p, pObj ); + int * pNodeStore = pStore + ObjId * nCutSize * nCutNum; + pNodeStore[0] = Gia_ObjFaninId0p( p, pObj ); + nCuts++; + } + } + // the number of dimension + Num = 3; + RetValue = fwrite( &Num, 4, 1, pFile ); + assert( RetValue == 1 ); + // the number of objects + Num = Gia_ManObjNum(p); + RetValue = fwrite( &Num, 4, 1, pFile ); + assert( RetValue == 1 ); + // the cut size + Num = nCutSize; + RetValue = fwrite( &Num, 4, 1, pFile ); + assert( RetValue == 1 ); + // the cut count + Num = nCutNum; + RetValue = fwrite( &Num, 4, 1, pFile ); + assert( RetValue == 1 ); + // the cuts themselves + RetValue = fwrite( Vec_IntArray(vStore), 4, Vec_IntSize(vStore), pFile ); + assert( RetValue == Vec_IntSize(vStore) ); + if ( fVerbose ) + printf( "Dumped %d cuts for %d nodes into binary file \"%s\" (%.2f MB).\n", nCuts, nNodes, pFileName, Vec_IntMemory(vStore)/(1<<20) ); + //Gia_ManDumpCutsPrint( p, vStore, nCutSize, nCutNum ); + Vec_IntFree( vStore ); } void Gia_ManComputeCutsCore( Gia_Man_t * pGia, int nCutSize, int nCutNum, int fTruth, int fVerbose, int fDumpText, int fDumpBin, char * pFileName ) { @@ -1107,14 +1214,17 @@ void Gia_ManComputeCutsCore( Gia_Man_t * pGia, int nCutSize, int nCutNum, int fT if ( fDumpText ) { FILE * pFile = pFileName ? fopen(pFileName, "wb") : stdout; if ( !pFile ) return; - Gia_ManDumpCuts( pGia, pSto, pFile, fVerbose, pFileName ); + Gia_ManDumpCutsText( pGia, pSto, pFile, fVerbose, pFileName ); + fclose( pFile ); } else if ( fDumpBin ) { FILE * pFile = pFileName ? fopen(pFileName, "wb") : NULL; if ( !pFile ) return; - Gia_ManDumpCuts( pGia, pSto, pFile, fVerbose, pFileName ); + Gia_ManDumpCutsBin( pGia, pSto, pFile, nCutSize, nCutNum, fVerbose, pFileName ); + fclose( pFile ); } //printf( "The number of nodes with self-cuts = %d (out of %d).\n", Gia_ManCountSelfCuts(pGia, pSto), Gia_ManAndNum(pGia) ); + //Gia_ManEvalCutHashing( pGia, pSto ); Gia_StoFree( pSto ); } @@ -1461,4 +1571,3 @@ void Gia_ManMatchConesOutput( Gia_Man_t * pBig, Gia_Man_t * pSmall, int nCutNum, ABC_NAMESPACE_IMPL_END - From ba852596b4a11e492e9682662a3e8d1a9be4d765 Mon Sep 17 00:00:00 2001 From: Alan Mishchenko Date: Sun, 23 Nov 2025 15:05:46 -0800 Subject: [PATCH 38/38] Adduing supporrt for dumping binary file with matches. --- src/aig/gia/gia.h | 1 + src/aig/gia/giaNf.c | 161 ++++++++++++++++++++++++++++++++++++++++++-- src/base/abci/abc.c | 18 ++++- 3 files changed, 173 insertions(+), 7 deletions(-) diff --git a/src/aig/gia/gia.h b/src/aig/gia/gia.h index 098892f85..0799a0c96 100644 --- a/src/aig/gia/gia.h +++ b/src/aig/gia/gia.h @@ -374,6 +374,7 @@ struct Jf_Par_t_ int nCutNumMax; int nProcNumMax; int nLutSizeMux; + int nMaxMatches; word Delay; word Area; word Edge; diff --git a/src/aig/gia/giaNf.c b/src/aig/gia/giaNf.c index b38093f23..7df056ba8 100644 --- a/src/aig/gia/giaNf.c +++ b/src/aig/gia/giaNf.c @@ -2241,9 +2241,159 @@ void Nf_ManDumpMatches( Nf_Man_t * p ) Nf_CutForEachVarCompl( pCut, pM->Cfg, iVar, fCompl, k ) fprintf( pFile, " %d", Abc_Var2Lit(iVar, fCompl) ); fprintf( pFile, "\n" ); - } + } fclose( pFile ); } +void Nf_ManDumpMatchesPrint( Gia_Man_t * pGia, Vec_Int_t * vStore, int nCutSize, int nMaxMatches ) +{ + int iObj, n, f, m; + int nObjs = Gia_ManObjNum( pGia ); + int * pData; + if ( vStore == NULL || nCutSize == 0 || nMaxMatches == 0 ) + return; + pData = Vec_IntArray( vStore ); + for ( iObj = 0; iObj < nObjs; iObj++ ) + { + Gia_Obj_t * pObj = Gia_ManObj( pGia, iObj ); + int fPrint = 0; + if ( Gia_ObjIsAnd(pObj) && !Gia_ObjIsBuf(pObj) ) + fPrint = 1; + else if ( Gia_ObjIsCo(pObj) ) + fPrint = 1; + if ( !fPrint ) + continue; + for ( n = 0; n < 2; n++ ) + { + int * pNodeStore = pData + (2 * iObj + n) * nCutSize * nMaxMatches; + printf( "Node %d (%s) polarity %d has %d matches:\n", iObj, Gia_ObjIsCo(pObj) ? "CO" : "AND", n, nMaxMatches ); + for ( f = 0; f < nCutSize; f++ ) + { + printf( " Input %d:", f ); + for ( m = 0; m < nMaxMatches; m++ ) + printf( " %4d", pNodeStore[f * nMaxMatches + m] ); + printf( "\n" ); + } + } + } +} +void Nf_ManDumpMatchesBin( Nf_Man_t * p, int nMaxMatches ) +{ + const char * pNameNA = "n/a"; + Gia_Obj_t * pObj; + Vec_Int_t * vStore; + int * pData; + int iObj, n, nMatches = 0; + int nCutSize = p->pPars->nLutSize; + int nObjs = Gia_ManObjNum(p->pGia); + char * pFileNameBin = NULL, * pFileNameGates = NULL; + FILE * pFileBin = NULL, * pFileGates = NULL; + if ( nMaxMatches <= 0 ) + return; + if ( p->pPars->ZFile == NULL ) + return; + assert( nCutSize > 0 && nCutSize <= NF_LEAF_MAX ); + vStore = Vec_IntStart( 2 * nObjs * nCutSize * nMaxMatches ); + pData = Vec_IntArray( vStore ); + pFileNameBin = Abc_UtilStrsav( Extra_FileNameGenericAppend( p->pPars->ZFile, ".bin" ) ); + pFileNameGates = Abc_UtilStrsav( Extra_FileNameGenericAppend( p->pPars->ZFile, ".gates" ) ); + pFileBin = fopen( pFileNameBin, "wb" ); + pFileGates = fopen( pFileNameGates, "wb" ); + if ( pFileBin == NULL || pFileGates == NULL ) { + printf( "Cannot open match dump files \"%s\" and \"%s\".\n", pFileNameBin, pFileNameGates ); + if ( pFileBin ) fclose( pFileBin ); + if ( pFileGates ) fclose( pFileGates ); + ABC_FREE( pFileNameBin ); + ABC_FREE( pFileNameGates ); + Vec_IntFree( vStore ); + return; + } + for ( iObj = 0; iObj < nObjs; iObj++ ) { + pObj = Gia_ManObj( p->pGia, iObj ); + assert( !Gia_ObjIsBuf(pObj) ); + for ( n = 0; n < 2; n++ ) { + int Slot = 0; + int k; + int LitBuffer[NF_LEAF_MAX]; + int * pNodeStore = pData + (2 * iObj + n) * nCutSize * nMaxMatches; + memset( pNodeStore, 0, sizeof(int) * nCutSize * nMaxMatches ); + if ( Gia_ObjIsCo(pObj) && n == 0 && Slot < nMaxMatches ) { + pNodeStore[Slot] = Gia_ObjFaninLit0p( p->pGia, pObj ); + fprintf( pFileGates, "%s %.2f\n", pNameNA, 0.0 ); + Slot++; + nMatches++; + } + if ( Gia_ObjIsAnd(pObj) ) { + int c, * pCut, * pCutSet = Nf_ObjCutSet( p, iObj ); + Nf_SetForEachCut( pCutSet, pCut, c ) + { + int iFuncLit, fComplExt; + Vec_Int_t * vVec; + int j, Info, Offset; + if ( Slot == nMaxMatches ) + break; + if ( Abc_Lit2Var(Nf_CutFunc(pCut)) >= Vec_WecSize(p->vTt2Match) ) + continue; + if ( Nf_CutIsTriv(pCut, iObj) ) + continue; + assert( Nf_CutSize(pCut) <= nCutSize ); + iFuncLit = Nf_CutFunc(pCut); + fComplExt = Abc_LitIsCompl(iFuncLit); + vVec = Vec_WecEntry( p->vTt2Match, Abc_Lit2Var(iFuncLit) ); + Vec_IntForEachEntryDouble( vVec, Info, Offset, j ) + { + Nf_Cfg_t Cfg = Nf_Int2Cfg( Offset ); + int fCompl = Cfg.fCompl ^ fComplExt; + Mio_Cell2_t * pCell = NULL; + const char * pGateName; + float Area = 0.0; + int iFanin, fComplF, nLitCount = 0; + if ( fCompl != n ) + continue; + if ( Slot == nMaxMatches ) + break; + if ( Info >= 0 ) + pCell = Nf_ManCell( p, Info ); + pGateName = (pCell && pCell->pName) ? pCell->pName : pNameNA; + Area = pCell ? pCell->AreaF : 0.0f; + Nf_CutForEachVarCompl( pCut, Cfg, iFanin, fComplF, k ) + LitBuffer[nLitCount++] = Abc_Var2Lit( iFanin, fComplF ); + for ( k = 0; k < nCutSize; k++ ) + pNodeStore[k * nMaxMatches + Slot] = 0; + for ( k = 0; k < nLitCount; k++ ) + pNodeStore[k * nMaxMatches + Slot] = LitBuffer[k]; + fprintf( pFileGates, "%s %.2f\n", pGateName, Area ); + Slot++; + nMatches++; + } + } + } + while ( Slot < nMaxMatches ) { + fprintf( pFileGates, "%s %.2f\n", pNameNA, 0.0 ); + Slot++; + } + } + } + { + int Num = 3; + fwrite( &Num, 4, 1, pFileBin ); + Num = 2 * nObjs; + fwrite( &Num, 4, 1, pFileBin ); + Num = nCutSize; + fwrite( &Num, 4, 1, pFileBin ); + Num = nMaxMatches; + fwrite( &Num, 4, 1, pFileBin ); + } + fwrite( pData, 4, Vec_IntSize(vStore), pFileBin ); + if ( p->pPars->fVerbose ) + printf( "Dumped %d matches (limit %d) into binary file \"%s\" (%.2f MB).\n", + nMatches, nMaxMatches, pFileNameBin, Vec_IntMemory(vStore)/(1<<20) ); + fclose( pFileBin ); + fclose( pFileGates ); + //Nf_ManDumpMatchesPrint( p->pGia, vStore, nCutSize, nMaxMatches ); + Vec_IntFree( vStore ); + ABC_FREE( pFileNameBin ); + ABC_FREE( pFileNameGates ); +} /**Function************************************************************* @@ -2300,8 +2450,12 @@ Gia_Man_t * Nf_ManDeriveMapping( Nf_Man_t * p ) } // assert( Vec_IntCap(vMapping) == 16 || Vec_IntSize(vMapping) == Vec_IntCap(vMapping) ); p->pGia->vCellMapping = vMapping; - if ( p->pPars->ZFile ) - Nf_ManDumpMatches( p ); + if ( p->pPars->ZFile ) { + if ( p->pPars->nMaxMatches ) + Nf_ManDumpMatchesBin( p, p->pPars->nMaxMatches ); + else + Nf_ManDumpMatches( p ); + } return p->pGia; } void Nf_ManUpdateStats( Nf_Man_t * p ) @@ -2775,4 +2929,3 @@ Gia_Man_t * Nf_ManPerformMapping( Gia_Man_t * p, Jf_Par_t * pPars ) ABC_NAMESPACE_IMPL_END - diff --git a/src/base/abci/abc.c b/src/base/abci/abc.c index ca0ff576c..75130bedd 100644 --- a/src/base/abci/abc.c +++ b/src/base/abci/abc.c @@ -44894,7 +44894,7 @@ int Abc_CommandAbc9Nf( Abc_Frame_t * pAbc, int argc, char ** argv ) Gia_Man_t * pNew; int c; Nf_ManSetDefaultPars( pPars ); Extra_UtilGetoptReset(); - while ( ( c = Extra_UtilGetopt( argc, argv, "KCFARLEDQWZakpqfvwh" ) ) != EOF ) + while ( ( c = Extra_UtilGetopt( argc, argv, "KCFARLEDQMWZakpqfvwh" ) ) != EOF ) { switch ( c ) { @@ -44995,7 +44995,7 @@ int Abc_CommandAbc9Nf( Abc_Frame_t * pAbc, int argc, char ** argv ) case 'Q': if ( globalUtilOptind >= argc ) { - Abc_Print( -1, "Command line switch \"-D\" should be followed by an integer number.\n" ); + Abc_Print( -1, "Command line switch \"-Q\" should be followed by an integer number.\n" ); goto usage; } pPars->nReqTimeFlex = atoi(argv[globalUtilOptind]); @@ -45003,6 +45003,17 @@ int Abc_CommandAbc9Nf( Abc_Frame_t * pAbc, int argc, char ** argv ) if ( pPars->nReqTimeFlex < 0 ) goto usage; break; + case 'M': + if ( globalUtilOptind >= argc ) + { + Abc_Print( -1, "Command line switch \"-M\" should be followed by an integer number.\n" ); + goto usage; + } + pPars->nMaxMatches = atoi(argv[globalUtilOptind]); + globalUtilOptind++; + if ( pPars->nMaxMatches < 0 ) + goto usage; + break; case 'W': if ( globalUtilOptind >= argc ) { @@ -45076,7 +45087,7 @@ usage: sprintf(Buffer, "best possible" ); else sprintf(Buffer, "%d", pPars->DelayTarget ); - Abc_Print( -2, "usage: &nf [-KCFARLEDQ num] [-Z file] [-akpqfvwh]\n" ); + Abc_Print( -2, "usage: &nf [-KCFARLEDQM num] [-Z file] [-akpqfvwh]\n" ); Abc_Print( -2, "\t performs technology mapping of the network\n" ); Abc_Print( -2, "\t-K num : LUT size for the mapping (2 <= K <= %d) [default = %d]\n", pPars->nLutSizeMax, pPars->nLutSize ); Abc_Print( -2, "\t-C num : the max number of priority cuts (1 <= C <= %d) [default = %d]\n", pPars->nCutNumMax, pPars->nCutNum ); @@ -45087,6 +45098,7 @@ usage: Abc_Print( -2, "\t-E num : the area/edge tradeoff parameter (0 <= num <= 100) [default = %d]\n", pPars->nAreaTuner ); Abc_Print( -2, "\t-D num : sets the delay constraint for the mapping [default = %s]\n", Buffer ); Abc_Print( -2, "\t-Q num : internal parameter impacting area of the mapping [default = %d]\n", pPars->nReqTimeFlex ); + Abc_Print( -2, "\t-M num : the max number of matches to dump into a binary file [default = %d]\n", pPars->nMaxMatches ); Abc_Print( -2, "\t-Z file : the output file name to dump internal match info [default = unused]\n" ); Abc_Print( -2, "\t-a : toggles SAT-based area-oriented mapping (experimental) [default = %s]\n", pPars->fAreaOnly? "yes": "no" ); Abc_Print( -2, "\t-k : toggles coarsening the subject graph [default = %s]\n", pPars->fCoarsen? "yes": "no" );