mirror of https://github.com/YosysHQ/abc.git
Merge remote-tracking branch 'upstream/master' into yosys-experimental
This commit is contained in:
commit
3b36aa1573
2
Makefile
2
Makefile
|
|
@ -36,7 +36,7 @@ MODULES := \
|
|||
src/misc/mem src/misc/bar src/misc/bbl src/misc/parse \
|
||||
src/opt/cut src/opt/fxu src/opt/fxch src/opt/rwr src/opt/mfs src/opt/sim \
|
||||
src/opt/ret src/opt/fret src/opt/res src/opt/lpk src/opt/nwk src/opt/rwt src/opt/rar \
|
||||
src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd src/opt/eslim \
|
||||
src/opt/cgt src/opt/csw src/opt/dar src/opt/dau src/opt/dsc src/opt/sfm src/opt/sbd src/opt/eslim src/opt/ufar src/opt/untk src/opt/util \
|
||||
src/sat/bsat src/sat/xsat src/sat/satoko src/sat/csat src/sat/msat src/sat/psat src/sat/cnf src/sat/bmc src/sat/glucose src/sat/glucose2 src/sat/kissat src/sat/cadical \
|
||||
src/bool/bdc src/bool/deco src/bool/dec src/bool/kit src/bool/lucky \
|
||||
src/bool/rsb src/bool/rpo \
|
||||
|
|
|
|||
12
abclib.dsp
12
abclib.dsp
|
|
@ -2911,6 +2911,10 @@ SOURCE=.\src\sat\cadical\cadical_averages.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\sat\cadical\cadical_backbone.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\sat\cadical\cadical_backtrack.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
@ -3243,6 +3247,14 @@ SOURCE=.\src\sat\cadical\cadical_walk.cpp
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\sat\cadical\cadical_walk_full_occs.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\sat\cadical\cadical_warmup.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\src\sat\cadical\cadical_watch.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
|||
|
|
@ -238,6 +238,22 @@ Gia_Man_t * Gia_ManRandSyn( Gia_Man_t * p, unsigned random_seed )
|
|||
return pRes;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
Gia_Man_t * Gia_ManDeepSyn2( Gia_Man_t * pGia, int nIters, int nNoImpr, int TimeOut, int nAnds, int Seed, int fUseTwo, int fChoices, int fVerbose )
|
||||
{
|
||||
return Gia_ManDeepSyn( pGia, nIters, nNoImpr, TimeOut, nAnds, Seed, fUseTwo, fChoices, fVerbose );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -3586,6 +3586,8 @@ Gia_Man_t * Gia_ManDupZeroUndc( Gia_Man_t * p, char * pInit, int nNewPis, int fG
|
|||
// map X-valued flops into new PIs
|
||||
assert( (int)strlen(pInit) == Gia_ManRegNum(p) );
|
||||
pPiLits = ABC_FALLOC( int, Gia_ManRegNum(p) );
|
||||
for ( i = 0; i < Gia_ManRegNum(p); i++ )
|
||||
pPiLits[i] = -1;
|
||||
for ( i = 0; i < Gia_ManRegNum(p); i++ )
|
||||
if ( pInit[i] == 'x' || pInit[i] == 'X' )
|
||||
pPiLits[i] = CountPis++;
|
||||
|
|
@ -3625,7 +3627,6 @@ Gia_Man_t * Gia_ManDupZeroUndc( Gia_Man_t * p, char * pInit, int nNewPis, int fG
|
|||
assert( 0 );
|
||||
}
|
||||
Gia_ManCleanMark0( p );
|
||||
ABC_FREE( pPiLits );
|
||||
// build internal nodes
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
|
||||
|
|
@ -3644,6 +3645,56 @@ Gia_Man_t * Gia_ManDupZeroUndc( Gia_Man_t * p, char * pInit, int nNewPis, int fG
|
|||
Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) + (int)(CountPis > Gia_ManPiNum(p)) );
|
||||
if ( fVerbose )
|
||||
printf( "Converted %d 1-valued FFs and %d DC-valued FFs.\n", Count1, CountPis-Gia_ManPiNum(p) );
|
||||
// propagate CI names if present and extend with init-value drivers
|
||||
if ( p->vNamesIn )
|
||||
{
|
||||
int nOldPis = Gia_ManPiNum(p);
|
||||
int nNewInitPis = CountPis - nOldPis;
|
||||
int hasResetCi = CountPis > nOldPis;
|
||||
Vec_Ptr_t * vNamesIn = Vec_PtrAlloc( Gia_ManCiNum(pNew) );
|
||||
// original PIs
|
||||
for ( i = 0; i < nOldPis && i < Vec_PtrSize(p->vNamesIn); i++ )
|
||||
Vec_PtrPush( vNamesIn, Abc_UtilStrsav( (char *)Vec_PtrEntry(p->vNamesIn, i) ) );
|
||||
// new PIs for X-init flops
|
||||
for ( i = 0; i < nNewInitPis; i++ )
|
||||
Vec_PtrPush( vNamesIn, NULL );
|
||||
// extra user-added PIs (nNewPis)
|
||||
for ( i = 0; i < nNewPis; i++ )
|
||||
Vec_PtrPush( vNamesIn, NULL );
|
||||
// flop outputs (ROs)
|
||||
for ( i = 0; i < Gia_ManRegNum(p); i++ )
|
||||
{
|
||||
int idxOld = nOldPis + i;
|
||||
char * pNameRo = (idxOld < Vec_PtrSize(p->vNamesIn)) ? (char *)Vec_PtrEntry(p->vNamesIn, idxOld) : NULL;
|
||||
Vec_PtrPush( vNamesIn, pNameRo ? Abc_UtilStrsav(pNameRo) : NULL );
|
||||
}
|
||||
// reset CI name, if any
|
||||
if ( hasResetCi )
|
||||
Vec_PtrPush( vNamesIn, Abc_UtilStrsav( "init_reset" ) );
|
||||
// fill in names for new init PIs using corresponding flop names
|
||||
for ( i = 0; i < Gia_ManRegNum(p); i++ )
|
||||
{
|
||||
if ( pPiLits[i] == -1 )
|
||||
continue;
|
||||
int idxOldRo = nOldPis + i;
|
||||
char * pBase = (idxOldRo < Vec_PtrSize(p->vNamesIn)) ? (char *)Vec_PtrEntry(p->vNamesIn, idxOldRo) : NULL;
|
||||
char Buffer[100];
|
||||
if ( pBase && strlen(pBase) < sizeof(Buffer)-12 )
|
||||
sprintf( Buffer, "%s_init_val", pBase );
|
||||
else
|
||||
sprintf( Buffer, "init_val_%d", i );
|
||||
Vec_PtrWriteEntry( vNamesIn, pPiLits[i], Abc_UtilStrsav(Buffer) );
|
||||
}
|
||||
pNew->vNamesIn = vNamesIn;
|
||||
}
|
||||
if ( p->vNamesOut )
|
||||
{
|
||||
Vec_Ptr_t * vNamesOut = Vec_PtrAlloc( Vec_PtrSize(p->vNamesOut) );
|
||||
for ( i = 0; i < Vec_PtrSize(p->vNamesOut); i++ )
|
||||
Vec_PtrPush( vNamesOut, Abc_UtilStrsav( (char *)Vec_PtrEntry(p->vNamesOut, i) ) );
|
||||
pNew->vNamesOut = vNamesOut;
|
||||
}
|
||||
ABC_FREE( pPiLits );
|
||||
return pNew;
|
||||
}
|
||||
|
||||
|
|
@ -6163,6 +6214,62 @@ Gia_Man_t * Gia_ManDupCofs( Gia_Man_t * p, Vec_Int_t * vVarNums )
|
|||
Gia_ManStop( pTemp );
|
||||
return pNew;
|
||||
}
|
||||
Gia_Man_t * Gia_ManDupUnCofs( Gia_Man_t * p, Vec_Int_t * vVarNums )
|
||||
{
|
||||
Gia_Man_t * pNew, * pTemp; Gia_Obj_t * pObj;
|
||||
Vec_Int_t * vOutLits, * vVarLits, * vTemp;
|
||||
int i, v, g, nVars = Vec_IntSize(vVarNums);
|
||||
int nMints = 1 << nVars;
|
||||
int nOrigCos;
|
||||
assert( Gia_ManRegNum(p) == 0 );
|
||||
assert( nMints > 0 );
|
||||
assert( Gia_ManCoNum(p) % nMints == 0 );
|
||||
nOrigCos = Gia_ManCoNum(p) / nMints;
|
||||
vVarLits = Vec_IntStartFull( nVars );
|
||||
pNew = Gia_ManStart( Gia_ManObjNum(p) + Gia_ManCoNum(p) );
|
||||
pNew->pName = Abc_UtilStrsav( p->pName );
|
||||
Gia_ManFillValue( p );
|
||||
Gia_ManConst0(p)->Value = 0;
|
||||
Gia_ManForEachCi( p, pObj, i )
|
||||
{
|
||||
pObj->Value = Gia_ManAppendCi( pNew );
|
||||
if ( (v = Vec_IntFind( vVarNums, i )) >= 0 )
|
||||
Vec_IntWriteEntry( vVarLits, v, pObj->Value );
|
||||
}
|
||||
Vec_IntForEachEntry( vVarLits, g, i )
|
||||
assert( g >= 0 );
|
||||
Gia_ManHashAlloc( pNew );
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
pObj->Value = Gia_ManHashAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
|
||||
vOutLits = Vec_IntAlloc( Gia_ManCoNum(p) );
|
||||
Gia_ManForEachCo( p, pObj, i )
|
||||
Vec_IntPush( vOutLits, Gia_ObjFanin0Copy(pObj) );
|
||||
vTemp = Vec_IntAlloc( nMints );
|
||||
for ( i = 0; i < nOrigCos; i++ )
|
||||
{
|
||||
Vec_IntFill( vTemp, nMints, 0 );
|
||||
for ( g = 0; g < nMints; g++ )
|
||||
Vec_IntWriteEntry( vTemp, g, Vec_IntEntry(vOutLits, g * nOrigCos + i) );
|
||||
for ( v = 0; v < nVars; v++ )
|
||||
{
|
||||
int Stride = 1 << v;
|
||||
for ( g = 0; g < nMints; g += 2 * Stride )
|
||||
{
|
||||
int iLit0 = Vec_IntEntry( vTemp, g );
|
||||
int iLit1 = Vec_IntEntry( vTemp, g + Stride );
|
||||
int iLitR = Gia_ManHashMux( pNew, Vec_IntEntry( vVarLits, v ), iLit1, iLit0 );
|
||||
Vec_IntWriteEntry( vTemp, g, iLitR );
|
||||
}
|
||||
}
|
||||
Gia_ManAppendCo( pNew, Vec_IntEntry( vTemp, 0 ) );
|
||||
}
|
||||
Vec_IntFree( vTemp );
|
||||
Vec_IntFree( vOutLits );
|
||||
Vec_IntFree( vVarLits );
|
||||
pNew = Gia_ManCleanup( pTemp = pNew );
|
||||
Gia_ManStop( pTemp );
|
||||
return pNew;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
|
|
@ -6673,4 +6780,3 @@ Gia_Man_t * Gia_ManDupExtractMffc( Gia_Man_t * p, Vec_Int_t * vLits, Vec_Int_t *
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -1866,6 +1866,72 @@ void Gia_ManDumpIoList( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse )
|
|||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
static Vec_Bit_t * Gia_ManCollectMultiBits( Vec_Ptr_t * vNames, int n )
|
||||
{
|
||||
Vec_Bit_t * vBits = Vec_BitStart( n );
|
||||
if ( n == 0 )
|
||||
return vBits;
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( n > 1 )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < n; i++ )
|
||||
Vec_BitWriteEntry( vBits, i, 1 );
|
||||
}
|
||||
return vBits;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = Gia_ManCountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
int nNames = Vec_PtrSize( vNames );
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : nNames;
|
||||
int k;
|
||||
if ( iNameNext - iName <= 1 )
|
||||
continue;
|
||||
for ( k = iName; k < iNameNext && k < n; k++ )
|
||||
Vec_BitWriteEntry( vBits, k, 1 );
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
return vBits;
|
||||
}
|
||||
static int Gia_ManDumpIoListMulti( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
int nNames = vNames ? Vec_PtrSize(vNames) : (fOuts ? Gia_ManCoNum(p) : Gia_ManCiNum(p));
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( nNames > 1 )
|
||||
{
|
||||
fprintf( pFile, "_%c_", fOuts ? 'o' : 'i' );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = Gia_ManCountSymbsAll( vNames );
|
||||
int nGroups = Vec_IntSize(vArray) / 2;
|
||||
int idx, fFirst = 1;
|
||||
for ( idx = 0; idx < nGroups; idx++ )
|
||||
{
|
||||
int g = fReverse ? (nGroups - 1 - idx) : idx;
|
||||
int iName = Vec_IntEntry(vArray, 2*g);
|
||||
int Size = Vec_IntEntry(vArray, 2*g + 1);
|
||||
int iNameNext = (g + 1 < nGroups) ? Vec_IntEntry(vArray, 2*(g + 1)) : nNames;
|
||||
if ( iNameNext - iName <= 1 )
|
||||
continue;
|
||||
if ( !fFirst )
|
||||
fprintf( pFile, ", " );
|
||||
Gia_ManPrintOneName( pFile, (char *)Vec_PtrEntry(vNames, iName), Size );
|
||||
fFirst = 0;
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
return !fFirst;
|
||||
}
|
||||
}
|
||||
void Gia_ManDumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
|
|
@ -1943,17 +2009,30 @@ void Gia_ManDumpInterface( Gia_Man_t * p, char * pFileName )
|
|||
Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManDumpIoList( p, pFile, 0, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManDumpIoList( p, pFile, 1, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
{
|
||||
Vec_Bit_t * vMultiIn = Gia_ManCollectMultiBits( p->vNamesIn, Gia_ManCiNum(p) );
|
||||
Vec_Bit_t * vMultiOut = Gia_ManCollectMultiBits( p->vNamesOut, Gia_ManCoNum(p) );
|
||||
int fHasMultiIn = Vec_BitCount( vMultiIn );
|
||||
int fHasMultiOut = Vec_BitCount( vMultiOut );
|
||||
if ( fHasMultiIn )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, vMultiIn, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManDumpIoListMulti( p, pFile, 0, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
if ( fHasMultiOut )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManDumpIoListMulti( p, pFile, 1, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, vMultiOut, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
Vec_BitFree( vMultiIn );
|
||||
Vec_BitFree( vMultiOut );
|
||||
}
|
||||
|
||||
if ( Vec_BitCount(vUsed) )
|
||||
{
|
||||
|
|
@ -2054,17 +2133,30 @@ void Gia_ManDumpInterfaceAssign( Gia_Man_t * p, char * pFileName )
|
|||
Gia_ManWriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, NULL, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManDumpIoList( p, pFile, 0, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManDumpIoList( p, pFile, 1, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, NULL, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
{
|
||||
Vec_Bit_t * vMultiIn = Gia_ManCollectMultiBits( p->vNamesIn, Gia_ManCiNum(p) );
|
||||
Vec_Bit_t * vMultiOut = Gia_ManCollectMultiBits( p->vNamesOut, Gia_ManCoNum(p) );
|
||||
int fHasMultiIn = Vec_BitCount( vMultiIn );
|
||||
int fHasMultiOut = Vec_BitCount( vMultiOut );
|
||||
if ( fHasMultiIn )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManWriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, vMultiIn, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManDumpIoListMulti( p, pFile, 0, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
if ( fHasMultiOut )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
Gia_ManDumpIoListMulti( p, pFile, 1, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
Gia_ManWriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, vMultiOut, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
Vec_BitFree( vMultiIn );
|
||||
Vec_BitFree( vMultiOut );
|
||||
}
|
||||
|
||||
if ( Vec_BitCount(vUsed) )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,10 +90,10 @@ struct Abc_Aig_t_
|
|||
static unsigned Abc_HashKey2( Abc_Obj_t * p0, Abc_Obj_t * p1, int TableSize )
|
||||
{
|
||||
unsigned Key = 0;
|
||||
Key ^= Abc_ObjRegular(p0)->Id * 7937;
|
||||
Key ^= Abc_ObjRegular(p1)->Id * 2971;
|
||||
Key ^= Abc_ObjIsComplement(p0) * 911;
|
||||
Key ^= Abc_ObjIsComplement(p1) * 353;
|
||||
Key ^= (unsigned)Abc_ObjRegular(p0)->Id * 7937;
|
||||
Key ^= (unsigned)Abc_ObjRegular(p1)->Id * 2971;
|
||||
Key ^= (unsigned)Abc_ObjIsComplement(p0) * 911;
|
||||
Key ^= (unsigned)Abc_ObjIsComplement(p1) * 353;
|
||||
return Key % TableSize;
|
||||
}
|
||||
|
||||
|
|
@ -905,7 +905,7 @@ void Abc_AigReplace_int( Abc_Aig_t * pMan, Abc_Obj_t * pOld, Abc_Obj_t * pNew, i
|
|||
{
|
||||
Abc_ObjSetReverseLevel( pFanin1, Abc_ObjReverseLevel(pOld) );
|
||||
assert( pFanin1->fMarkB == 0 );
|
||||
if ( !Abc_ObjIsCi(pFanin1) )
|
||||
if ( !Abc_ObjIsCi(pFanin1) && !Abc_AigNodeIsConst(pFanin1) )
|
||||
{
|
||||
pFanin1->fMarkB = 1;
|
||||
Vec_VecPush( pMan->vLevelsR, Abc_ObjReverseLevel(pFanin1), pFanin1 );
|
||||
|
|
@ -1139,7 +1139,7 @@ void Abc_AigUpdateLevelR_int( Abc_Aig_t * pMan )
|
|||
// iterate through the fanins
|
||||
Abc_ObjForEachFanin( pNode, pFanin, v )
|
||||
{
|
||||
if ( Abc_ObjIsCi(pFanin) )
|
||||
if ( Abc_ObjIsCi(pFanin) || Abc_AigNodeIsConst(pFanin) )
|
||||
continue;
|
||||
// get the new reverse level of this fanin
|
||||
LevelNew = 0;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
***********************************************************************/
|
||||
|
||||
#include "abc.h"
|
||||
#include <ctype.h>
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
|
|
@ -573,10 +574,749 @@ void Abc_NtkInsertHierarchyGia( Abc_Ntk_t * pNtk, Abc_Ntk_t * pNew, int fVerbose
|
|||
Gia_ManInsertOne( pModel, pNew );
|
||||
}
|
||||
|
||||
static Vec_Bit_t * GiaHie_GenUsed( Gia_Man_t * p, int fBuf )
|
||||
{
|
||||
Gia_Obj_t * pObj; int i;
|
||||
Vec_Bit_t * vUsed = Vec_BitStart( Gia_ManObjNum(p) );
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
{
|
||||
if ( fBuf )
|
||||
Vec_BitWriteEntry( vUsed, i, 1 );
|
||||
if ( Gia_ObjFaninC0(pObj) ^ fBuf )
|
||||
Vec_BitWriteEntry( vUsed, Gia_ObjFaninId0(pObj, i), 1 );
|
||||
if ( Gia_ObjFaninC1(pObj) ^ fBuf )
|
||||
Vec_BitWriteEntry( vUsed, Gia_ObjFaninId1(pObj, i), 1 );
|
||||
}
|
||||
Gia_ManForEachCo( p, pObj, i )
|
||||
if ( Gia_ObjFaninC0(pObj) ^ fBuf )
|
||||
Vec_BitWriteEntry( vUsed, Gia_ObjFaninId0p(p, pObj), 1 );
|
||||
Vec_BitWriteEntry( vUsed, 0, 0 ); // clean zero
|
||||
return vUsed;
|
||||
}
|
||||
static int GiaHie_NameIsLegalInVerilog( char * pName )
|
||||
{
|
||||
// identifier ::= simple_identifier | escaped_identifier
|
||||
// simple_identifier ::= [a-zA-Z_][a-zA-Z0-9_$]
|
||||
// escaped_identifier ::= \ {Any_ASCII_character_except_white_space} white_space
|
||||
// white_space ::= space | tab | newline
|
||||
assert( pName != NULL && *pName != '\0' );
|
||||
if ( *pName == '\\' )
|
||||
return 1;
|
||||
if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && *pName != '_' )
|
||||
return 0;
|
||||
while ( *(++pName) )
|
||||
if ( (*pName < 'a' || *pName > 'z') && (*pName < 'A' || *pName > 'Z') && (*pName < '0' || *pName > '9') && *pName != '_' && *pName != '$' )
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
static char * GiaHie_ObjGetDumpName( Vec_Ptr_t * vNames, char c, int i, int d )
|
||||
{
|
||||
static char pBuffer[10000];
|
||||
if ( vNames )
|
||||
{
|
||||
char * pName = (char *)Vec_PtrEntry(vNames, i);
|
||||
if ( GiaHie_NameIsLegalInVerilog(pName) )
|
||||
sprintf( pBuffer, "%s", pName );
|
||||
else
|
||||
sprintf( pBuffer, "\\%s ", pName );
|
||||
}
|
||||
else
|
||||
sprintf( pBuffer, "%c%0*d%c", c, d, i, c );
|
||||
return pBuffer;
|
||||
}
|
||||
static void GiaHie_WriteNames( FILE * pFile, char c, int n, Vec_Ptr_t * vNames, int Start, int Skip, Vec_Bit_t * vObjs, int fReverse )
|
||||
{
|
||||
int Digits = Abc_Base10Log( n );
|
||||
int Length = Start, i, fFirst = 1;
|
||||
char * pName;
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
int k = fReverse ? n-1-i : i;
|
||||
if ( vObjs && !Vec_BitEntry(vObjs, k) )
|
||||
continue;
|
||||
pName = GiaHie_ObjGetDumpName( vNames, c, k, Digits );
|
||||
Length += strlen(pName) + 2;
|
||||
if ( Length > 60 )
|
||||
{
|
||||
fprintf( pFile, ",\n " );
|
||||
Length = Skip;
|
||||
fFirst = 1;
|
||||
}
|
||||
fprintf( pFile, "%s%s", fFirst ? "":", ", pName );
|
||||
fFirst = 0;
|
||||
}
|
||||
}
|
||||
static void GiaHie_PrintOneName( FILE * pFile, char * pName, int Size )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < Size; i++ )
|
||||
fprintf( pFile, "%c", pName[i] );
|
||||
}
|
||||
static int GiaHie_CountSymbs( char * pName )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; pName[i]; i++ )
|
||||
if ( pName[i] == '[' )
|
||||
break;
|
||||
return i;
|
||||
}
|
||||
static int GiaHie_ReadRangeNum( char * pName, int Size )
|
||||
{
|
||||
if ( pName[Size] == 0 )
|
||||
return -1;
|
||||
assert( pName[Size] == '[' );
|
||||
return atoi(pName+Size+1);
|
||||
}
|
||||
static Vec_Int_t * GiaHie_CountSymbsAll( Vec_Ptr_t * vNames )
|
||||
{
|
||||
char * pNameLast = (char *)Vec_PtrEntry(vNames, 0), * pName;
|
||||
int i, nSymbsLast = GiaHie_CountSymbs(pNameLast);
|
||||
Vec_Int_t * vArray = Vec_IntAlloc( Vec_PtrSize(vNames) * 2 );
|
||||
Vec_IntPush( vArray, 0 );
|
||||
Vec_IntPush( vArray, nSymbsLast );
|
||||
Vec_PtrForEachEntryStart( char *, vNames, pName, i, 1 )
|
||||
{
|
||||
int nSymbs = GiaHie_CountSymbs(pName);
|
||||
if ( nSymbs == nSymbsLast && !strncmp(pName, pNameLast, nSymbsLast) )
|
||||
continue;
|
||||
Vec_IntPush( vArray, i );
|
||||
Vec_IntPush( vArray, nSymbs );
|
||||
pNameLast = pName;
|
||||
nSymbsLast = nSymbs;
|
||||
}
|
||||
return vArray;
|
||||
}
|
||||
static void GiaHie_DumpIoList( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
if ( vNames == NULL )
|
||||
fprintf( pFile, "_%c_", fOuts ? 'o' : 'i' );
|
||||
else
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
if ( fReverse )
|
||||
{
|
||||
iName = Vec_IntEntry(vArray, Vec_IntSize(vArray)-2-i);
|
||||
Size = Vec_IntEntry(vArray, Vec_IntSize(vArray)-1-i);
|
||||
}
|
||||
if ( i ) fprintf( pFile, ", " );
|
||||
GiaHie_PrintOneName( pFile, (char *)Vec_PtrEntry(vNames, iName), Size );
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
static Vec_Bit_t * GiaHie_CollectMultiBits( Vec_Ptr_t * vNames, int n )
|
||||
{
|
||||
Vec_Bit_t * vBits = Vec_BitStart( n );
|
||||
if ( n == 0 )
|
||||
return vBits;
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( n > 1 )
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < n; i++ )
|
||||
Vec_BitWriteEntry( vBits, i, 1 );
|
||||
}
|
||||
return vBits;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
int nNames = Vec_PtrSize( vNames );
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : nNames;
|
||||
int k;
|
||||
if ( iNameNext - iName <= 1 )
|
||||
continue;
|
||||
for ( k = iName; k < iNameNext && k < n; k++ )
|
||||
Vec_BitWriteEntry( vBits, k, 1 );
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
return vBits;
|
||||
}
|
||||
static int GiaHie_DumpIoListMulti( Gia_Man_t * p, FILE * pFile, int fOuts, int fReverse )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
int nNames = vNames ? Vec_PtrSize(vNames) : (fOuts ? Gia_ManCoNum(p) : Gia_ManCiNum(p));
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( nNames > 1 )
|
||||
{
|
||||
fprintf( pFile, "_%c_", fOuts ? 'o' : 'i' );
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int nGroups = Vec_IntSize(vArray) / 2;
|
||||
int idx, fFirst = 1;
|
||||
for ( idx = 0; idx < nGroups; idx++ )
|
||||
{
|
||||
int g = fReverse ? (nGroups - 1 - idx) : idx;
|
||||
int iName = Vec_IntEntry(vArray, 2*g);
|
||||
int Size = Vec_IntEntry(vArray, 2*g + 1);
|
||||
int iNameNext = (g + 1 < nGroups) ? Vec_IntEntry(vArray, 2*(g + 1)) : nNames;
|
||||
if ( iNameNext - iName <= 1 )
|
||||
continue;
|
||||
if ( !fFirst )
|
||||
fprintf( pFile, ", " );
|
||||
GiaHie_PrintOneName( pFile, (char *)Vec_PtrEntry(vNames, iName), Size );
|
||||
fFirst = 0;
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
return !fFirst;
|
||||
}
|
||||
}
|
||||
static void GiaHie_DumpIoRanges( Gia_Man_t * p, FILE * pFile, int fOuts )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
if ( p->vNamesOut == NULL )
|
||||
fprintf( pFile, "%s [%d:0] _%c_;\n", fOuts ? "output" : "input", fOuts ? Gia_ManPoNum(p)-1 : Gia_ManPiNum(p)-1, fOuts ? 'o' : 'i' );
|
||||
else
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : Vec_PtrSize(vNames);
|
||||
char * pName = (char *)Vec_PtrEntry(vNames, iName);
|
||||
char * pNameLast = (char *)Vec_PtrEntry(vNames, iNameNext-1);
|
||||
assert( !strncmp(pName, pNameLast, Size) );
|
||||
int NumBeg = GiaHie_ReadRangeNum( pName, Size );
|
||||
int NumEnd = GiaHie_ReadRangeNum( pNameLast, Size );
|
||||
fprintf( pFile, " %s ", fOuts ? "output" : "input" );
|
||||
if ( NumBeg != -1 && iName < iNameNext-1 )
|
||||
fprintf( pFile, "[%d:%d] ", NumEnd, NumBeg );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
fprintf( pFile, ";\n" );
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
static void GiaHie_DumpModuleName( FILE * pFile, char * pName )
|
||||
{
|
||||
int i;
|
||||
if ( pName == NULL || pName[0] == '\0' )
|
||||
{
|
||||
fprintf( pFile, "top" );
|
||||
return;
|
||||
}
|
||||
if ( !isalpha(pName[0]) && pName[0] != '_' )
|
||||
fprintf( pFile, "m" );
|
||||
for ( i = 0; i < (int)strlen(pName); i++ )
|
||||
if ( isalpha(pName[i]) || isdigit(pName[i]) || pName[i] == '_' )
|
||||
fprintf( pFile, "%c", pName[i] );
|
||||
else
|
||||
fprintf( pFile, "_" );
|
||||
}
|
||||
static void GiaHie_DumpInterfaceGates( Gia_Man_t * p, char * pFileName )
|
||||
{
|
||||
Gia_Obj_t * pObj;
|
||||
Vec_Bit_t * vInvs, * vUsed;
|
||||
int nDigits = Abc_Base10Log( Gia_ManObjNum(p) );
|
||||
int nDigitsI = Abc_Base10Log( Gia_ManPiNum(p) );
|
||||
int nDigitsO = Abc_Base10Log( Gia_ManPoNum(p) );
|
||||
int i;
|
||||
|
||||
FILE * pFile = fopen( pFileName, "wb" );
|
||||
if ( pFile == NULL )
|
||||
{
|
||||
printf( "Cannot open output file \"%s\".\n", pFileName );
|
||||
return;
|
||||
}
|
||||
|
||||
vInvs = GiaHie_GenUsed( p, 0 );
|
||||
vUsed = GiaHie_GenUsed( p, 1 );
|
||||
|
||||
fprintf( pFile, "module " );
|
||||
GiaHie_DumpModuleName( pFile, p->pName );
|
||||
fprintf( pFile, " ( " );
|
||||
GiaHie_DumpIoList( p, pFile, 0, 0 );
|
||||
fprintf( pFile, ", " );
|
||||
GiaHie_DumpIoList( p, pFile, 1, 0 );
|
||||
fprintf( pFile, " );\n\n" );
|
||||
GiaHie_DumpIoRanges( p, pFile, 0 );
|
||||
GiaHie_DumpIoRanges( p, pFile, 1 );
|
||||
fprintf( pFile, "\n" );
|
||||
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteNames( pFile, 'x', Gia_ManPiNum(p), p->vNamesIn, 8, 4, NULL, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteNames( pFile, 'z', Gia_ManPoNum(p), p->vNamesOut, 9, 4, NULL, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
|
||||
{
|
||||
Vec_Bit_t * vMultiIn = GiaHie_CollectMultiBits( p->vNamesIn, Gia_ManCiNum(p) );
|
||||
Vec_Bit_t * vMultiOut = GiaHie_CollectMultiBits( p->vNamesOut, Gia_ManCoNum(p) );
|
||||
int fHasMultiIn = Vec_BitCount( vMultiIn );
|
||||
int fHasMultiOut = Vec_BitCount( vMultiOut );
|
||||
if ( fHasMultiIn )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_WriteNames( pFile, 'x', Gia_ManCiNum(p), p->vNamesIn, 8, 4, vMultiIn, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
GiaHie_DumpIoListMulti( p, pFile, 0, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
if ( fHasMultiOut )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_DumpIoListMulti( p, pFile, 1, 1 );
|
||||
fprintf( pFile, " } = { " );
|
||||
GiaHie_WriteNames( pFile, 'z', Gia_ManCoNum(p), p->vNamesOut, 9, 4, vMultiOut, 1 );
|
||||
fprintf( pFile, " };\n\n" );
|
||||
}
|
||||
Vec_BitFree( vMultiIn );
|
||||
Vec_BitFree( vMultiOut );
|
||||
}
|
||||
|
||||
if ( Vec_BitCount(vUsed) )
|
||||
{
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteNames( pFile, 'n', Gia_ManObjNum(p), NULL, 7, 4, vUsed, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
}
|
||||
|
||||
if ( Vec_BitCount(vInvs) )
|
||||
{
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteNames( pFile, 'i', Gia_ManObjNum(p), NULL, 7, 4, vInvs, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
}
|
||||
|
||||
// input inverters
|
||||
Gia_ManForEachCi( p, pObj, i )
|
||||
{
|
||||
if ( Vec_BitEntry(vUsed, Gia_ObjId(p, pObj)) )
|
||||
{
|
||||
fprintf( pFile, " buf ( %s,", GiaHie_ObjGetDumpName(NULL, 'n', Gia_ObjId(p, pObj), nDigits) );
|
||||
fprintf( pFile, " %s );\n", GiaHie_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) );
|
||||
}
|
||||
if ( Vec_BitEntry(vInvs, Gia_ObjId(p, pObj)) )
|
||||
{
|
||||
fprintf( pFile, " not ( %s,", GiaHie_ObjGetDumpName(NULL, 'i', Gia_ObjId(p, pObj), nDigits) );
|
||||
fprintf( pFile, " %s );\n", GiaHie_ObjGetDumpName(p->vNamesIn, 'x', i, nDigitsI) );
|
||||
}
|
||||
}
|
||||
|
||||
// internal nodes and their inverters
|
||||
fprintf( pFile, "\n" );
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
{
|
||||
fprintf( pFile, " and ( %s,", GiaHie_ObjGetDumpName(NULL, 'n', i, nDigits) );
|
||||
fprintf( pFile, " %s,", GiaHie_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0(pObj, i), nDigits) );
|
||||
fprintf( pFile, " %s );\n", GiaHie_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC1(pObj)? 'i':'n'), Gia_ObjFaninId1(pObj, i), nDigits) );
|
||||
if ( Vec_BitEntry(vInvs, i) )
|
||||
{
|
||||
fprintf( pFile, " not ( %s,", GiaHie_ObjGetDumpName(NULL, 'i', i, nDigits) );
|
||||
fprintf( pFile, " %s );\n", GiaHie_ObjGetDumpName(NULL, 'n', i, nDigits) );
|
||||
}
|
||||
}
|
||||
|
||||
// output drivers
|
||||
fprintf( pFile, "\n" );
|
||||
Gia_ManForEachCo( p, pObj, i )
|
||||
{
|
||||
fprintf( pFile, " buf ( %s, ", GiaHie_ObjGetDumpName(p->vNamesOut, 'z', i, nDigitsO) );
|
||||
if ( Gia_ObjIsConst0(Gia_ObjFanin0(pObj)) )
|
||||
fprintf( pFile, "1\'b%d );\n", Gia_ObjFaninC0(pObj) );
|
||||
else
|
||||
fprintf( pFile, "%s );\n", GiaHie_ObjGetDumpName(NULL, (char)(Gia_ObjFaninC0(pObj)? 'i':'n'), Gia_ObjFaninId0p(p, pObj), nDigits) );
|
||||
}
|
||||
|
||||
fprintf( pFile, "\nendmodule\n\n" );
|
||||
fclose( pFile );
|
||||
|
||||
Vec_BitFree( vInvs );
|
||||
Vec_BitFree( vUsed );
|
||||
}
|
||||
|
||||
static void GiaHie_PrintObjName( FILE * pFile, int ObjId, int nDigits )
|
||||
{
|
||||
fprintf( pFile, "n%0*d", nDigits, ObjId );
|
||||
}
|
||||
static void GiaHie_PrintObjLit( FILE * pFile, int ObjId, int fCompl, int nDigits )
|
||||
{
|
||||
fprintf( pFile, "%c", fCompl ? '~' : ' ' );
|
||||
GiaHie_PrintObjName( pFile, ObjId, nDigits );
|
||||
}
|
||||
static void GiaHie_WriteObjRange( FILE * pFile, Gia_Man_t * p, int iStart, int iStop, int nDigits, int Start, int Skip, int fReverse, int fCis )
|
||||
{
|
||||
int Length = Start, i, fFirst = 1;
|
||||
int n = iStop - iStart;
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
int Idx = fReverse ? (iStop - 1 - i) : (iStart + i);
|
||||
int ObjId = fCis ? Gia_ManCiIdToId(p, Idx) : Gia_ManCoIdToId(p, Idx);
|
||||
char pName[64];
|
||||
sprintf( pName, "n%0*d", nDigits, ObjId );
|
||||
Length += strlen(pName) + 2;
|
||||
if ( Length > 100 )
|
||||
{
|
||||
fprintf( pFile, ",\n " );
|
||||
Length = Skip;
|
||||
fFirst = 1;
|
||||
}
|
||||
fprintf( pFile, "%s%s", fFirst ? "":", ", pName );
|
||||
fFirst = 0;
|
||||
}
|
||||
}
|
||||
static void GiaHie_WritePiPoNames( FILE * pFile, const char * pPrefix, int nBits, int nDigits, int Start, int Skip, int fReverse )
|
||||
{
|
||||
int Length = Start, i, fFirst = 1;
|
||||
for ( i = 0; i < nBits; i++ )
|
||||
{
|
||||
int Idx = fReverse ? (nBits - 1 - i) : i;
|
||||
char pName[64];
|
||||
sprintf( pName, "%s%0*d", pPrefix, nDigits, Idx );
|
||||
Length += strlen(pName) + 2;
|
||||
if ( Length > 100 )
|
||||
{
|
||||
fprintf( pFile, ",\n " );
|
||||
Length = Skip;
|
||||
fFirst = 1;
|
||||
}
|
||||
fprintf( pFile, "%s%s", fFirst ? "":", ", pName );
|
||||
fFirst = 0;
|
||||
}
|
||||
}
|
||||
static int GiaHie_IsBitLevelNames( Vec_Ptr_t * vNames )
|
||||
{
|
||||
int nNames, nGroups, idx;
|
||||
Vec_Int_t * vArray;
|
||||
if ( vNames == NULL )
|
||||
return 1;
|
||||
nNames = Vec_PtrSize( vNames );
|
||||
if ( nNames == 0 )
|
||||
return 1;
|
||||
vArray = GiaHie_CountSymbsAll( vNames );
|
||||
nGroups = Vec_IntSize(vArray) / 2;
|
||||
for ( idx = 0; idx < nGroups; idx++ )
|
||||
{
|
||||
int iName = Vec_IntEntry(vArray, 2*idx);
|
||||
int iNameNext = (idx + 1 < nGroups) ? Vec_IntEntry(vArray, 2*(idx + 1)) : nNames;
|
||||
if ( iNameNext - iName > 1 )
|
||||
{
|
||||
Vec_IntFree( vArray );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
return 1;
|
||||
}
|
||||
static void GiaHie_DumpPortDeclsOne( Gia_Man_t * p, FILE * pFile, int fOuts, int * pfFirst )
|
||||
{
|
||||
Vec_Ptr_t * vNames = fOuts ? p->vNamesOut : p->vNamesIn;
|
||||
int nBits = fOuts ? Gia_ManPoNum(p) : Gia_ManPiNum(p);
|
||||
int fUsePiPo = (nBits > 2) && GiaHie_IsBitLevelNames( vNames );
|
||||
if ( nBits == 0 )
|
||||
return;
|
||||
if ( fUsePiPo )
|
||||
{
|
||||
int nDigits = Abc_Base10Log( nBits );
|
||||
if ( nDigits < 2 )
|
||||
nDigits = 2;
|
||||
if ( !(*pfFirst) )
|
||||
fprintf( pFile, ",\n" );
|
||||
fprintf( pFile, " %s ", fOuts ? "output" : "input" );
|
||||
GiaHie_WritePiPoNames( pFile, fOuts ? "po" : "pi", nBits, nDigits, 8, 4, 0 );
|
||||
*pfFirst = 0;
|
||||
return;
|
||||
}
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( !(*pfFirst) )
|
||||
fprintf( pFile, ",\n" );
|
||||
fprintf( pFile, " %s [%d:0] _%c_", fOuts ? "output" : "input", nBits-1, fOuts ? 'o' : 'i' );
|
||||
*pfFirst = 0;
|
||||
return;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : Vec_PtrSize(vNames);
|
||||
char * pName = (char *)Vec_PtrEntry(vNames, iName);
|
||||
char * pNameLast = (char *)Vec_PtrEntry(vNames, iNameNext-1);
|
||||
assert( !strncmp(pName, pNameLast, Size) );
|
||||
int NumBeg = GiaHie_ReadRangeNum( pName, Size );
|
||||
int NumEnd = GiaHie_ReadRangeNum( pNameLast, Size );
|
||||
if ( !(*pfFirst) )
|
||||
fprintf( pFile, ",\n" );
|
||||
fprintf( pFile, " %s ", fOuts ? "output" : "input" );
|
||||
if ( NumBeg != -1 && iName < iNameNext-1 )
|
||||
fprintf( pFile, "[%d:%d] ", NumEnd, NumBeg );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
*pfFirst = 0;
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
static void GiaHie_DumpPortDecls( Gia_Man_t * p, FILE * pFile )
|
||||
{
|
||||
int fFirst = 1;
|
||||
GiaHie_DumpPortDeclsOne( p, pFile, 0, &fFirst );
|
||||
GiaHie_DumpPortDeclsOne( p, pFile, 1, &fFirst );
|
||||
}
|
||||
static int GiaHie_ConstUsed( Gia_Man_t * p )
|
||||
{
|
||||
Gia_Obj_t * pObj; int i;
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
if ( Gia_ObjFaninId0(pObj, i) == 0 || Gia_ObjFaninId1(pObj, i) == 0 )
|
||||
return 1;
|
||||
Gia_ManForEachCo( p, pObj, i )
|
||||
if ( Gia_ObjIsConst0(Gia_ObjFanin0(pObj)) )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static void GiaHie_DumpInputAssigns( Gia_Man_t * p, FILE * pFile, int nDigits )
|
||||
{
|
||||
Vec_Ptr_t * vNames = p->vNamesIn;
|
||||
int nCis = Gia_ManCiNum(p);
|
||||
int fUsePiPo = (nCis > 2) && GiaHie_IsBitLevelNames( vNames );
|
||||
if ( nCis == 0 )
|
||||
return;
|
||||
if ( fUsePiPo )
|
||||
{
|
||||
int nDigitsPi = Abc_Base10Log( nCis );
|
||||
if ( nDigitsPi < 2 )
|
||||
nDigitsPi = 2;
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, nCis, nDigits, 11, 4, 1, 1 );
|
||||
fprintf( pFile, " } =\n { " );
|
||||
GiaHie_WritePiPoNames( pFile, "pi", nCis, nDigitsPi, 18, 4, 1 );
|
||||
fprintf( pFile, " };\n" );
|
||||
return;
|
||||
}
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( nCis == 1 )
|
||||
{
|
||||
fprintf( pFile, " assign " );
|
||||
GiaHie_PrintObjName( pFile, Gia_ManCiIdToId(p, 0), nDigits );
|
||||
fprintf( pFile, " = _i_;\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, nCis, nDigits, 11, 4, 1, 1 );
|
||||
fprintf( pFile, " } = { _i_ };\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : Vec_PtrSize(vNames);
|
||||
int nBits = iNameNext - iName;
|
||||
char * pName = (char *)Vec_PtrEntry(vNames, iName);
|
||||
if ( nBits > 1 )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_WriteObjRange( pFile, p, iName, iNameNext, nDigits, 11, 4, 1, 1 );
|
||||
fprintf( pFile, " } =\n { " );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
fprintf( pFile, " };\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( pFile, " assign " );
|
||||
GiaHie_PrintObjName( pFile, Gia_ManCiIdToId(p, iName), nDigits );
|
||||
fprintf( pFile, " = " );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
fprintf( pFile, ";\n" );
|
||||
}
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
static void GiaHie_DumpOutputAssigns( Gia_Man_t * p, FILE * pFile, int nDigits )
|
||||
{
|
||||
Vec_Ptr_t * vNames = p->vNamesOut;
|
||||
int nCos = Gia_ManCoNum(p);
|
||||
int fUsePiPo = (nCos > 2) && GiaHie_IsBitLevelNames( vNames );
|
||||
if ( nCos == 0 )
|
||||
return;
|
||||
if ( fUsePiPo )
|
||||
{
|
||||
int nDigitsPo = Abc_Base10Log( nCos );
|
||||
if ( nDigitsPo < 2 )
|
||||
nDigitsPo = 2;
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_WritePiPoNames( pFile, "po", nCos, nDigitsPo, 11, 4, 1 );
|
||||
fprintf( pFile, " } =\n { " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, nCos, nDigits, 18, 4, 1, 0 );
|
||||
fprintf( pFile, " };\n" );
|
||||
return;
|
||||
}
|
||||
if ( vNames == NULL )
|
||||
{
|
||||
if ( nCos == 1 )
|
||||
{
|
||||
fprintf( pFile, " assign _o_ = " );
|
||||
GiaHie_PrintObjName( pFile, Gia_ManCoIdToId(p, 0), nDigits );
|
||||
fprintf( pFile, ";\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( pFile, " assign { _o_ } = { " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, nCos, nDigits, 18, 4, 1, 0 );
|
||||
fprintf( pFile, " };\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
{
|
||||
Vec_Int_t * vArray = GiaHie_CountSymbsAll( vNames );
|
||||
int iName, Size, i;
|
||||
Vec_IntForEachEntryDouble( vArray, iName, Size, i )
|
||||
{
|
||||
int iNameNext = Vec_IntSize(vArray) > i+2 ? Vec_IntEntry(vArray, i+2) : Vec_PtrSize(vNames);
|
||||
int nBits = iNameNext - iName;
|
||||
char * pName = (char *)Vec_PtrEntry(vNames, iName);
|
||||
if ( nBits > 1 )
|
||||
{
|
||||
fprintf( pFile, " assign { " );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
fprintf( pFile, " } =\n { " );
|
||||
GiaHie_WriteObjRange( pFile, p, iName, iNameNext, nDigits, 18, 4, 1, 0 );
|
||||
fprintf( pFile, " };\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf( pFile, " assign " );
|
||||
GiaHie_PrintOneName( pFile, pName, Size );
|
||||
fprintf( pFile, " = " );
|
||||
GiaHie_PrintObjName( pFile, Gia_ManCoIdToId(p, iName), nDigits );
|
||||
fprintf( pFile, ";\n" );
|
||||
}
|
||||
}
|
||||
Vec_IntFree( vArray );
|
||||
}
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
static void GiaHie_DumpInterfaceAssigns( Gia_Man_t * p, char * pFileName )
|
||||
{
|
||||
Gia_Obj_t * pObj;
|
||||
int nDigits = Abc_Base10Log( Gia_ManObjNum(p) );
|
||||
int nPerLine = 4;
|
||||
int nOnLine = 0;
|
||||
int i;
|
||||
FILE * pFile = fopen( pFileName, "wb" );
|
||||
if ( pFile == NULL )
|
||||
{
|
||||
printf( "Cannot open output file \"%s\".\n", pFileName );
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf( pFile, "module " );
|
||||
GiaHie_DumpModuleName( pFile, p->pName );
|
||||
fprintf( pFile, " (\n" );
|
||||
GiaHie_DumpPortDecls( p, pFile );
|
||||
fprintf( pFile, "\n);\n\n" );
|
||||
|
||||
if ( Gia_ManCiNum(p) )
|
||||
{
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, Gia_ManCiNum(p), nDigits, 7, 4, 0, 1 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
GiaHie_DumpInputAssigns( p, pFile, nDigits );
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
|
||||
if ( Gia_ManCoNum(p) )
|
||||
{
|
||||
fprintf( pFile, " wire " );
|
||||
GiaHie_WriteObjRange( pFile, p, 0, Gia_ManCoNum(p), nDigits, 7, 4, 0, 0 );
|
||||
fprintf( pFile, ";\n\n" );
|
||||
GiaHie_DumpOutputAssigns( p, pFile, nDigits );
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
|
||||
if ( GiaHie_ConstUsed(p) )
|
||||
fprintf( pFile, " wire n%0*d = 1'b0;\n\n", nDigits, 0 );
|
||||
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
{
|
||||
if ( nOnLine == 0 )
|
||||
fprintf( pFile, " " );
|
||||
fprintf( pFile, "wire n%0*d = ", nDigits, i );
|
||||
GiaHie_PrintObjLit( pFile, Gia_ObjFaninId0(pObj, i), Gia_ObjFaninC0(pObj), nDigits );
|
||||
fprintf( pFile, " & " );
|
||||
GiaHie_PrintObjLit( pFile, Gia_ObjFaninId1(pObj, i), Gia_ObjFaninC1(pObj), nDigits );
|
||||
fprintf( pFile, "; " );
|
||||
nOnLine++;
|
||||
if ( nOnLine == nPerLine )
|
||||
{
|
||||
fprintf( pFile, "\n" );
|
||||
nOnLine = 0;
|
||||
}
|
||||
else
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
if ( nOnLine != 0 )
|
||||
fprintf( pFile, "\n" );
|
||||
if ( Gia_ManAndNum(p) )
|
||||
fprintf( pFile, "\n" );
|
||||
|
||||
Gia_ManForEachCo( p, pObj, i )
|
||||
{
|
||||
fprintf( pFile, " assign n%0*d = ", nDigits, Gia_ManCoIdToId(p, i) );
|
||||
GiaHie_PrintObjLit( pFile, Gia_ObjFaninId0p(p, pObj), Gia_ObjFaninC0(pObj), nDigits );
|
||||
fprintf( pFile, ";\n" );
|
||||
}
|
||||
|
||||
fprintf( pFile, "\nendmodule\n\n" );
|
||||
fclose( pFile );
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose )
|
||||
{
|
||||
(void)fVerbose;
|
||||
if ( pFileName == NULL || pGia == NULL )
|
||||
return;
|
||||
if ( fUseGates )
|
||||
GiaHie_DumpInterfaceGates( pGia, pFileName );
|
||||
else
|
||||
GiaHie_DumpInterfaceAssigns( pGia, pFileName );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ static int Abc_CommandSimSec ( Abc_Frame_t * pAbc, int argc, cha
|
|||
static int Abc_CommandMatch ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
//static int Abc_CommandHaig ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandQbf ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAigSim ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
||||
static int Abc_CommandFraig ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandFraigTrust ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
|
@ -467,6 +468,9 @@ static int Abc_CommandAbc9Times ( Abc_Frame_t * pAbc, int argc, cha
|
|||
static int Abc_CommandAbc9Frames ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Retime ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Enable ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Resyn3 ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Resyn3rs ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Compress3rs ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Dc2 ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Dsd ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbc9Bidec ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
|
@ -1107,6 +1111,7 @@ void Abc_Init( Abc_Frame_t * pAbc )
|
|||
Cmd_CommandAdd( pAbc, "New AIG", "csweep", Abc_CommandCSweep, 1 );
|
||||
// Cmd_CommandAdd( pAbc, "New AIG", "haig", Abc_CommandHaig, 1 );
|
||||
Cmd_CommandAdd( pAbc, "New AIG", "qbf", Abc_CommandQbf, 0 );
|
||||
Cmd_CommandAdd( pAbc, "New AIG", "aigsim", Abc_CommandAigSim, 0 );
|
||||
|
||||
Cmd_CommandAdd( pAbc, "Fraiging", "fraig", Abc_CommandFraig, 1 );
|
||||
Cmd_CommandAdd( pAbc, "Fraiging", "fraig_trust", Abc_CommandFraigTrust, 1 );
|
||||
|
|
@ -1297,6 +1302,9 @@ void Abc_Init( Abc_Frame_t * pAbc )
|
|||
Cmd_CommandAdd( pAbc, "ABC9", "&frames", Abc_CommandAbc9Frames, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&retime", Abc_CommandAbc9Retime, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&enable", Abc_CommandAbc9Enable, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&resyn3", Abc_CommandAbc9Resyn3, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&resyn3rs", Abc_CommandAbc9Resyn3rs, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&compress3rs", Abc_CommandAbc9Compress3rs, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&dc2", Abc_CommandAbc9Dc2, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&dsd", Abc_CommandAbc9Dsd, 0 );
|
||||
Cmd_CommandAdd( pAbc, "ABC9", "&bidec", Abc_CommandAbc9Bidec, 0 );
|
||||
|
|
@ -10956,7 +10964,7 @@ int Abc_CommandLutExact( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Abc_Print( -1, "Function with %d variales cannot be implemented with %d %d-input LUTs.\n", pPars->nVars, pPars->nNodes, pPars->nLutSize );
|
||||
return 1;
|
||||
}
|
||||
if ( pPars->fKissat )
|
||||
if ( pPars->fKissat || pPars->fCadical )
|
||||
{
|
||||
if ( pPars->nVars > 14 )
|
||||
{
|
||||
|
|
@ -19269,6 +19277,68 @@ usage:
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int Abc_CommandAigSim( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern int SimulateAigTop( char *fname1, char *fname2, char * mask, int verbose );
|
||||
char * pMask = NULL;
|
||||
char ** pArgvNew = NULL;
|
||||
int nArgcNew = 0;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "Mvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 'M':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-M\" should be followed by a string.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pMask = argv[globalUtilOptind];
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
pArgvNew = argv + globalUtilOptind;
|
||||
nArgcNew = argc - globalUtilOptind;
|
||||
if ( nArgcNew != 2 ) {
|
||||
Abc_Print( -1, "Expecting two files names on the command line.\n" );
|
||||
return 1;
|
||||
}
|
||||
SimulateAigTop( pArgvNew[0], pArgvNew[1], pMask, fVerbose );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: aigsim -M <str> [-vh] <file1> <file2>\n" );
|
||||
Abc_Print( -2, "\t combinational AIG simulation\n" );
|
||||
Abc_Print( -2, "\t-M <str> : mask to select inputs for simulation [default = unused]\n" );
|
||||
Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
Abc_Print( -2, "\t<file1> : the first file to simulate\n");
|
||||
Abc_Print( -2, "\t<file2> : the second file to simulate\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
@ -35016,14 +35086,16 @@ usage:
|
|||
***********************************************************************/
|
||||
int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern void Gia_WriteVerilog( char * pFileName, Gia_Man_t * pGia, int fUseGates, int fVerbose );
|
||||
char * pFileSpec = NULL;
|
||||
Abc_Ntk_t * pNtkSpec = NULL;
|
||||
char * pFileName;
|
||||
char ** pArgvNew;
|
||||
int c, nArgcNew;
|
||||
int fUseGates = 0;
|
||||
int fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "Svh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "Sgvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -35036,6 +35108,9 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
pFileSpec = argv[globalUtilOptind];
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'g':
|
||||
fUseGates ^= 1;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
|
|
@ -35053,31 +35128,39 @@ int Abc_CommandAbc9WriteVer( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
return 1;
|
||||
}
|
||||
pFileName = argv[globalUtilOptind];
|
||||
if ( pAbc->pNtkCur == NULL )
|
||||
{
|
||||
Abc_Print( -1, "There is no mapped file to write.\n" );
|
||||
return 1;
|
||||
}
|
||||
if ( pFileSpec == NULL )
|
||||
{
|
||||
Abc_Print( -1, "The specification file is not given.\n" );
|
||||
return 1;
|
||||
if ( pAbc->pGia == NULL )
|
||||
{
|
||||
Abc_Print( -1, "There is no AIG to write.\n" );
|
||||
return 1;
|
||||
}
|
||||
Gia_WriteVerilog( pFileName, pAbc->pGia, fUseGates, fVerbose );
|
||||
}
|
||||
pNtkSpec = Io_ReadNetlist( pFileSpec, Io_ReadFileType(pFileSpec), 0 );
|
||||
if ( pNtkSpec == NULL )
|
||||
else
|
||||
{
|
||||
Abc_Print( -1, "Reading hierarchical Verilog for the specification has failed.\n" );
|
||||
return 1;
|
||||
if ( pAbc->pNtkCur == NULL )
|
||||
{
|
||||
Abc_Print( -1, "There is no mapped file to write.\n" );
|
||||
return 1;
|
||||
}
|
||||
pNtkSpec = Io_ReadNetlist( pFileSpec, Io_ReadFileType(pFileSpec), 0 );
|
||||
if ( pNtkSpec == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Reading hierarchical Verilog for the specification has failed.\n" );
|
||||
return 1;
|
||||
}
|
||||
Abc_NtkInsertHierarchyGia( pNtkSpec, pAbc->pNtkCur, fVerbose );
|
||||
Io_WriteVerilog( pNtkSpec, pFileName, 0, 0 );
|
||||
Abc_NtkDelete( pNtkSpec );
|
||||
}
|
||||
Abc_NtkInsertHierarchyGia( pNtkSpec, pAbc->pNtkCur, fVerbose );
|
||||
Io_WriteVerilog( pNtkSpec, pFileName, 0, 0 );
|
||||
Abc_NtkDelete( pNtkSpec );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &write_ver [-S <file>] [-vh] <file>\n" );
|
||||
Abc_Print( -2, "\t writes hierarchical Verilog after mapping\n" );
|
||||
Abc_Print( -2, "\t-S file : file name for the original hierarchical design (required)\n" );
|
||||
Abc_Print( -2, "usage: &write_ver [-S <file>] [-gvh] <file>\n" );
|
||||
Abc_Print( -2, "\t writes hierarchical Verilog\n" );
|
||||
Abc_Print( -2, "\t-S file : file name for the original design (required when hierarchy is present)\n" );
|
||||
Abc_Print( -2, "\t-g : toggle output gates vs assign-statements [default = %s]\n", fUseGates? "gates": "assigns" );
|
||||
Abc_Print( -2, "\t-v : toggle verbose output [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
Abc_Print( -2, "\t<file> : the file name\n");
|
||||
|
|
@ -36637,10 +36720,11 @@ usage:
|
|||
int Abc_CommandAbc9Cofs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Gia_Man_t * Gia_ManDupCofs( Gia_Man_t * p, Vec_Int_t * vVarNums );
|
||||
extern Gia_Man_t * Gia_ManDupUnCofs( Gia_Man_t * p, Vec_Int_t * vVarNums );
|
||||
Gia_Man_t * pTemp; Vec_Int_t * vVars = NULL;
|
||||
int c, iVar = 0, nVars = 0, fVerbose = 0;
|
||||
int c, iVar = 0, nVars = 0, fLastVars = 0, fVerbose = 0, fUndo = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "VNvh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "VNluvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -36666,6 +36750,12 @@ int Abc_CommandAbc9Cofs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
if ( nVars < 0 )
|
||||
goto usage;
|
||||
break;
|
||||
case 'l':
|
||||
fLastVars ^= 1;
|
||||
break;
|
||||
case 'u':
|
||||
fUndo ^= 1;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
|
|
@ -36686,8 +36776,14 @@ int Abc_CommandAbc9Cofs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Vec_IntPush( vVars, iVar );
|
||||
}
|
||||
else if ( nVars ) {
|
||||
Abc_Print( 0, "Cofactoring the first %d inputs.\n", nVars );
|
||||
vVars = Vec_IntStartNatural( nVars );
|
||||
Abc_Print( 0, "Cofactoring the %s %d inputs.\n", fLastVars ? "last":"first", nVars );
|
||||
if ( fLastVars) {
|
||||
vVars = Vec_IntAlloc(nVars);
|
||||
for ( int v = 0; v < nVars; v++ )
|
||||
Vec_IntPush( vVars, Gia_ManCiNum(pAbc->pGia)-nVars+v );
|
||||
}
|
||||
else
|
||||
vVars = Vec_IntStartNatural( nVars );
|
||||
}
|
||||
else if ( globalUtilOptind < argc ) {
|
||||
vVars = Vec_IntAlloc( argc );
|
||||
|
|
@ -36698,16 +36794,18 @@ int Abc_CommandAbc9Cofs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Abc_Print( -1, "One of the parameters, -V <num> or -L <num>, should be set on the command line.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pTemp = Gia_ManDupCofs( pAbc->pGia, vVars );
|
||||
pTemp = fUndo ? Gia_ManDupUnCofs( pAbc->pGia, vVars ) : Gia_ManDupCofs( pAbc->pGia, vVars );
|
||||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
Vec_IntFree( vVars );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &cofs [-VN num] [-vh]\n" );
|
||||
Abc_Print( -2, "\t derives cofactors w.r.t the set of variables\n" );
|
||||
Abc_Print( -2, "usage: &cofs [-VN num] [-luvh]\n" );
|
||||
Abc_Print( -2, "\t derives cofactors or reconstructs them w.r.t the set of variables\n" );
|
||||
Abc_Print( -2, "\t-V num : the zero-based ID of one variable to cofactor [default = %d]\n", iVar );
|
||||
Abc_Print( -2, "\t-N num : cofactoring the given number of first input variables [default = %d]\n", nVars );
|
||||
Abc_Print( -2, "\t-l : toggle cofactoring last variables instead [default = %s]\n", fLastVars? "yes": "no" );
|
||||
Abc_Print( -2, "\t-u : undo cofactoring (recombine cofactors using muxes) [default = %s]\n", fUndo? "yes": "no" );
|
||||
Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
return 1;
|
||||
|
|
@ -39119,6 +39217,147 @@ usage:
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int Abc_CommandAbc9Resyn3( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Gia_Man_t * Gia_ManResyn3( Gia_Man_t * pGia, int fVerbose );
|
||||
Gia_Man_t * pTemp;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( pAbc->pGia == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9Resyn3(): There is no AIG.\n" );
|
||||
return 1;
|
||||
}
|
||||
pTemp = Gia_ManResyn3( pAbc->pGia, fVerbose );
|
||||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &resyn3 [-vh]\n" );
|
||||
Abc_Print( -2, "\t performs rewriting of the AIG while preserving logic level\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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int Abc_CommandAbc9Resyn3rs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Gia_Man_t * Gia_ManCompress3rs( Gia_Man_t * pGia, int fUpdateLevel, int fVerbose );
|
||||
Gia_Man_t * pTemp;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( pAbc->pGia == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9Resyn3rs(): There is no AIG.\n" );
|
||||
return 1;
|
||||
}
|
||||
pTemp = Gia_ManCompress3rs( pAbc->pGia, 1, fVerbose );
|
||||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &resyn3rs [-vh]\n" );
|
||||
Abc_Print( -2, "\t performs rewriting of the AIG while preserving logic level\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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
int Abc_CommandAbc9Compress3rs( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Gia_Man_t * Gia_ManCompress3rs( Gia_Man_t * pGia, int fUpdateLevel, int fVerbose );
|
||||
Gia_Man_t * pTemp;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "vh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( pAbc->pGia == NULL )
|
||||
{
|
||||
Abc_Print( -1, "Abc_CommandAbc9Compress3rs(): There is no AIG.\n" );
|
||||
return 1;
|
||||
}
|
||||
pTemp = Gia_ManCompress3rs( pAbc->pGia, 0, fVerbose );
|
||||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &compress3rs [-vh]\n" );
|
||||
Abc_Print( -2, "\t performs rewriting of the AIG without preserving logic level\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");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
@ -42283,6 +42522,7 @@ usage:
|
|||
***********************************************************************/
|
||||
int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern void Cec_ManPrintCexSummary( Gia_Man_t * p, Abc_Cex_t * pCex, Cec_ParCec_t * pPars );
|
||||
Cec_ParCec_t ParsCec, * pPars = &ParsCec;
|
||||
FILE * pFile;
|
||||
Gia_Man_t * pGias[2] = {NULL, NULL}, * pMiter;
|
||||
|
|
@ -42509,6 +42749,9 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
pPars->pNameSpec = pGias[0] ? (pGias[0]->pSpec ? pGias[0]->pSpec : pGias[0]->pName) : NULL;
|
||||
pPars->pNameImpl = pGias[1] ? (pGias[1]->pSpec ? pGias[1]->pSpec : pGias[1]->pName) : NULL;
|
||||
pPars->vNamesIn = pGias[0] ? pGias[0]->vNamesIn : NULL;
|
||||
// compute the miter
|
||||
if ( Gia_ManCiNum(pGias[0]) < 6 )
|
||||
{
|
||||
|
|
@ -42549,12 +42792,32 @@ int Abc_CommandAbc9Cec( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
extern int Gia_ManCheckSimEquiv( Gia_Man_t * p, int fVerbose );
|
||||
int Status = Gia_ManCheckSimEquiv( pMiter, pPars->fVerbose );
|
||||
if ( Status == 1 )
|
||||
{
|
||||
Abc_Print( 1, "Networks are equivalent. " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
}
|
||||
else if ( Status == 0 )
|
||||
{
|
||||
Abc_Print( 1, "Networks are NOT equivalent. " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
{
|
||||
Cec_ParCec_t ParsTemp = *pPars;
|
||||
ParsTemp.fSilent = 1;
|
||||
Cec_ManVerify( pMiter, &ParsTemp );
|
||||
if ( pMiter->pCexComb )
|
||||
{
|
||||
Cec_ManPrintCexSummary( pMiter, pMiter->pCexComb, pPars );
|
||||
pGias[0]->pCexComb = pMiter->pCexComb;
|
||||
pMiter->pCexComb = NULL;
|
||||
Abc_FrameReplaceCex( pAbc, &pGias[0]->pCexComb );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Abc_Print( 1, "Networks are UNDECIDED. " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
}
|
||||
}
|
||||
else if ( fUseNewX )
|
||||
{
|
||||
|
|
@ -54532,9 +54795,10 @@ usage:
|
|||
int Abc_CommandAbc9DeepSyn( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Gia_Man_t * Gia_ManDeepSyn( Gia_Man_t * pGia, int nIters, int nNoImpr, int TimeOut, int nAnds, int Seed, int fUseTwo, int fChoices, int fVerbose );
|
||||
Gia_Man_t * pTemp; int c, nIters = 1, nNoImpr = ABC_INFINITY, TimeOut = 0, nAnds = 0, Seed = 0, fUseTwo = 0, fChoices = 0, fVerbose = 0;
|
||||
extern Gia_Man_t * Gia_ManDeepSyn2( Gia_Man_t * pGia, int nIters, int nNoImpr, int TimeOut, int nAnds, int Seed, int fUseTwo, int fChoices, int fVerbose );
|
||||
Gia_Man_t * pTemp; int c, nIters = 1, nNoImpr = ABC_INFINITY, TimeOut = 0, nAnds = 0, Seed = 0, fUseTwo = 0, fChoices = 0, fOpt = 0, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "IJTAStcvh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "IJTAStcovh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -54599,6 +54863,9 @@ int Abc_CommandAbc9DeepSyn( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
case 'c':
|
||||
fChoices ^= 1;
|
||||
break;
|
||||
case 'o':
|
||||
fOpt ^= 1;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
|
|
@ -54613,12 +54880,15 @@ int Abc_CommandAbc9DeepSyn( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
Abc_Print( -1, "Abc_CommandAbc9DeepSyn(): There is no AIG.\n" );
|
||||
return 0;
|
||||
}
|
||||
pTemp = Gia_ManDeepSyn( pAbc->pGia, nIters, nNoImpr, TimeOut, nAnds, Seed, fUseTwo, fChoices, fVerbose );
|
||||
if ( fOpt )
|
||||
pTemp = Gia_ManDeepSyn2( pAbc->pGia, nIters, nNoImpr, TimeOut, nAnds, Seed, fUseTwo, fChoices, fVerbose );
|
||||
else
|
||||
pTemp = Gia_ManDeepSyn( pAbc->pGia, nIters, nNoImpr, TimeOut, nAnds, Seed, fUseTwo, fChoices, fVerbose );
|
||||
Abc_FrameUpdateGia( pAbc, pTemp );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
Abc_Print( -2, "usage: &deepsyn [-IJTAS <num>] [-tcvh]\n" );
|
||||
Abc_Print( -2, "usage: &deepsyn [-IJTAS <num>] [-tcovh]\n" );
|
||||
Abc_Print( -2, "\t performs synthesis\n" );
|
||||
Abc_Print( -2, "\t-I <num> : the number of iterations [default = %d]\n", nIters );
|
||||
Abc_Print( -2, "\t-J <num> : the number of steps without improvements [default = %d]\n", nNoImpr );
|
||||
|
|
@ -54627,6 +54897,7 @@ usage:
|
|||
Abc_Print( -2, "\t-S <num> : user-specified random seed (0 <= num <= 100) [default = %d]\n", Seed );
|
||||
Abc_Print( -2, "\t-t : toggle using two-input LUTs [default = %s]\n", fUseTwo? "yes": "no" );
|
||||
Abc_Print( -2, "\t-c : toggle computing structural choices [default = %s]\n", fChoices? "yes": "no" );
|
||||
Abc_Print( -2, "\t-o : toggle using optimization [default = %s]\n", fOpt? "yes": "no" );
|
||||
Abc_Print( -2, "\t-v : toggle printing optimization summary [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -662,6 +662,45 @@ Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pMan )
|
|||
}
|
||||
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
Aig_Man_t * Dar_ManResub( Aig_Man_t * pMan, int nCutsMax, int nNodesMax, int fUpdateLevel, int fUseZeros, int fVerbose )
|
||||
{
|
||||
extern int Abc_NtkResubstitute( Abc_Ntk_t * pNtk, int nCutMax, int nStepsMax, int nMinSaved, int nLevelsOdc, int fUpdateLevel, int fVerbose, int fVeryVerbose, int Log2Probs, int Log2Divs );
|
||||
Abc_Ntk_t * pNtk = Abc_NtkFromAigPhase( pMan );
|
||||
Aig_Man_t * pRes = NULL;
|
||||
char * pName = NULL, * pSpec = NULL;
|
||||
int nMinSaved = fUseZeros ? 0 : 1;
|
||||
if ( pMan->pName )
|
||||
pName = Abc_UtilStrsav( pMan->pName );
|
||||
if ( pMan->pSpec )
|
||||
pSpec = Abc_UtilStrsav( pMan->pSpec );
|
||||
if ( pName )
|
||||
{
|
||||
ABC_FREE( pNtk->pName );
|
||||
pNtk->pName = pName;
|
||||
}
|
||||
if ( pSpec )
|
||||
{
|
||||
ABC_FREE( pNtk->pSpec );
|
||||
pNtk->pSpec = pSpec;
|
||||
}
|
||||
if ( !Abc_NtkResubstitute( pNtk, nCutsMax, nNodesMax, nMinSaved, 0, fUpdateLevel, fVerbose, 0, 0, 0 ) )
|
||||
Abc_Print( 0, "Dar_ManResub(): Resubstitution has failed.\n" );
|
||||
pRes = Abc_NtkToDar( pNtk, 0, 1 );
|
||||
Abc_NtkDelete( pNtk );
|
||||
return pRes;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
@ -5181,4 +5220,3 @@ Gia_Man_t * Abc_NtkDarTestFiles()
|
|||
|
||||
#include "abcDarUnfold2.c"
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -731,6 +731,147 @@ int * Abc_NtkVerifySimulatePattern( Abc_Ntk_t * pNtk, int * pModel )
|
|||
return pValues;
|
||||
}
|
||||
|
||||
typedef struct Abc_NtkCexWord_t_
|
||||
{
|
||||
char * pBase;
|
||||
Vec_Int_t * vBits;
|
||||
} Abc_NtkCexWord_t;
|
||||
|
||||
static Abc_NtkCexWord_t * Abc_NtkVerifyFindWord( Vec_Ptr_t * vWords, const char * pBase )
|
||||
{
|
||||
Abc_NtkCexWord_t * pWord;
|
||||
int i;
|
||||
Vec_PtrForEachEntry( Abc_NtkCexWord_t *, vWords, pWord, i )
|
||||
if ( !strcmp( pWord->pBase, pBase ) )
|
||||
return pWord;
|
||||
pWord = ABC_ALLOC( Abc_NtkCexWord_t, 1 );
|
||||
pWord->pBase = ABC_ALLOC( char, strlen(pBase) + 1 );
|
||||
strcpy( pWord->pBase, pBase );
|
||||
pWord->vBits = Vec_IntAlloc( 0 );
|
||||
Vec_PtrPush( vWords, pWord );
|
||||
return pWord;
|
||||
}
|
||||
|
||||
static void Abc_NtkVerifyFreeWords( Vec_Ptr_t * vWords )
|
||||
{
|
||||
Abc_NtkCexWord_t * pWord;
|
||||
int i;
|
||||
Vec_PtrForEachEntry( Abc_NtkCexWord_t *, vWords, pWord, i )
|
||||
{
|
||||
ABC_FREE( pWord->pBase );
|
||||
Vec_IntFree( pWord->vBits );
|
||||
ABC_FREE( pWord );
|
||||
}
|
||||
Vec_PtrFree( vWords );
|
||||
}
|
||||
|
||||
static int Abc_NtkVerifyParseBitName( const char * pName, char ** ppBase, int * pIndex )
|
||||
{
|
||||
const char * pOpen;
|
||||
const char * pClose;
|
||||
char * pEnd;
|
||||
long Index;
|
||||
*ppBase = NULL;
|
||||
pClose = strrchr( pName, ']' );
|
||||
pOpen = pClose ? strrchr( pName, '[' ) : NULL;
|
||||
if ( pOpen == NULL || pClose == NULL || pClose < pOpen || pClose[1] != 0 )
|
||||
return 0;
|
||||
Index = strtol( pOpen + 1, &pEnd, 10 );
|
||||
if ( pEnd != pClose || Index < 0 )
|
||||
return 0;
|
||||
*pIndex = (int)Index;
|
||||
*ppBase = ABC_ALLOC( char, pOpen - pName + 1 );
|
||||
strncpy( *ppBase, pName, pOpen - pName );
|
||||
(*ppBase)[pOpen - pName] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Abc_NtkVerifyCollectWords( Vec_Ptr_t * vWords, const char * const * ppNames, const int * pValues, int nEntries )
|
||||
{
|
||||
int i, fHasVector = 0;
|
||||
for ( i = 0; i < nEntries; i++ )
|
||||
{
|
||||
char * pBase = NULL;
|
||||
int Index = 0;
|
||||
int fVector = Abc_NtkVerifyParseBitName( ppNames[i], &pBase, &Index );
|
||||
Abc_NtkCexWord_t * pWord = Abc_NtkVerifyFindWord( vWords, fVector ? pBase : ppNames[i] );
|
||||
Vec_IntSetEntry( pWord->vBits, fVector ? Index : 0, pValues[i] );
|
||||
fHasVector |= fVector;
|
||||
if ( pBase )
|
||||
ABC_FREE( pBase );
|
||||
}
|
||||
return fHasVector;
|
||||
}
|
||||
|
||||
static void Abc_NtkVerifyPrintWords( Vec_Ptr_t * vWords )
|
||||
{
|
||||
Abc_NtkCexWord_t * pWord;
|
||||
int i, d, b, nBits, nHex, Digit;
|
||||
Vec_PtrForEachEntry( Abc_NtkCexWord_t *, vWords, pWord, i )
|
||||
{
|
||||
nBits = Vec_IntSize( pWord->vBits );
|
||||
nHex = (nBits + 3) / 4;
|
||||
nHex = nHex ? nHex : 1;
|
||||
{
|
||||
char * pHex = ABC_ALLOC( char, nHex + 1 );
|
||||
for ( d = 0; d < nHex; d++ )
|
||||
{
|
||||
Digit = 0;
|
||||
for ( b = 0; b < 4; b++ )
|
||||
{
|
||||
int iBit = d * 4 + b;
|
||||
if ( iBit < nBits && Vec_IntEntry( pWord->vBits, iBit ) )
|
||||
Digit |= 1 << b;
|
||||
}
|
||||
pHex[nHex - d - 1] = "0123456789ABCDEF"[Digit];
|
||||
}
|
||||
pHex[nHex] = 0;
|
||||
printf( "%s = %d'h%s", pWord->pBase, nBits, pHex );
|
||||
ABC_FREE( pHex );
|
||||
}
|
||||
if ( i + 1 < Vec_PtrSize(vWords) )
|
||||
printf( ", " );
|
||||
}
|
||||
}
|
||||
|
||||
void Abc_NtkVerifyPrintCex( const int * pModel, const int * pValues1, const int * pValues2,
|
||||
const char * const * ppInputNames, int nInputs, const char * const * ppOutputNames, int nOutputs,
|
||||
const char * pNtkName1, const char * pNtkName2 )
|
||||
{
|
||||
Vec_Ptr_t * vInputs = Vec_PtrAlloc( 0 );
|
||||
Vec_Ptr_t * vOutputs1 = Vec_PtrAlloc( 0 );
|
||||
Vec_Ptr_t * vOutputs2 = Vec_PtrAlloc( 0 );
|
||||
Abc_NtkVerifyCollectWords( vInputs, ppInputNames, pModel, nInputs );
|
||||
Abc_NtkVerifyCollectWords( vOutputs1, ppOutputNames, pValues1, nOutputs );
|
||||
if ( pValues2 )
|
||||
Abc_NtkVerifyCollectWords( vOutputs2, ppOutputNames, pValues2, nOutputs );
|
||||
if ( Vec_PtrSize(vInputs) || Vec_PtrSize(vOutputs1) || Vec_PtrSize(vOutputs2) )
|
||||
{
|
||||
printf( "INPUT: " );
|
||||
Abc_NtkVerifyPrintWords( vInputs );
|
||||
printf( ". OUTPUT: " );
|
||||
Abc_NtkVerifyPrintWords( vOutputs1 );
|
||||
printf( " (%s)", pNtkName1 ? pNtkName1 : "network1" );
|
||||
if ( pValues2 && Vec_PtrSize(vOutputs2) )
|
||||
{
|
||||
printf( ", " );
|
||||
Abc_NtkVerifyPrintWords( vOutputs2 );
|
||||
printf( " (%s)", pNtkName2 ? pNtkName2 : "network2" );
|
||||
}
|
||||
printf( ".\n" );
|
||||
}
|
||||
Abc_NtkVerifyFreeWords( vInputs );
|
||||
Abc_NtkVerifyFreeWords( vOutputs1 );
|
||||
Abc_NtkVerifyFreeWords( vOutputs2 );
|
||||
}
|
||||
|
||||
static const char * Abc_NtkVerifyNetworkName( Abc_Ntk_t * pNtk )
|
||||
{
|
||||
if ( pNtk == NULL )
|
||||
return NULL;
|
||||
return Abc_NtkSpec(pNtk) ? Abc_NtkSpec(pNtk) : Abc_NtkName(pNtk);
|
||||
}
|
||||
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
|
|
@ -747,6 +888,8 @@ void Abc_NtkVerifyReportError( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int * pMode
|
|||
{
|
||||
Vec_Ptr_t * vNodes;
|
||||
Abc_Obj_t * pNode;
|
||||
const char ** ppCiNames = NULL;
|
||||
const char ** ppCoNames = NULL;
|
||||
int * pValues1, * pValues2;
|
||||
int nErrors, nPrinted, i, iNode = -1;
|
||||
|
||||
|
|
@ -755,6 +898,17 @@ void Abc_NtkVerifyReportError( Abc_Ntk_t * pNtk1, Abc_Ntk_t * pNtk2, int * pMode
|
|||
// get the CO values under this model
|
||||
pValues1 = Abc_NtkVerifySimulatePattern( pNtk1, pModel );
|
||||
pValues2 = Abc_NtkVerifySimulatePattern( pNtk2, pModel );
|
||||
// print word-level counter-example, if available
|
||||
ppCiNames = ABC_ALLOC( const char *, Abc_NtkCiNum(pNtk1) );
|
||||
Abc_NtkForEachCi( pNtk1, pNode, i )
|
||||
ppCiNames[i] = Abc_ObjName( pNode );
|
||||
ppCoNames = ABC_ALLOC( const char *, Abc_NtkCoNum(pNtk1) );
|
||||
Abc_NtkForEachCo( pNtk1, pNode, i )
|
||||
ppCoNames[i] = Abc_ObjName( pNode );
|
||||
Abc_NtkVerifyPrintCex( pModel, pValues1, pValues2, ppCiNames, Abc_NtkCiNum(pNtk1),
|
||||
ppCoNames, Abc_NtkCoNum(pNtk1), Abc_NtkVerifyNetworkName(pNtk1), Abc_NtkVerifyNetworkName(pNtk2) );
|
||||
ABC_FREE( ppCiNames );
|
||||
ABC_FREE( ppCoNames );
|
||||
// count the mismatches
|
||||
nErrors = 0;
|
||||
for ( i = 0; i < Abc_NtkCoNum(pNtk1); i++ )
|
||||
|
|
@ -1115,4 +1269,3 @@ int Abc_NtkIsValidCex( Abc_Ntk_t * pNtk, Abc_Cex_t * pCex )
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -1890,7 +1890,8 @@ usage:
|
|||
***********************************************************************/
|
||||
int IoCommandReadJsonc( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern int Jsonc_ReadTest( char * pFileName );
|
||||
extern Abc_Ntk_t * Jsonc_ReadNetwork( char * pFileName );
|
||||
Abc_Ntk_t * pNtk;
|
||||
char * pFileName;
|
||||
FILE * pFile;
|
||||
int c;
|
||||
|
|
@ -1920,7 +1921,11 @@ int IoCommandReadJsonc( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
}
|
||||
fclose( pFile );
|
||||
|
||||
Jsonc_ReadTest( pFileName );
|
||||
pNtk = Jsonc_ReadNetwork( pFileName );
|
||||
if ( pNtk == NULL )
|
||||
return 1;
|
||||
Abc_FrameReplaceCurrentNetwork( pAbc, pNtk );
|
||||
Abc_FrameClearVerifStatus( pAbc );
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
|
|
@ -4607,4 +4612,3 @@ usage:
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ioAbc.h"
|
||||
#include "base/abc/abc.h"
|
||||
#include "base/main/main.h"
|
||||
#include "map/mio/mio.h"
|
||||
#include "ioAbc.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
|
|
@ -45,38 +47,50 @@ typedef enum {
|
|||
} json_type_t;
|
||||
|
||||
// Core structure: stores offset and length in the original string
|
||||
typedef struct {
|
||||
uint32_t offset; // Offset in the JSON string
|
||||
uint32_t length; // Length of this value
|
||||
json_type_t type; // Type of JSON value
|
||||
typedef struct json_value_t_ {
|
||||
uint32_t offset; // Offset in the JSON string
|
||||
uint32_t length; // Length of this value
|
||||
json_type_t type; // Type of JSON value
|
||||
uint32_t container; // Index of the container if this is an object/array
|
||||
} json_value_t;
|
||||
|
||||
// Key-value pair for objects
|
||||
typedef struct {
|
||||
json_value_t key; // Key (always a string)
|
||||
json_value_t value; // Associated value
|
||||
typedef struct json_pair_t_ {
|
||||
json_value_t key; // Key (always a string)
|
||||
json_value_t value; // Associated value
|
||||
} json_pair_t;
|
||||
|
||||
// Dynamic array for storing pairs (objects) or values (arrays)
|
||||
typedef struct {
|
||||
typedef struct json_container_t_ {
|
||||
union {
|
||||
json_pair_t *pairs; // For objects
|
||||
json_value_t *values; // For arrays
|
||||
} data;
|
||||
uint32_t count; // Number of elements
|
||||
uint32_t capacity; // Allocated capacity
|
||||
uint32_t count; // Number of elements
|
||||
uint32_t capacity; // Allocated capacity
|
||||
} json_container_t;
|
||||
|
||||
// Main JSON structure
|
||||
typedef struct {
|
||||
char *str; // The original JSON string
|
||||
uint32_t str_len; // Length of the string
|
||||
json_value_t root; // Root element
|
||||
json_container_t *containers; // Array of containers
|
||||
uint32_t container_count; // Number of containers
|
||||
uint32_t container_capacity; // Allocated capacity
|
||||
typedef struct json_t_ {
|
||||
char *str; // The original JSON string
|
||||
uint32_t str_len; // Length of the string
|
||||
json_value_t root; // Root element
|
||||
json_container_t *containers; // Array of containers
|
||||
uint32_t container_count; // Number of containers
|
||||
uint32_t container_capacity; // Allocated capacity
|
||||
} json_t;
|
||||
|
||||
// Creation / destruction
|
||||
json_t * json_create(void);
|
||||
void json_destroy(json_t *json);
|
||||
bool json_load_file(json_t *json, const char *filename);
|
||||
|
||||
// Debug/printing helpers
|
||||
void json_print(json_t *json, FILE *fp);
|
||||
void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool format);
|
||||
void json_print_string(json_t *json, json_value_t val, FILE *fp);
|
||||
void json_debug_value(json_t *json, json_value_t val, int indent);
|
||||
|
||||
// Function prototypes
|
||||
json_t* json_create(void);
|
||||
void json_destroy(json_t *json);
|
||||
|
|
@ -93,6 +107,12 @@ void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool
|
|||
void json_print_string(json_t *json, json_value_t val, FILE *fp);
|
||||
void json_debug_value(json_t *json, json_value_t val, int indent);
|
||||
|
||||
extern Abc_Ntk_t * Abc_NtkFromMiniMapping( int * pArray );
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Create a new JSON structure
|
||||
json_t* json_create(void) {
|
||||
json_t *json = (json_t*)calloc(1, sizeof(json_t));
|
||||
|
|
@ -185,6 +205,7 @@ json_container_t* json_add_container(json_t *json) {
|
|||
// Parse a JSON string
|
||||
json_value_t json_parse_string(json_t *json, uint32_t *pos) {
|
||||
json_value_t val = {0};
|
||||
val.container = UINT32_MAX;
|
||||
val.type = JSON_STRING;
|
||||
val.offset = *pos;
|
||||
|
||||
|
|
@ -203,6 +224,7 @@ json_value_t json_parse_string(json_t *json, uint32_t *pos) {
|
|||
// Parse a JSON number
|
||||
json_value_t json_parse_number(json_t *json, uint32_t *pos) {
|
||||
json_value_t val = {0};
|
||||
val.container = UINT32_MAX;
|
||||
val.type = JSON_NUMBER;
|
||||
val.offset = *pos;
|
||||
|
||||
|
|
@ -223,6 +245,7 @@ json_value_t json_parse_number(json_t *json, uint32_t *pos) {
|
|||
// Parse a JSON object
|
||||
json_value_t json_parse_object(json_t *json, uint32_t *pos) {
|
||||
json_value_t val = {0};
|
||||
val.container = UINT32_MAX;
|
||||
val.type = JSON_OBJECT;
|
||||
val.offset = *pos;
|
||||
|
||||
|
|
@ -230,6 +253,8 @@ json_value_t json_parse_object(json_t *json, uint32_t *pos) {
|
|||
|
||||
json_container_t *container = json_add_container(json);
|
||||
if (!container) return val;
|
||||
val.container = json->container_count - 1;
|
||||
container = json->containers + val.container;
|
||||
|
||||
container->capacity = 8;
|
||||
container->data.pairs = (json_pair_t*)calloc(container->capacity, sizeof(json_pair_t));
|
||||
|
|
@ -249,6 +274,7 @@ json_value_t json_parse_object(json_t *json, uint32_t *pos) {
|
|||
json_value_t value = json_parse_value(json, pos);
|
||||
|
||||
// Add pair to container
|
||||
container = json->containers + val.container;
|
||||
if (container->count >= container->capacity) {
|
||||
uint32_t new_capacity = container->capacity * 2;
|
||||
json_pair_t *new_pairs = (json_pair_t*)realloc(
|
||||
|
|
@ -278,6 +304,7 @@ json_value_t json_parse_object(json_t *json, uint32_t *pos) {
|
|||
// Parse a JSON array
|
||||
json_value_t json_parse_array(json_t *json, uint32_t *pos) {
|
||||
json_value_t val = {0};
|
||||
val.container = UINT32_MAX;
|
||||
val.type = JSON_ARRAY;
|
||||
val.offset = *pos;
|
||||
|
||||
|
|
@ -285,6 +312,8 @@ json_value_t json_parse_array(json_t *json, uint32_t *pos) {
|
|||
|
||||
json_container_t *container = json_add_container(json);
|
||||
if (!container) return val;
|
||||
val.container = json->container_count - 1;
|
||||
container = json->containers + val.container;
|
||||
|
||||
container->capacity = 8;
|
||||
container->data.values = (json_value_t*)calloc(container->capacity, sizeof(json_value_t));
|
||||
|
|
@ -297,6 +326,7 @@ json_value_t json_parse_array(json_t *json, uint32_t *pos) {
|
|||
json_value_t value = json_parse_value(json, pos);
|
||||
|
||||
// Add value to container
|
||||
container = json->containers + val.container;
|
||||
if (container->count >= container->capacity) {
|
||||
uint32_t new_capacity = container->capacity * 2;
|
||||
json_value_t *new_values = (json_value_t*)realloc(
|
||||
|
|
@ -325,6 +355,7 @@ json_value_t json_parse_array(json_t *json, uint32_t *pos) {
|
|||
// Parse any JSON value
|
||||
json_value_t json_parse_value(json_t *json, uint32_t *pos) {
|
||||
json_value_t val = {0};
|
||||
val.container = UINT32_MAX;
|
||||
|
||||
json_skip_whitespace(json->str, pos, json->str_len);
|
||||
|
||||
|
|
@ -342,18 +373,21 @@ json_value_t json_parse_value(json_t *json, uint32_t *pos) {
|
|||
val.type = JSON_NULL;
|
||||
val.offset = *pos;
|
||||
val.length = 4;
|
||||
val.container = UINT32_MAX;
|
||||
*pos += 4;
|
||||
return val;
|
||||
} else if (c == 't') {
|
||||
val.type = JSON_BOOL;
|
||||
val.offset = *pos;
|
||||
val.length = 4;
|
||||
val.container = UINT32_MAX;
|
||||
*pos += 4;
|
||||
return val;
|
||||
} else if (c == 'f') {
|
||||
val.type = JSON_BOOL;
|
||||
val.offset = *pos;
|
||||
val.length = 5;
|
||||
val.container = UINT32_MAX;
|
||||
*pos += 5;
|
||||
return val;
|
||||
} else if ((c >= '0' && c <= '9') || c == '-') {
|
||||
|
|
@ -397,6 +431,7 @@ bool json_load_file(json_t *json, const char *filename) {
|
|||
|
||||
json->str[file_size] = '\0';
|
||||
json->str_len = (uint32_t)file_size;
|
||||
json->container_count = 0;
|
||||
|
||||
// Parse JSON
|
||||
uint32_t pos = 0;
|
||||
|
|
@ -442,24 +477,8 @@ void json_print_string(json_t *json, json_value_t val, FILE *fp) {
|
|||
fputc('"', fp);
|
||||
}
|
||||
|
||||
// Find the container index for a given value
|
||||
static int find_container_index(json_t *json, json_value_t val) {
|
||||
static int last_container = 0;
|
||||
|
||||
// Check if it's an object or array
|
||||
if (val.type == JSON_OBJECT || val.type == JSON_ARRAY) {
|
||||
int index = last_container++;
|
||||
if (index < json->container_count) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Print a JSON value recursively
|
||||
void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool format) {
|
||||
static int container_index = 0;
|
||||
|
||||
switch (val.type) {
|
||||
case JSON_NULL:
|
||||
fprintf(fp, "null");
|
||||
|
|
@ -486,8 +505,8 @@ void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool
|
|||
case JSON_ARRAY: {
|
||||
fputc('[', fp);
|
||||
|
||||
if (container_index < json->container_count) {
|
||||
json_container_t *container = &json->containers[container_index++];
|
||||
if (val.container < json->container_count) {
|
||||
json_container_t *container = &json->containers[val.container];
|
||||
|
||||
for (uint32_t i = 0; i < container->count; i++) {
|
||||
if (format) {
|
||||
|
|
@ -516,8 +535,8 @@ void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool
|
|||
case JSON_OBJECT: {
|
||||
fputc('{', fp);
|
||||
|
||||
if (container_index < json->container_count) {
|
||||
json_container_t *container = &json->containers[container_index++];
|
||||
if (val.container < json->container_count) {
|
||||
json_container_t *container = &json->containers[val.container];
|
||||
|
||||
for (uint32_t i = 0; i < container->count; i++) {
|
||||
if (format) {
|
||||
|
|
@ -549,7 +568,6 @@ void json_print_value(json_t *json, json_value_t val, FILE *fp, int indent, bool
|
|||
|
||||
// Print the entire JSON to a file
|
||||
void json_print(json_t *json, FILE *fp) {
|
||||
// Reset the static container index in json_print_value
|
||||
json_print_value(json, json->root, fp, 0, true);
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
|
@ -722,7 +740,6 @@ void Jsonc_WriteTest( Abc_Ntk_t * p, char * pFileName )
|
|||
fprintf( pFile, " }%s\n", Mio_PinReadNext(pPin) ? "," : "" );
|
||||
}
|
||||
fprintf( pFile, " }\n" );
|
||||
//fprintf( pFile, " ]\n" );
|
||||
fprintf( pFile, " }%s\n", ++Counter == Total ? "" : "," );
|
||||
}
|
||||
Abc_NtkForEachPo( p, pObj, i )
|
||||
|
|
@ -749,6 +766,443 @@ void Jsonc_WriteTest( Abc_Ntk_t * p, char * pFileName )
|
|||
Vec_PtrFree( vNodes );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
static json_container_t * Jsonc_GetContainer( json_t * pJson, json_value_t value )
|
||||
{
|
||||
if ( value.container == UINT32_MAX )
|
||||
return NULL;
|
||||
if ( value.container >= pJson->container_count )
|
||||
return NULL;
|
||||
return pJson->containers + value.container;
|
||||
}
|
||||
static int Jsonc_StringEqual( json_t * pJson, json_value_t value, const char * pStr )
|
||||
{
|
||||
uint32_t Len;
|
||||
if ( value.type != JSON_STRING || value.length < 2 )
|
||||
return 0;
|
||||
Len = value.length - 2;
|
||||
return strlen(pStr) == Len && strncmp( pJson->str + value.offset + 1, pStr, Len ) == 0;
|
||||
}
|
||||
static char * Jsonc_StringDup( json_t * pJson, json_value_t value )
|
||||
{
|
||||
char * pRes;
|
||||
uint32_t i, Len;
|
||||
if ( value.type != JSON_STRING || value.length < 2 )
|
||||
return NULL;
|
||||
Len = value.length - 2;
|
||||
pRes = ABC_ALLOC( char, Len + 1 );
|
||||
for ( i = 0; i < Len; i++ )
|
||||
{
|
||||
char c = pJson->str[value.offset + 1 + i];
|
||||
if ( c == '\\' && i + 1 < Len )
|
||||
{
|
||||
i++;
|
||||
c = pJson->str[value.offset + 1 + i];
|
||||
}
|
||||
pRes[i] = c;
|
||||
}
|
||||
pRes[Len] = '\0';
|
||||
return pRes;
|
||||
}
|
||||
static int Jsonc_ParseInt( json_t * pJson, json_value_t value, int * pResult )
|
||||
{
|
||||
char * pBuffer, * pEnd;
|
||||
uint32_t Len;
|
||||
long Temp;
|
||||
if ( value.type != JSON_NUMBER )
|
||||
return 0;
|
||||
Len = value.length;
|
||||
pBuffer = ABC_ALLOC( char, Len + 1 );
|
||||
memcpy( pBuffer, pJson->str + value.offset, Len );
|
||||
pBuffer[Len] = '\0';
|
||||
Temp = strtol( pBuffer, &pEnd, 10 );
|
||||
ABC_FREE( pBuffer );
|
||||
if ( pEnd == NULL || pEnd == pBuffer )
|
||||
return 0;
|
||||
*pResult = (int)Temp;
|
||||
return 1;
|
||||
}
|
||||
static json_value_t * Jsonc_ObjectLookup( json_t * pJson, json_value_t object, const char * pKey )
|
||||
{
|
||||
json_container_t * pCont;
|
||||
uint32_t i;
|
||||
if ( object.type != JSON_OBJECT )
|
||||
return NULL;
|
||||
pCont = Jsonc_GetContainer( pJson, object );
|
||||
if ( pCont == NULL )
|
||||
return NULL;
|
||||
for ( i = 0; i < pCont->count; i++ )
|
||||
if ( Jsonc_StringEqual( pJson, pCont->data.pairs[i].key, pKey ) )
|
||||
return &pCont->data.pairs[i].value;
|
||||
return NULL;
|
||||
}
|
||||
static Vec_Int_t * Jsonc_NameCounts( Vec_Ptr_t * vBases, Vec_Int_t ** pvBaseIds )
|
||||
{
|
||||
Abc_Nam_t * pNames;
|
||||
Vec_Int_t * vCounts, * vBaseIds;
|
||||
char * pBase;
|
||||
int i, Id;
|
||||
pNames = Abc_NamStart( Vec_PtrSize(vBases) + 1, 24 );
|
||||
vCounts = Vec_IntAlloc( Vec_PtrSize(vBases) + 1 );
|
||||
vBaseIds = Vec_IntAlloc( Vec_PtrSize(vBases) + 1 );
|
||||
Vec_IntFillExtra( vCounts, 1, 0 );
|
||||
Vec_PtrForEachEntry( char *, vBases, pBase, i )
|
||||
{
|
||||
int fFound;
|
||||
Id = Abc_NamStrFindOrAdd( pNames, pBase, &fFound );
|
||||
Vec_IntFillExtra( vCounts, Id + 1, 0 );
|
||||
Vec_IntAddToEntry( vCounts, Id, 1 );
|
||||
Vec_IntPush( vBaseIds, Id );
|
||||
}
|
||||
Abc_NamDeref( pNames );
|
||||
*pvBaseIds = vBaseIds;
|
||||
return vCounts;
|
||||
}
|
||||
static void Jsonc_AppendName( Vec_Str_t * vNames, const char * pBase, int Bit, int fUseBit )
|
||||
{
|
||||
int nSize = (int)strlen(pBase ? pBase : "") + 32;
|
||||
char * pBuffer = ABC_ALLOC( char, nSize );
|
||||
if ( fUseBit )
|
||||
snprintf( pBuffer, nSize, "%s[%d]", pBase ? pBase : "", Bit );
|
||||
else
|
||||
snprintf( pBuffer, nSize, "%s", pBase ? pBase : "" );
|
||||
Vec_StrPrintStr( vNames, pBuffer );
|
||||
Vec_StrPush( vNames, '\0' );
|
||||
ABC_FREE( pBuffer );
|
||||
}
|
||||
static void Jsonc_AppendPortNames( Vec_Str_t * vNames, Vec_Ptr_t * vBases, Vec_Int_t * vBits )
|
||||
{
|
||||
Vec_Int_t * vCounts, * vBaseIds;
|
||||
char * pBase;
|
||||
int i, Bit, Count;
|
||||
vCounts = Jsonc_NameCounts( vBases, &vBaseIds );
|
||||
Vec_PtrForEachEntry( char *, vBases, pBase, i )
|
||||
{
|
||||
Bit = Vec_IntEntry( vBits, i );
|
||||
Count = Vec_IntEntry( vCounts, Vec_IntEntry( vBaseIds, i ) );
|
||||
Jsonc_AppendName( vNames, pBase, Bit, Bit != 0 || Count > 1 );
|
||||
}
|
||||
Vec_IntFree( vCounts );
|
||||
Vec_IntFree( vBaseIds );
|
||||
}
|
||||
static Vec_Int_t * Jsonc_ConvertToMiniMapping( json_t * pJson, Mio_Library_t * pLib, char ** ppDesignName )
|
||||
{
|
||||
Vec_Ptr_t * vPiBases = NULL, * vPoBases = NULL;
|
||||
Vec_Int_t * vPiBits = NULL, * vPoBits = NULL;
|
||||
Vec_Int_t * vNodeMap = NULL, * vGateIdx = NULL, * vPoIdx = NULL;
|
||||
Vec_Int_t * vMapping = NULL, * vPoDrivers = NULL;
|
||||
Vec_Str_t * vNames = NULL;
|
||||
json_container_t * pNodes;
|
||||
json_value_t * pTemp;
|
||||
char * pBase;
|
||||
int i, k, nCis = 0, nNodes = 0, nCos = 0;
|
||||
int fSuccess = 0;
|
||||
if ( ppDesignName )
|
||||
*ppDesignName = NULL;
|
||||
if ( pLib == NULL )
|
||||
{
|
||||
printf( "Genlib library is not available.\n" );
|
||||
return NULL;
|
||||
}
|
||||
if ( pJson->root.type != JSON_OBJECT )
|
||||
{
|
||||
printf( "JSONC root should be an object.\n" );
|
||||
return NULL;
|
||||
}
|
||||
pTemp = Jsonc_ObjectLookup( pJson, pJson->root, "name" );
|
||||
if ( pTemp && ppDesignName && pTemp->type == JSON_STRING )
|
||||
*ppDesignName = Jsonc_StringDup( pJson, *pTemp );
|
||||
pTemp = Jsonc_ObjectLookup( pJson, pJson->root, "nodes" );
|
||||
if ( pTemp == NULL || pTemp->type != JSON_ARRAY )
|
||||
{
|
||||
printf( "JSONC file is missing top-level \"nodes\" array.\n" );
|
||||
return NULL;
|
||||
}
|
||||
pNodes = Jsonc_GetContainer( pJson, *pTemp );
|
||||
if ( pNodes == NULL )
|
||||
{
|
||||
printf( "Internal JSONC structure is incomplete.\n" );
|
||||
return NULL;
|
||||
}
|
||||
vNodeMap = Vec_IntStartFull( pNodes->count );
|
||||
vGateIdx = Vec_IntAlloc( pNodes->count );
|
||||
vPoIdx = Vec_IntAlloc( pNodes->count );
|
||||
vPiBases = Vec_PtrAlloc( pNodes->count );
|
||||
vPiBits = Vec_IntAlloc( pNodes->count );
|
||||
vPoBases = Vec_PtrAlloc( pNodes->count );
|
||||
vPoBits = Vec_IntAlloc( pNodes->count );
|
||||
// first pass: collect object types and names
|
||||
for ( i = 0; i < (int)pNodes->count; i++ )
|
||||
{
|
||||
json_value_t Node = pNodes->data.values[i];
|
||||
json_value_t * pType = Jsonc_ObjectLookup( pJson, Node, "type" );
|
||||
json_value_t * pName = Jsonc_ObjectLookup( pJson, Node, "name" );
|
||||
json_value_t * pBit = Jsonc_ObjectLookup( pJson, Node, "bit" );
|
||||
int Bit = 0;
|
||||
if ( pType == NULL || pType->type != JSON_STRING )
|
||||
{
|
||||
printf( "Node %d does not have a valid \"type\" field.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
if ( pBit && !Jsonc_ParseInt( pJson, *pBit, &Bit ) )
|
||||
{
|
||||
printf( "Node %d has an invalid \"bit\" field.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
if ( Jsonc_StringEqual( pJson, *pType, "pi" ) )
|
||||
{
|
||||
Vec_IntWriteEntry( vNodeMap, i, nCis++ );
|
||||
pBase = Jsonc_StringDup( pJson, pName ? *pName : *pType );
|
||||
if ( pBase == NULL )
|
||||
{
|
||||
printf( "Primary input %d is missing a name.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
Vec_PtrPush( vPiBases, pBase );
|
||||
Vec_IntPush( vPiBits, Bit );
|
||||
}
|
||||
else if ( Jsonc_StringEqual( pJson, *pType, "instance" ) )
|
||||
{
|
||||
Vec_IntPush( vGateIdx, i );
|
||||
nNodes++;
|
||||
}
|
||||
else if ( Jsonc_StringEqual( pJson, *pType, "PO" ) || Jsonc_StringEqual( pJson, *pType, "po" ) )
|
||||
{
|
||||
Vec_IntPush( vPoIdx, i );
|
||||
nCos++;
|
||||
pBase = Jsonc_StringDup( pJson, pName ? *pName : *pType );
|
||||
if ( pBase == NULL )
|
||||
{
|
||||
printf( "Primary output %d is missing a name.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
Vec_PtrPush( vPoBases, pBase );
|
||||
Vec_IntPush( vPoBits, Bit );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Node %d has unsupported type.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
// assign IDs to internal nodes
|
||||
for ( i = 0; i < Vec_IntSize(vGateIdx); i++ )
|
||||
Vec_IntWriteEntry( vNodeMap, Vec_IntEntry(vGateIdx, i), nCis + i );
|
||||
// allocate storage for mapping
|
||||
vMapping = Vec_IntAlloc( 4 + nNodes * 4 + nCos + 10 );
|
||||
vNames = Vec_StrAlloc( 1024 );
|
||||
vPoDrivers = Vec_IntAlloc( nCos );
|
||||
Vec_IntPush( vMapping, nCis );
|
||||
Vec_IntPush( vMapping, nCos );
|
||||
Vec_IntPush( vMapping, nNodes );
|
||||
Vec_IntPush( vMapping, 0 ); // flops
|
||||
// second pass: build nodes and POs
|
||||
for ( i = 0; i < (int)pNodes->count; i++ )
|
||||
{
|
||||
json_value_t Node = pNodes->data.values[i];
|
||||
json_value_t * pType = Jsonc_ObjectLookup( pJson, Node, "type" );
|
||||
if ( Jsonc_StringEqual( pJson, *pType, "instance" ) )
|
||||
{
|
||||
json_value_t * pGateName = Jsonc_ObjectLookup( pJson, Node, "name" );
|
||||
json_value_t * pFanins = Jsonc_ObjectLookup( pJson, Node, "fanins" );
|
||||
json_container_t * pFanObj;
|
||||
Mio_Gate_t * pGate;
|
||||
Mio_Pin_t * pPin;
|
||||
char * pGateStr;
|
||||
if ( pGateName == NULL || pGateName->type != JSON_STRING )
|
||||
{
|
||||
printf( "Gate node %d is missing a name.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
pGateStr = Jsonc_StringDup( pJson, *pGateName );
|
||||
if ( pGateStr == NULL )
|
||||
{
|
||||
printf( "Gate node %d has an invalid name.\n", i );
|
||||
goto cleanup;
|
||||
}
|
||||
pGate = Mio_LibraryReadGateByName( pLib, pGateStr, NULL );
|
||||
if ( pGate == NULL )
|
||||
{
|
||||
printf( "Gate \"%s\" is not found in the current library.\n", pGateStr );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
if ( pFanins == NULL || pFanins->type != JSON_OBJECT )
|
||||
{
|
||||
printf( "Gate \"%s\" is missing \"fanins\" description.\n", pGateStr );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
pFanObj = Jsonc_GetContainer( pJson, *pFanins );
|
||||
if ( pFanObj == NULL )
|
||||
{
|
||||
printf( "Gate \"%s\" has incomplete fanin information.\n", pGateStr );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
Vec_IntPush( vMapping, Mio_GateReadPinNum(pGate) );
|
||||
for ( pPin = Mio_GateReadPins(pGate), k = 0; pPin; pPin = Mio_PinReadNext(pPin), k++ )
|
||||
{
|
||||
json_value_t * pPinInfo = Jsonc_ObjectLookup( pJson, *pFanins, Mio_PinReadName(pPin) );
|
||||
json_value_t * pNodeLit;
|
||||
int NodeId, MapId;
|
||||
if ( pPinInfo == NULL || pPinInfo->type != JSON_OBJECT )
|
||||
{
|
||||
printf( "Gate \"%s\" is missing connection for pin \"%s\".\n", pGateStr, Mio_PinReadName(pPin) );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
pNodeLit = Jsonc_ObjectLookup( pJson, *pPinInfo, "node" );
|
||||
if ( pNodeLit == NULL || !Jsonc_ParseInt( pJson, *pNodeLit, &NodeId ) )
|
||||
{
|
||||
printf( "Gate \"%s\" has invalid node reference on pin \"%s\".\n", pGateStr, Mio_PinReadName(pPin) );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
if ( NodeId < 0 || NodeId >= Vec_IntSize(vNodeMap) )
|
||||
{
|
||||
printf( "Gate \"%s\" references out-of-range node %d.\n", pGateStr, NodeId );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
MapId = Vec_IntEntry( vNodeMap, NodeId );
|
||||
if ( MapId < 0 )
|
||||
{
|
||||
printf( "Gate \"%s\" refers to unsupported node %d.\n", pGateStr, NodeId );
|
||||
ABC_FREE( pGateStr );
|
||||
goto cleanup;
|
||||
}
|
||||
Vec_IntPush( vMapping, MapId );
|
||||
}
|
||||
Vec_StrPrintStr( vNames, pGateStr );
|
||||
Vec_StrPush( vNames, '\0' );
|
||||
ABC_FREE( pGateStr );
|
||||
}
|
||||
else if ( Jsonc_StringEqual( pJson, *pType, "PO" ) || Jsonc_StringEqual( pJson, *pType, "po" ) )
|
||||
{
|
||||
json_value_t * pFanin = Jsonc_ObjectLookup( pJson, Node, "fanin" );
|
||||
json_value_t * pNodeId = pFanin ? Jsonc_ObjectLookup( pJson, *pFanin, "node" ) : NULL;
|
||||
int NodeId, MapId;
|
||||
if ( pNodeId == NULL || !Jsonc_ParseInt( pJson, *pNodeId, &NodeId ) )
|
||||
{
|
||||
printf( "Primary output %d is missing driver information.\n", Vec_IntSize(vPoDrivers) );
|
||||
goto cleanup;
|
||||
}
|
||||
if ( NodeId < 0 || NodeId >= Vec_IntSize(vNodeMap) )
|
||||
{
|
||||
printf( "Primary output %d refers to out-of-range node %d.\n", Vec_IntSize(vPoDrivers), NodeId );
|
||||
goto cleanup;
|
||||
}
|
||||
MapId = Vec_IntEntry( vNodeMap, NodeId );
|
||||
if ( MapId < 0 )
|
||||
{
|
||||
printf( "Primary output %d points to unsupported node %d.\n", Vec_IntSize(vPoDrivers), NodeId );
|
||||
goto cleanup;
|
||||
}
|
||||
Vec_IntPush( vPoDrivers, MapId );
|
||||
}
|
||||
}
|
||||
if ( Vec_IntSize(vPoDrivers) != nCos )
|
||||
{
|
||||
printf( "JSONC file declares %d POs but %d drivers were found.\n", nCos, Vec_IntSize(vPoDrivers) );
|
||||
goto cleanup;
|
||||
}
|
||||
// append CO drivers
|
||||
Vec_IntForEachEntry( vPoDrivers, k, i )
|
||||
Vec_IntPush( vMapping, k );
|
||||
// append gate / CI / CO names
|
||||
Jsonc_AppendPortNames( vNames, vPiBases, vPiBits );
|
||||
Jsonc_AppendPortNames( vNames, vPoBases, vPoBits );
|
||||
// align to 4 bytes and append strings as ints
|
||||
{
|
||||
int nExtra = (4 - Vec_StrSize(vNames) % 4) % 4;
|
||||
int nWords, * pBuffer;
|
||||
for ( i = 0; i < nExtra; i++ )
|
||||
Vec_StrPush( vNames, '\0' );
|
||||
nWords = Vec_StrSize(vNames) / 4;
|
||||
pBuffer = (int *)Vec_StrArray( vNames );
|
||||
for ( i = 0; i < nWords; i++ )
|
||||
Vec_IntPush( vMapping, pBuffer[i] );
|
||||
}
|
||||
fSuccess = 1;
|
||||
cleanup:
|
||||
if ( fSuccess == 0 && ppDesignName && *ppDesignName )
|
||||
ABC_FREE( *ppDesignName );
|
||||
Vec_IntFreeP( &vPoDrivers );
|
||||
Vec_IntFreeP( &vNodeMap );
|
||||
Vec_IntFreeP( &vGateIdx );
|
||||
Vec_IntFreeP( &vPoIdx );
|
||||
Vec_IntFreeP( &vPiBits );
|
||||
Vec_IntFreeP( &vPoBits );
|
||||
if ( vNames )
|
||||
Vec_StrFree( vNames );
|
||||
if ( vPiBases )
|
||||
{
|
||||
Vec_PtrForEachEntry( char *, vPiBases, pBase, i )
|
||||
ABC_FREE( pBase );
|
||||
Vec_PtrFree( vPiBases );
|
||||
}
|
||||
if ( vPoBases )
|
||||
{
|
||||
Vec_PtrForEachEntry( char *, vPoBases, pBase, i )
|
||||
ABC_FREE( pBase );
|
||||
Vec_PtrFree( vPoBases );
|
||||
}
|
||||
if ( fSuccess == 0 && vMapping )
|
||||
{
|
||||
Vec_IntFree( vMapping );
|
||||
vMapping = NULL;
|
||||
}
|
||||
return vMapping;
|
||||
}
|
||||
Abc_Ntk_t * Jsonc_ReadNetwork( char * pFileName )
|
||||
{
|
||||
Mio_Library_t * pLib = (Mio_Library_t *)Abc_FrameReadLibGen();
|
||||
Vec_Int_t * vMapping;
|
||||
Abc_Ntk_t * pNtk;
|
||||
char * pDesignName = NULL;
|
||||
json_t * pJson = json_create();
|
||||
if ( pJson == NULL )
|
||||
{
|
||||
printf( "Failed to allocate JSONC parser.\n" );
|
||||
return NULL;
|
||||
}
|
||||
if ( !json_load_file( pJson, pFileName ) )
|
||||
{
|
||||
printf( "Failed to load JSONC file \"%s\".\n", pFileName );
|
||||
json_destroy( pJson );
|
||||
return NULL;
|
||||
}
|
||||
vMapping = Jsonc_ConvertToMiniMapping( pJson, pLib, &pDesignName );
|
||||
json_destroy( pJson );
|
||||
if ( vMapping == NULL )
|
||||
return NULL;
|
||||
pNtk = Abc_NtkFromMiniMapping( Vec_IntArray(vMapping) );
|
||||
Vec_IntFree( vMapping );
|
||||
if ( pNtk == NULL )
|
||||
{
|
||||
ABC_FREE( pDesignName );
|
||||
return NULL;
|
||||
}
|
||||
ABC_FREE( pNtk->pName );
|
||||
pNtk->pName = pDesignName ? pDesignName : Extra_FileNameGeneric( pFileName );
|
||||
ABC_FREE( pNtk->pSpec );
|
||||
pNtk->pSpec = Abc_UtilStrsav( pFileName );
|
||||
return pNtk;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ extern void Glucose_Init( Abc_Frame_t *pAbc );
|
|||
extern void Glucose_End( Abc_Frame_t * pAbc );
|
||||
extern void Glucose2_Init( Abc_Frame_t *pAbc );
|
||||
extern void Glucose2_End( Abc_Frame_t * pAbc );
|
||||
extern void Ufar_Init(Abc_Frame_t *pAbc);
|
||||
|
||||
static Abc_FrameInitializer_t* s_InitializerStart = NULL;
|
||||
static Abc_FrameInitializer_t* s_InitializerEnd = NULL;
|
||||
|
|
@ -123,6 +124,7 @@ void Abc_FrameInit( Abc_Frame_t * pAbc )
|
|||
Cba_Init( pAbc );
|
||||
Pla_Init( pAbc );
|
||||
Test_Init( pAbc );
|
||||
Ufar_Init( pAbc );
|
||||
Glucose_Init( pAbc );
|
||||
Glucose2_Init( pAbc );
|
||||
for( p = s_InitializerStart ; p ; p = p->next )
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ void Wln_End( Abc_Frame_t * pAbc )
|
|||
int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern Abc_Ntk_t * Wln_ReadMappedSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, char * pLibrary, int fVerbose );
|
||||
extern Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fVerbose );
|
||||
extern Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose );
|
||||
extern Rtl_Lib_t * Wln_ReadSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fCollapse, int fVerbose );
|
||||
|
||||
FILE * pFile;
|
||||
|
|
@ -107,9 +107,10 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
int fLibInDir = 0;
|
||||
int fSkipStrash = 0;
|
||||
int fCollapse = 0;
|
||||
int fSetUndef = 0;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "TDLbismlcvh" ) ) != EOF )
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "TDLbisumlcvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
|
|
@ -158,6 +159,9 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
case 'c':
|
||||
fCollapse ^= 1;
|
||||
break;
|
||||
case 'u':
|
||||
fSetUndef ^= 1;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
|
|
@ -203,11 +207,11 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
{
|
||||
Gia_Man_t * pNew = NULL;
|
||||
if ( !strcmp( Extra_FileNameExtension(pFileName), "v" ) )
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fVerbose );
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose );
|
||||
else if ( !strcmp( Extra_FileNameExtension(pFileName), "sv" ) )
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fVerbose );
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose );
|
||||
else if ( !strcmp( Extra_FileNameExtension(pFileName), "rtlil" ) )
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fVerbose );
|
||||
pNew = Wln_BlastSystemVerilog( pFileName, pTopModule, pDefines, fSkipStrash, fInvert, fTechMap, fLibInDir, fSetUndef, fVerbose );
|
||||
else
|
||||
{
|
||||
printf( "Abc_CommandYosys(): Unknown file extension.\n" );
|
||||
|
|
@ -233,7 +237,7 @@ int Abc_CommandYosys( Abc_Frame_t * pAbc, int argc, char ** argv )
|
|||
}
|
||||
return 0;
|
||||
usage:
|
||||
Abc_Print( -2, "usage: %%yosys [-T <module>] [-D <defines>] [-L <liberty_file>] [-bismlcvh] <file_name>\n" );
|
||||
Abc_Print( -2, "usage: %%yosys [-T <module>] [-D <defines>] [-L <liberty_file>] [-bisumlcvh] <file_name>\n" );
|
||||
Abc_Print( -2, "\t reads Verilog or SystemVerilog using Yosys\n" );
|
||||
Abc_Print( -2, "\t-T : specify the top module name (default uses \"-auto-top\")\n" );
|
||||
Abc_Print( -2, "\t-D : specify defines to be used by Yosys (default \"not used\")\n" );
|
||||
|
|
@ -244,6 +248,7 @@ usage:
|
|||
Abc_Print( -2, "\t-m : toggle using \"techmap\" to blast operators [default = %s]\n", fTechMap? "yes": "no" );
|
||||
Abc_Print( -2, "\t-l : toggle looking for \"techmap.v\" in the current directory [default = %s]\n", fLibInDir? "yes": "no" );
|
||||
Abc_Print( -2, "\t-c : toggle collapsing design hierarchy using Yosys [default = %s]\n", fCollapse? "yes": "no" );
|
||||
Abc_Print( -2, "\t-u : toggle replacing undefined/reset-X with zero using Yosys setundef [default = %s]\n", fSetUndef? "yes": "no" );
|
||||
Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
return 1;
|
||||
|
|
@ -575,4 +580,3 @@ usage:
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -171,14 +171,14 @@ Rtl_Lib_t * Wln_ReadSystemVerilog( char * pFileName, char * pTopModule, char * p
|
|||
unlink( pFileTemp );
|
||||
return pNtk;
|
||||
}
|
||||
Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fVerbose )
|
||||
Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char * pDefines, int fSkipStrash, int fInvert, int fTechMap, int fLibInDir, int fSetUndef, int fVerbose )
|
||||
{
|
||||
Gia_Man_t * pGia = NULL;
|
||||
char Command[1000];
|
||||
char * pFileTemp = "_temp_.aig";
|
||||
int fRtlil = strstr(pFileName, ".rtl") != NULL;
|
||||
int fSVlog = strstr(pFileName, ".sv") != NULL;
|
||||
sprintf( Command, "%s -qp \"%s %s%s %s%s; hierarchy %s%s; flatten; proc; memory -nomap; memory_map; %saigmap; write_aiger -symbols %s\"",
|
||||
sprintf( Command, "%s -qp \"%s %s%s %s%s; hierarchy %s%s; flatten; proc; opt; async2sync; opt; setundef -undriven -zero; %s%smemory -nomap; memory_map; dffunmap; opt_clean; opt_expr; aigmap; write_aiger -symbols %s\"",
|
||||
Wln_GetYosysName(),
|
||||
fRtlil ? "read_rtlil" : "read_verilog",
|
||||
pDefines ? "-D" : "",
|
||||
|
|
@ -187,7 +187,9 @@ Gia_Man_t * Wln_BlastSystemVerilog( char * pFileName, char * pTopModule, char *
|
|||
pFileName,
|
||||
pTopModule ? "-top " : "-auto-top",
|
||||
pTopModule ? pTopModule : "",
|
||||
fTechMap ? (fLibInDir ? "techmap -map techmap.v; setundef -zero; " : "techmap; setundef -zero; ") : "", pFileTemp );
|
||||
fTechMap ? (fLibInDir ? "techmap -map techmap.v; " : "techmap; ") : "",
|
||||
fSetUndef ? "setundef -init -zero; " : "",
|
||||
pFileTemp );
|
||||
if ( fVerbose )
|
||||
printf( "%s\n", Command );
|
||||
if ( !Wln_ConvertToRtl(Command, pFileTemp) )
|
||||
|
|
@ -260,4 +262,3 @@ Abc_Ntk_t * Wln_ReadMappedSystemVerilog( char * pFileName, char * pTopModule, ch
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ static inline int Abc_Base2LogW( word n ) { int r; if ( n <
|
|||
static inline int Abc_Base10LogW( word n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 10, r++ ) {}; return r; }
|
||||
static inline int Abc_Base16LogW( word n ) { int r; if ( n < 2 ) return (int)n; for ( r = 0, n--; n; n /= 16, r++ ) {}; return r; }
|
||||
static inline char * Abc_UtilStrsav( char * s ) { return s ? strcpy(ABC_ALLOC(char, strlen(s)+1), s) : NULL; }
|
||||
static inline char * Abc_UtilStrsavTwo( char * s, char * a ){ char * r; if (!a) return Abc_UtilStrsav(s); r = ABC_ALLOC(char, strlen(s)+strlen(a)+1); sprintf(r, "%s%s", s, a ); return r; }
|
||||
static inline char * Abc_UtilStrsavNum( char * s, int n ) { char * r; if (!s) return NULL; r = ABC_ALLOC(char, strlen(s)+12+1); sprintf(r, "%s%d", s, n ); return r; }
|
||||
static inline char * Abc_UtilStrsavTwo( char * s, char * a ){ char * r; if (!a) return Abc_UtilStrsav(s); r = ABC_ALLOC(char, strlen(s)+strlen(a)+1); snprintf(r, strlen(s)+strlen(a)+1, "%s%s", s, a ); return r; }
|
||||
static inline char * Abc_UtilStrsavNum( char * s, int n ) { char * r; if (!s) return NULL; r = ABC_ALLOC(char, strlen(s)+12+1); snprintf(r, strlen(s)+12+1, "%s%d", s, n ); return r; }
|
||||
static inline int Abc_BitByteNum( int nBits ) { return (nBits>>3) + ((nBits&7) > 0); }
|
||||
static inline int Abc_BitWordNum( int nBits ) { return (nBits>>5) + ((nBits&31) > 0); }
|
||||
static inline int Abc_Bit6WordNum( int nBits ) { return (nBits>>6) + ((nBits&63) > 0); }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
SRC += src/misc/util/utilBridge.c \
|
||||
SRC += src/misc/util/utilAigSim.c \
|
||||
src/misc/util/utilBridge.c \
|
||||
src/misc/util/utilBipart.c \
|
||||
src/misc/util/utilBSet.c \
|
||||
src/misc/util/utilCex.c \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,663 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [utilAigSim.c]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [AIG simulation.]
|
||||
|
||||
Synopsis [AIG simulation.]
|
||||
|
||||
Author [Alan Mishchenko]
|
||||
|
||||
Affiliation [UC Berkeley]
|
||||
|
||||
Date [Ver. 1.0. Started - Feburary 13, 2011.]
|
||||
|
||||
Revision [$Id: utilAigSim.c,v 1.00 2011/02/11 00:00:00 alanmi Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> // mkstemp(), close(), unlink()
|
||||
|
||||
#define AIGSIM_LIBRARY_ONLY
|
||||
|
||||
#ifdef AIGSIM_LIBRARY_ONLY
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// DECLARATIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ABC_ALLOC(type, n) ((type*)malloc((size_t)(n) * sizeof(type)))
|
||||
#define ABC_CALLOC(type, n) ((type*)calloc((size_t)(n), sizeof(type)))
|
||||
#define ABC_FREE(p) do { free(p); (p) = NULL; } while (0)
|
||||
|
||||
typedef struct AigNode_ { uint32_t f0, f1; } AigNode;
|
||||
typedef struct AigMan_ {
|
||||
AigNode *nodes;
|
||||
int nObjs, nCis, nAnds, nCos;
|
||||
} AigMan;
|
||||
|
||||
static inline int Aig_LitId(uint32_t lit) { return (int)(lit >> 1); }
|
||||
static inline int Aig_LitCompl(uint32_t lit) { return (int)(lit & 1u); }
|
||||
static inline uint32_t Aig_Lit(int id, int c) { return ((uint32_t)id << 1) | (uint32_t)(c & 1); }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static AigMan* Aig_ManStartCompact(int nCis, int nAnds, int nCos) {
|
||||
AigMan *p = ABC_CALLOC(AigMan, 1);
|
||||
p->nCis = nCis; p->nAnds = nAnds; p->nCos = nCos;
|
||||
p->nObjs = 1 + nCis + nAnds + nCos;
|
||||
p->nodes = ABC_CALLOC(AigNode, p->nObjs);
|
||||
return p;
|
||||
}
|
||||
static void Aig_ManStop(AigMan *p) { ABC_FREE(p->nodes); ABC_FREE(p); }
|
||||
|
||||
/* ---------------------- AIGER binary loader ----------------------- */
|
||||
/* Simple combinational (.aig) reader: header + O ASCII lines + A delta-encoded ANDs */
|
||||
|
||||
static int read_line(FILE *f, char *buf, size_t cap) {
|
||||
if (!fgets(buf, (int)cap, f)) return 0;
|
||||
size_t n = strlen(buf);
|
||||
while (n && (buf[n-1] == '\n' || buf[n-1] == '\r')) buf[--n] = 0;
|
||||
return 1;
|
||||
}
|
||||
static int parse_header(const char *s, unsigned *M, unsigned *I, unsigned *L, unsigned *O, unsigned *A) {
|
||||
if (strncmp(s, "aig ", 4) != 0) return 0;
|
||||
const char *p = s + 4;
|
||||
*M = (unsigned)strtoul(p, (char**)&p, 10);
|
||||
*I = (unsigned)strtoul(p, (char**)&p, 10);
|
||||
*L = (unsigned)strtoul(p, (char**)&p, 10);
|
||||
*O = (unsigned)strtoul(p, (char**)&p, 10);
|
||||
*A = (unsigned)strtoul(p, (char**)&p, 10);
|
||||
return 1;
|
||||
}
|
||||
static int read_ascii_uint_line(FILE *f, unsigned *out) {
|
||||
char buf[128]; if (!read_line(f, buf, sizeof(buf))) return 0;
|
||||
char *p = buf; while (*p && isspace((unsigned char)*p)) p++;
|
||||
*out = (unsigned)strtoul(p, NULL, 10);
|
||||
return 1;
|
||||
}
|
||||
static int read_uleb128(FILE *f, unsigned *out) {
|
||||
unsigned x = 0, shift = 0;
|
||||
for (;;) {
|
||||
int ch = fgetc(f); if (ch == EOF) return 0;
|
||||
x |= ((unsigned)(ch & 0x7F)) << shift;
|
||||
if (!(ch & 0x80)) break;
|
||||
shift += 7; if (shift > 28) return 0;
|
||||
}
|
||||
*out = x; return 1;
|
||||
}
|
||||
static AigMan* Aig_ManLoadAigerBinary(const char *filename, int verbose) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (!f) { fprintf(stderr, "Error: cannot open '%s'\n", filename); return NULL; }
|
||||
char hdr[256];
|
||||
if (!read_line(f, hdr, sizeof(hdr))) { fprintf(stderr, "Error: cannot read header\n"); fclose(f); return NULL; }
|
||||
unsigned M=0,I=0,L=0,O=0,A=0;
|
||||
if (!parse_header(hdr, &M,&I,&L,&O,&A)) { fprintf(stderr, "Error: bad header: %s\n", hdr); fclose(f); return NULL; }
|
||||
if (verbose) printf("[aiger] %s : M=%u I=%u L=%u O=%u A=%u\n", filename, M,I,L,O,A);
|
||||
if (L != 0) { fprintf(stderr, "Error: latches (L=%u) not supported.\n", L); fclose(f); return NULL; }
|
||||
|
||||
unsigned *outs = ABC_ALLOC(unsigned, O);
|
||||
for (unsigned i = 0; i < O; i++) if (!read_ascii_uint_line(f, &outs[i])) {
|
||||
fprintf(stderr, "Error: cannot read output literal %u\n", i); ABC_FREE(outs); fclose(f); return NULL;
|
||||
}
|
||||
|
||||
AigMan *p = Aig_ManStartCompact((int)I, (int)A, (int)O);
|
||||
|
||||
for (unsigned k = 0; k < A; k++) {
|
||||
unsigned lhs_var = I + k + 1;
|
||||
unsigned lhs_lit = lhs_var << 1;
|
||||
unsigned d1=0, d2=0;
|
||||
if (!read_uleb128(f, &d1) || !read_uleb128(f, &d2)) {
|
||||
fprintf(stderr, "Error: cannot decode AND gate %u\n", k);
|
||||
ABC_FREE(outs); Aig_ManStop(p); fclose(f); return NULL;
|
||||
}
|
||||
unsigned rhs0 = lhs_lit - d1;
|
||||
unsigned rhs1 = rhs0 - d2;
|
||||
p->nodes[(int)lhs_var].f0 = (uint32_t)rhs0;
|
||||
p->nodes[(int)lhs_var].f1 = (uint32_t)rhs1;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < O; i++) {
|
||||
int id = p->nCis + p->nAnds + 1 + (int)i; // CO objects at the end
|
||||
p->nodes[id].f0 = (uint32_t)outs[i];
|
||||
}
|
||||
|
||||
ABC_FREE(outs);
|
||||
fclose(f);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* ---------------------- sim helpers ---------------------- */
|
||||
|
||||
static inline uint64_t u64_mask_n(int nBits) {
|
||||
return (nBits >= 64) ? ~0ull : ((nBits <= 0) ? 0ull : ((1ull << nBits) - 1ull));
|
||||
}
|
||||
static void u128_to_dec(unsigned __int128 x, char *buf, size_t cap) {
|
||||
char tmp[64]; int n = 0;
|
||||
if (!x) { snprintf(buf, cap, "0"); return; }
|
||||
while (x && n < (int)sizeof(tmp)) { tmp[n++] = (char)('0' + (unsigned)(x % 10)); x /= 10; }
|
||||
int k = 0; while (n && k + 1 < (int)cap) buf[k++] = tmp[--n];
|
||||
buf[k] = 0;
|
||||
}
|
||||
|
||||
enum { NW = 64, BATCH = NW * 64 }; // 4096 patterns/round
|
||||
|
||||
static inline uint64_t SimLit(const uint64_t *S, uint32_t lit, int w) {
|
||||
uint64_t v = S[(size_t)Aig_LitId(lit) * NW + (size_t)w];
|
||||
return Aig_LitCompl(lit) ? ~v : v;
|
||||
}
|
||||
|
||||
static inline void SimulateOne(const AigMan *p, uint64_t *S) {
|
||||
const int firstAnd = p->nCis + 1;
|
||||
const int lastAnd = p->nCis + p->nAnds;
|
||||
for (int id = firstAnd; id <= lastAnd; ++id) {
|
||||
uint32_t f0 = p->nodes[id].f0, f1 = p->nodes[id].f1;
|
||||
size_t off = (size_t)id * NW;
|
||||
for (int w = 0; w < NW; ++w)
|
||||
S[off + (size_t)w] = SimLit(S, f0, w) & SimLit(S, f1, w);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------- mask string parser ---------------------- */
|
||||
/* maskStr grammar: sequence of tokens N or (N)
|
||||
N : N individual bits (each enumerated independently)
|
||||
(N) : N bits grouped together (enumerated as all-0 or all-1)
|
||||
Total widths must sum to nCis.
|
||||
Output: varMasks[0..nVars-1] (each is a bitmask of input bits controlled by that var).
|
||||
*/
|
||||
|
||||
static void PrintMaskSegmentsOneLine(const char *maskStr,
|
||||
const int *segS, const int *segW, const int *segG, int nSeg,
|
||||
int nVars, int nCis)
|
||||
{
|
||||
char buf[1024];
|
||||
int n = 0;
|
||||
n += snprintf(buf + n, sizeof(buf) - (size_t)n, "[mask] \"%s\" segs:", maskStr ? maskStr : "");
|
||||
for (int i = 0; i < nSeg; ++i) {
|
||||
int s = segS[i], e = s + segW[i] - 1;
|
||||
if (segG[i]) n += snprintf(buf + n, sizeof(buf) - (size_t)n, " (%d-%d)", s, e);
|
||||
else n += snprintf(buf + n, sizeof(buf) - (size_t)n, " %d-%d", s, e);
|
||||
}
|
||||
n += snprintf(buf + n, sizeof(buf) - (size_t)n, " vars=%d nCis=%d", nVars, nCis);
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
static int ParseMaskString(const char *maskStr, int nCis, uint64_t *varMasks, int *pnVars, int verbose) {
|
||||
if (!maskStr || !*maskStr) {
|
||||
for (int i = 0; i < nCis; ++i) varMasks[i] = 1ull << i;
|
||||
*pnVars = nCis;
|
||||
if (verbose) {
|
||||
int segS[1] = {0};
|
||||
int segW[1] = {nCis};
|
||||
int segG[1] = {0};
|
||||
PrintMaskSegmentsOneLine("default", segS, segW, segG, 1, *pnVars, nCis);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// For printing segments: each token becomes one segment
|
||||
int segS[128], segW[128], segG[128], nSeg = 0;
|
||||
|
||||
const char *p = maskStr;
|
||||
int off = 0, nVars = 0;
|
||||
|
||||
while (*p) {
|
||||
while (*p && isspace((unsigned char)*p)) p++;
|
||||
if (!*p) break;
|
||||
|
||||
int grouped = 0;
|
||||
if (*p == '(') { grouped = 1; p++; while (*p && isspace((unsigned char)*p)) p++; }
|
||||
|
||||
if (!isdigit((unsigned char)*p)) {
|
||||
fprintf(stderr, "Error: bad mask near '%s'\n", p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *end = NULL;
|
||||
long w = strtol(p, &end, 10);
|
||||
if (w <= 0 || w > 64) {
|
||||
fprintf(stderr, "Error: bad width %ld in mask\n", w);
|
||||
return 0;
|
||||
}
|
||||
p = end;
|
||||
|
||||
while (*p && isspace((unsigned char)*p)) p++;
|
||||
if (grouped) {
|
||||
if (*p != ')') { fprintf(stderr, "Error: missing ')' in mask\n"); return 0; }
|
||||
p++;
|
||||
}
|
||||
|
||||
if (off + (int)w > nCis) {
|
||||
fprintf(stderr, "Error: mask widths exceed nCis (%d)\n", nCis);
|
||||
return 0;
|
||||
}
|
||||
|
||||
segS[nSeg] = off;
|
||||
segW[nSeg] = (int)w;
|
||||
segG[nSeg] = grouped;
|
||||
nSeg++;
|
||||
|
||||
if (grouped) {
|
||||
uint64_t m = ((w == 64) ? ~0ull : (((1ull << (unsigned)w) - 1ull) << (unsigned)off));
|
||||
if (nVars >= 64) { fprintf(stderr, "Error: too many vars in mask\n"); return 0; }
|
||||
varMasks[nVars++] = m;
|
||||
} else {
|
||||
for (int t = 0; t < (int)w; ++t) {
|
||||
if (nVars >= 64) { fprintf(stderr, "Error: too many vars in mask\n"); return 0; }
|
||||
varMasks[nVars++] = 1ull << (unsigned)(off + t);
|
||||
}
|
||||
}
|
||||
off += (int)w;
|
||||
}
|
||||
|
||||
if (off != nCis) {
|
||||
fprintf(stderr, "Error: mask widths sum to %d but nCis=%d\n", off, nCis);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pnVars = nVars;
|
||||
if (verbose) PrintMaskSegmentsOneLine(maskStr, segS, segW, segG, nSeg, nVars, nCis);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---------------------- file/binary helpers ---------------------- */
|
||||
|
||||
static int ends_with(const char *s, const char *suf) {
|
||||
size_t ns = strlen(s), nf = strlen(suf);
|
||||
return (ns >= nf) && !strcmp(s + (ns - nf), suf);
|
||||
}
|
||||
|
||||
static int make_tmp_file(char *path, size_t cap, const char *prefix) {
|
||||
// Creates an existing temp file (for input)
|
||||
snprintf(path, cap, "/tmp/%sXXXXXX", prefix);
|
||||
int fd = mkstemp(path);
|
||||
if (fd < 0) return 0;
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int make_tmp_path_noexist(char *path, size_t cap, const char *prefix) {
|
||||
// Creates a unique temp path that does not exist (for output)
|
||||
snprintf(path, cap, "/tmp/%sXXXXXX", prefix);
|
||||
int fd = mkstemp(path);
|
||||
if (fd < 0) return 0;
|
||||
close(fd);
|
||||
unlink(path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int write_words(const char *fname, const uint64_t *data, size_t nWords) {
|
||||
FILE *f = fopen(fname, "wb");
|
||||
if (!f) return 0;
|
||||
size_t wr = fwrite(data, sizeof(uint64_t), nWords, f);
|
||||
fclose(f);
|
||||
return wr == nWords;
|
||||
}
|
||||
|
||||
static int read_words(const char *fname, uint64_t *data, size_t nWords) {
|
||||
FILE *f = fopen(fname, "rb");
|
||||
if (!f) return 0;
|
||||
size_t rd = fread(data, sizeof(uint64_t), nWords, f);
|
||||
fclose(f);
|
||||
return rd == nWords;
|
||||
}
|
||||
|
||||
/* ---------------------- compare: AIG vs AIG ---------------------- */
|
||||
|
||||
static int SimulateCompareAigAig(const AigMan *p1, const AigMan *p2,
|
||||
const uint64_t *varMasks, int nVars, int verbose)
|
||||
{
|
||||
if (p1->nCis != p2->nCis || p1->nCos != p2->nCos) {
|
||||
fprintf(stderr, "Error: interface mismatch: (I,O)=(%d,%d) vs (%d,%d)\n",
|
||||
p1->nCis, p1->nCos, p2->nCis, p2->nCos);
|
||||
return 0;
|
||||
}
|
||||
if (p1->nCis > 64 || p1->nCos > 64) {
|
||||
fprintf(stderr, "Error: supports nCis<=64 and nCos<=64 (got I=%d O=%d)\n", p1->nCis, p1->nCos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint64_t inMask = u64_mask_n(p1->nCis);
|
||||
const uint64_t outMask = u64_mask_n(p1->nCos);
|
||||
const unsigned __int128 combs = ((unsigned __int128)1) << (unsigned)nVars;
|
||||
|
||||
uint32_t *co1 = ABC_ALLOC(uint32_t, p1->nCos);
|
||||
uint32_t *co2 = ABC_ALLOC(uint32_t, p2->nCos);
|
||||
for (int o = 0; o < p1->nCos; ++o) {
|
||||
co1[o] = p1->nodes[p1->nCis + p1->nAnds + 1 + o].f0;
|
||||
co2[o] = p2->nodes[p2->nCis + p2->nAnds + 1 + o].f0;
|
||||
}
|
||||
|
||||
uint64_t *S1 = ABC_CALLOC(uint64_t, (size_t)p1->nObjs * NW);
|
||||
uint64_t *S2 = ABC_CALLOC(uint64_t, (size_t)p2->nObjs * NW);
|
||||
|
||||
uint64_t inVec[BATCH], valid[NW];
|
||||
unsigned long long rounds = 0;
|
||||
unsigned __int128 patsDone = 0;
|
||||
|
||||
clock_t t0 = clock();
|
||||
|
||||
for (unsigned __int128 base = 0; base < combs; base += BATCH) {
|
||||
unsigned __int128 remain = combs - base;
|
||||
int nThis = (remain < BATCH) ? (int)remain : BATCH;
|
||||
|
||||
int left = nThis;
|
||||
for (int w = 0; w < NW; ++w) {
|
||||
if (left >= 64) { valid[w] = ~0ull; left -= 64; }
|
||||
else if (left > 0) { valid[w] = ((left == 64) ? ~0ull : ((1ull << left) - 1ull)); left = 0; }
|
||||
else valid[w] = 0ull;
|
||||
}
|
||||
|
||||
// Clear CI words in both sims
|
||||
for (int i = 0; i < p1->nCis; ++i) {
|
||||
size_t off1 = (size_t)(1 + i) * NW;
|
||||
size_t off2 = (size_t)(1 + i) * NW;
|
||||
for (int w = 0; w < NW; ++w) S1[off1 + (size_t)w] = 0ull, S2[off2 + (size_t)w] = 0ull;
|
||||
}
|
||||
|
||||
// Fill CIs
|
||||
for (int ptn = 0; ptn < nThis; ++ptn) {
|
||||
uint64_t idx = (uint64_t)(base + (unsigned)ptn);
|
||||
uint64_t in = 0;
|
||||
for (int j = 0; j < nVars; ++j) if ((idx >> j) & 1ull) in |= varMasks[j];
|
||||
in &= inMask;
|
||||
inVec[ptn] = in;
|
||||
|
||||
int w = ptn >> 6;
|
||||
uint64_t bit = 1ull << (ptn & 63);
|
||||
uint64_t x = in;
|
||||
while (x) {
|
||||
int i = __builtin_ctzll(x);
|
||||
x &= x - 1;
|
||||
S1[(size_t)(1 + i) * NW + (size_t)w] |= bit;
|
||||
S2[(size_t)(1 + i) * NW + (size_t)w] |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate AIG #1 then AIG #2
|
||||
SimulateOne(p1, S1);
|
||||
SimulateOne(p2, S2);
|
||||
|
||||
// Compare COs
|
||||
for (int o = 0; o < p1->nCos; ++o) {
|
||||
for (int w = 0; w < NW; ++w) {
|
||||
uint64_t y1 = SimLit(S1, co1[o], w);
|
||||
uint64_t y2 = SimLit(S2, co2[o], w);
|
||||
uint64_t diff = (y1 ^ y2) & valid[w];
|
||||
if (!diff) continue;
|
||||
|
||||
int bit = __builtin_ctzll(diff);
|
||||
int ptn = (w << 6) | bit;
|
||||
|
||||
uint64_t out1 = 0, out2 = 0;
|
||||
for (int oo = 0; oo < p1->nCos; ++oo) {
|
||||
out1 |= ((SimLit(S1, co1[oo], w) >> bit) & 1ull) << oo;
|
||||
out2 |= ((SimLit(S2, co2[oo], w) >> bit) & 1ull) << oo;
|
||||
}
|
||||
|
||||
int inHex = (p1->nCis + 3) / 4;
|
||||
int outHex = (p1->nCos + 3) / 4;
|
||||
char gbuf[64]; u128_to_dec(patsDone + (unsigned)ptn, gbuf, sizeof(gbuf));
|
||||
|
||||
printf("FAIL pattern=%s out_bit=%d\n", gbuf, o);
|
||||
printf(" in = 0x%0*llx\n", inHex, (unsigned long long)(inVec[ptn] & inMask));
|
||||
printf(" y1 = 0x%0*llx\n", outHex, (unsigned long long)(out1 & outMask));
|
||||
printf(" y2 = 0x%0*llx\n", outHex, (unsigned long long)(out2 & outMask));
|
||||
|
||||
ABC_FREE(S1); ABC_FREE(S2); ABC_FREE(co1); ABC_FREE(co2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rounds++;
|
||||
patsDone += (unsigned)nThis;
|
||||
if (verbose && (rounds % 256ull) == 0ull) {
|
||||
char buf[64]; u128_to_dec(patsDone, buf, sizeof(buf));
|
||||
printf("[sim] rounds=%llu patterns=%s\n", rounds, buf);
|
||||
}
|
||||
}
|
||||
|
||||
clock_t t1 = clock();
|
||||
double sec = (double)(t1 - t0) / (double)CLOCKS_PER_SEC;
|
||||
|
||||
char totBuf[64]; u128_to_dec(combs, totBuf, sizeof(totBuf));
|
||||
printf("OK patterns=%s rounds=%llu time=%.3fs\n", totBuf, rounds, sec);
|
||||
|
||||
ABC_FREE(S1); ABC_FREE(S2); ABC_FREE(co1); ABC_FREE(co2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---------------------- compare: AIG vs external binary ---------------------- */
|
||||
|
||||
static int SimulateCompareAigBin(const AigMan *p1, const char *bin,
|
||||
const uint64_t *varMasks, int nVars, int verbose)
|
||||
{
|
||||
if (p1->nCis > 64 || p1->nCos > 64) {
|
||||
fprintf(stderr, "Error: supports nCis<=64 and nCos<=64 (got I=%d O=%d)\n", p1->nCis, p1->nCos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint64_t inMask = u64_mask_n(p1->nCis);
|
||||
const uint64_t outMask = u64_mask_n(p1->nCos);
|
||||
const unsigned __int128 combs = ((unsigned __int128)1) << (unsigned)nVars;
|
||||
|
||||
// Precompute AIG CO literals
|
||||
uint32_t *co1 = ABC_ALLOC(uint32_t, p1->nCos);
|
||||
for (int o = 0; o < p1->nCos; ++o)
|
||||
co1[o] = p1->nodes[p1->nCis + p1->nAnds + 1 + o].f0;
|
||||
|
||||
uint64_t *S1 = ABC_CALLOC(uint64_t, (size_t)p1->nObjs * NW);
|
||||
uint64_t *out2 = ABC_ALLOC(uint64_t, (size_t)p1->nCos * NW);
|
||||
|
||||
// Temp IO files for the binary
|
||||
char inFile[128], outFile[128], cmd[512];
|
||||
if (!make_tmp_file(inFile, sizeof(inFile), "aigsim_in_") ||
|
||||
!make_tmp_path_noexist(outFile, sizeof(outFile), "aigsim_out_")) {
|
||||
fprintf(stderr, "Error: cannot create temp files\n");
|
||||
ABC_FREE(S1); ABC_FREE(co1); ABC_FREE(out2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t inVec[BATCH], valid[NW];
|
||||
unsigned long long rounds = 0;
|
||||
unsigned __int128 patsDone = 0;
|
||||
|
||||
clock_t t0 = clock();
|
||||
|
||||
for (unsigned __int128 base = 0; base < combs; base += BATCH) {
|
||||
unsigned __int128 remain = combs - base;
|
||||
int nThis = (remain < BATCH) ? (int)remain : BATCH;
|
||||
|
||||
int left = nThis;
|
||||
for (int w = 0; w < NW; ++w) {
|
||||
if (left >= 64) { valid[w] = ~0ull; left -= 64; }
|
||||
else if (left > 0) { valid[w] = ((left == 64) ? ~0ull : ((1ull << left) - 1ull)); left = 0; }
|
||||
else valid[w] = 0ull;
|
||||
}
|
||||
|
||||
// Clear CI words
|
||||
for (int i = 0; i < p1->nCis; ++i) {
|
||||
size_t off = (size_t)(1 + i) * NW;
|
||||
for (int w = 0; w < NW; ++w) S1[off + (size_t)w] = 0ull;
|
||||
}
|
||||
|
||||
// Fill CIs for this batch
|
||||
for (int ptn = 0; ptn < nThis; ++ptn) {
|
||||
uint64_t idx = (uint64_t)(base + (unsigned)ptn);
|
||||
uint64_t in = 0;
|
||||
for (int j = 0; j < nVars; ++j) if ((idx >> j) & 1ull) in |= varMasks[j];
|
||||
in &= inMask;
|
||||
inVec[ptn] = in;
|
||||
|
||||
int w = ptn >> 6;
|
||||
uint64_t bit = 1ull << (ptn & 63);
|
||||
|
||||
uint64_t x = in;
|
||||
while (x) {
|
||||
int i = __builtin_ctzll(x);
|
||||
x &= x - 1;
|
||||
S1[(size_t)(1 + i) * NW + (size_t)w] |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate AIG
|
||||
SimulateOne(p1, S1);
|
||||
|
||||
// Write input sim-info file: nCis * NW words, CI major, word minor
|
||||
if (!write_words(inFile, &S1[1 * NW], (size_t)p1->nCis * NW)) {
|
||||
fprintf(stderr, "Error: cannot write %s\n", inFile);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Run external binary: "<bin> <inFile> <outFile>"
|
||||
remove(outFile);
|
||||
snprintf(cmd, sizeof(cmd), "%s %s %s", bin, inFile, outFile);
|
||||
int rc = system(cmd);
|
||||
if (rc != 0) {
|
||||
fprintf(stderr, "Error: system() failed (rc=%d): %s\n", rc, cmd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Read output sim-info file: nCos * NW words
|
||||
if (!read_words(outFile, out2, (size_t)p1->nCos * NW)) {
|
||||
fprintf(stderr, "Error: cannot read %s (expected %d*%d words)\n", outFile, p1->nCos, NW);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Compare AIG outputs vs binary outputs
|
||||
for (int o = 0; o < p1->nCos; ++o) {
|
||||
for (int w = 0; w < NW; ++w) {
|
||||
uint64_t y1 = SimLit(S1, co1[o], w);
|
||||
uint64_t y2 = out2[(size_t)o * NW + (size_t)w];
|
||||
uint64_t diff = (y1 ^ y2) & valid[w];
|
||||
if (!diff) continue;
|
||||
|
||||
int bit = __builtin_ctzll(diff);
|
||||
int ptn = (w << 6) | bit;
|
||||
|
||||
uint64_t out1 = 0, outB = 0;
|
||||
for (int oo = 0; oo < p1->nCos; ++oo) {
|
||||
out1 |= ((SimLit(S1, co1[oo], w) >> bit) & 1ull) << oo;
|
||||
outB |= ((out2[(size_t)oo * NW + (size_t)w] >> bit) & 1ull) << oo;
|
||||
}
|
||||
|
||||
int inHex = (p1->nCis + 3) / 4;
|
||||
int outHex = (p1->nCos + 3) / 4;
|
||||
char gbuf[64]; u128_to_dec(patsDone + (unsigned)ptn, gbuf, sizeof(gbuf));
|
||||
|
||||
printf("FAIL pattern=%s out_bit=%d\n", gbuf, o);
|
||||
printf(" in = 0x%0*llx\n", inHex, (unsigned long long)(inVec[ptn] & inMask));
|
||||
printf(" aig = 0x%0*llx\n", outHex, (unsigned long long)(out1 & outMask));
|
||||
printf(" bin = 0x%0*llx\n", outHex, (unsigned long long)(outB & outMask));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rounds++;
|
||||
patsDone += (unsigned)nThis;
|
||||
if (verbose && (rounds % 256ull) == 0ull) {
|
||||
char buf[64]; u128_to_dec(patsDone, buf, sizeof(buf));
|
||||
printf("[sim] rounds=%llu patterns=%s\n", rounds, buf);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
clock_t t1 = clock();
|
||||
double sec = (double)(t1 - t0) / (double)CLOCKS_PER_SEC;
|
||||
char totBuf[64]; u128_to_dec(combs, totBuf, sizeof(totBuf));
|
||||
printf("OK patterns=%s rounds=%llu time=%.3fs\n", totBuf, rounds, sec);
|
||||
}
|
||||
|
||||
remove(inFile);
|
||||
remove(outFile);
|
||||
ABC_FREE(S1); ABC_FREE(co1); ABC_FREE(out2);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
remove(inFile);
|
||||
remove(outFile);
|
||||
ABC_FREE(S1); ABC_FREE(co1); ABC_FREE(out2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ---------------------- top API ---------------------- */
|
||||
|
||||
int SimulateAigTop( char *fname1, char *fname2, char *mask, int verbose )
|
||||
{
|
||||
AigMan *p1 = Aig_ManLoadAigerBinary(fname1, verbose);
|
||||
if (!p1) return 2;
|
||||
|
||||
uint64_t varMasks[64];
|
||||
int nVars = 0;
|
||||
if (!ParseMaskString(mask, p1->nCis, varMasks, &nVars, verbose)) {
|
||||
Aig_ManStop(p1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ok = 0;
|
||||
|
||||
if (ends_with(fname2, ".aig")) {
|
||||
AigMan *p2 = Aig_ManLoadAigerBinary(fname2, verbose);
|
||||
if (!p2) { Aig_ManStop(p1); return 2; }
|
||||
ok = SimulateCompareAigAig(p1, p2, varMasks, nVars, verbose);
|
||||
Aig_ManStop(p2);
|
||||
} else {
|
||||
// fname2 is an external binary: bin <inFile> <outFile>
|
||||
ok = SimulateCompareAigBin(p1, fname2, varMasks, nVars, verbose);
|
||||
}
|
||||
|
||||
Aig_ManStop(p1);
|
||||
return ok ? 0 : 3;
|
||||
}
|
||||
|
||||
/* ---------------------- main ---------------------- */
|
||||
/* Usage:
|
||||
./aig_equiv_2aigs [-v] file1.aig file2.aig_or_binary [mask_str]
|
||||
|
||||
mask_str example for 16 inputs:
|
||||
"2(4)10" -> 2 individual bits, then 4 grouped bits (all-0/all-1), then 10 individual bits
|
||||
*/
|
||||
#ifndef AIGSIM_LIBRARY_ONLY
|
||||
int main(int argc, char **argv) {
|
||||
int verbose = 0;
|
||||
const char *f1 = NULL, *f2 = NULL;
|
||||
const char *mask = NULL;
|
||||
|
||||
int ai = 1;
|
||||
if (ai < argc && !strcmp(argv[ai], "-v")) { verbose = 1; ai++; }
|
||||
if (ai + 1 >= argc) {
|
||||
fprintf(stderr, "Usage: %s [-v] file1.aig file2.aig_or_binary [mask_str]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
f1 = argv[ai++];
|
||||
f2 = argv[ai++];
|
||||
if (ai < argc) mask = argv[ai++];
|
||||
|
||||
return SimulateAigTop((char*)f1, (char*)f2, (char*)mask, verbose);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef AIGSIM_LIBRARY_ONLY
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -183,6 +183,8 @@ static inline void Xdbl_Test()
|
|||
xdbl ten100_ = ABC_CONST(0x014c924d692ca61b);
|
||||
|
||||
assert( ten100 == ten100_ );
|
||||
(void)ten100;
|
||||
(void)ten100_;
|
||||
|
||||
// float f1 = Xdbl_ToDouble(c1);
|
||||
// Extra_PrintBinary( stdout, (int *)&c1, 32 ); printf( "\n" );
|
||||
|
|
|
|||
|
|
@ -1595,6 +1595,7 @@ static inline int Abc_TtReadBin( word * pWords, int nWords, char * pString )
|
|||
{
|
||||
int i, Len = (int)strlen(pString), nWords2 = (Len+63)/64;
|
||||
assert( nWords2 <= nWords );
|
||||
(void)nWords2;
|
||||
memset( pWords, 0, sizeof(word)*nWords );
|
||||
for ( i = 0; i < Len; i++ )
|
||||
if ( pString[i] == '1' )
|
||||
|
|
@ -1608,6 +1609,7 @@ static inline word Abc_TtReadBin64( char * pString )
|
|||
word Word = 0;
|
||||
int Len = (int)strlen(pString);
|
||||
assert( Len <= 64 );
|
||||
(void)Len;
|
||||
int Res = Abc_TtReadBin( &Word, 1, pString );
|
||||
if ( Res == 0 ) {
|
||||
printf( "Reading binary string \"%s\" has failed.\n", pString );
|
||||
|
|
@ -1842,6 +1844,7 @@ static inline int Abc_TtCheckCondDep( word * pTruth, int nVars, int nSuppLim )
|
|||
word Cof0[128], Cof1[128]; // pow( 2, nVarsMax-6 )
|
||||
int v, d, nWords = Abc_TtWordNum(nVars);
|
||||
assert( nVars <= nVarsMax );
|
||||
(void)nVarsMax;
|
||||
if ( nVars <= nSuppLim + 1 )
|
||||
return 0;
|
||||
for ( v = 0; v < nVars; v++ )
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ static inline void Vec_MemDumpTruthTables( Vec_Mem_t * p, char * pName, int nLut
|
|||
{
|
||||
FILE * pFile;
|
||||
char pFileName[1000];
|
||||
sprintf( pFileName, "tt_%s_%02d.txt", pName ? pName : NULL, nLutSize );
|
||||
snprintf( pFileName, sizeof(pFileName), "tt_%s_%02d.txt", pName ? pName : "", nLutSize );
|
||||
pFile = pName ? fopen( pFileName, "wb" ) : stdout;
|
||||
Vec_MemDump( pFile, p );
|
||||
if ( pFile != stdout )
|
||||
|
|
@ -475,4 +475,3 @@ ABC_NAMESPACE_HEADER_END
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -907,6 +907,244 @@ pPars->timeSynth = Abc_Clock() - clk;
|
|||
return pMan;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis [Reproduces script "resyn2".]
|
||||
|
||||
Description [Equivalent to: b; rw; rf; b; rw; rwz; b; rfz; rwz; b.]
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
Gia_Man_t * Gia_ManResyn3( Gia_Man_t * pGia, int fVerbose )
|
||||
{
|
||||
Gia_Man_t * pGiaRes;
|
||||
Aig_Man_t * pAig, * pTemp;
|
||||
Dar_RwrPar_t ParsRwr, * pParsRwr = &ParsRwr;
|
||||
Dar_RefPar_t ParsRef, * pParsRef = &ParsRef;
|
||||
int fUpdateLevel = 1;
|
||||
|
||||
if ( pGia->pManTime && pGia->vLevels == NULL )
|
||||
Gia_ManLevelWithBoxes( pGia );
|
||||
|
||||
Dar_ManDefaultRwrParams( pParsRwr );
|
||||
Dar_ManDefaultRefParams( pParsRef );
|
||||
pParsRwr->nCutsMax = 250;
|
||||
pParsRef->nLeafMax = 10;
|
||||
pParsRef->nMffcMin = 1;
|
||||
pParsRwr->fUpdateLevel = fUpdateLevel;
|
||||
pParsRef->fUpdateLevel = fUpdateLevel;
|
||||
pParsRwr->fVerbose = 0;
|
||||
pParsRef->fVerbose = 0;
|
||||
|
||||
pAig = Gia_ManToAig( pGia, 0 );
|
||||
if ( fVerbose ) printf( "Starting: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rw
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Rewrite: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rf
|
||||
Dar_ManRefactor( pAig, pParsRef );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Refactor: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rw
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Rewrite: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rwz
|
||||
pParsRwr->fUseZeros = 1;
|
||||
pParsRef->fUseZeros = 1;
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RewriteZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rfz
|
||||
Dar_ManRefactor( pAig, pParsRef );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RefactorZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rwz
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RewriteZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
pGiaRes = Gia_ManFromAig( pAig );
|
||||
Aig_ManStop( pAig );
|
||||
Gia_ManTransferTiming( pGiaRes, pGia );
|
||||
return pGiaRes;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis [Reproduces script "compress2rs".]
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
Gia_Man_t * Gia_ManCompress3rs( Gia_Man_t * pGia, int fUpdateLevel, int fVerbose )
|
||||
{
|
||||
Gia_Man_t * pGiaRes;
|
||||
Aig_Man_t * pAig, * pTemp;
|
||||
Dar_RwrPar_t ParsRwr, * pParsRwr = &ParsRwr;
|
||||
Dar_RefPar_t ParsRef, * pParsRef = &ParsRef;
|
||||
extern Aig_Man_t * Dar_ManResub( Aig_Man_t * pAig, int nCutsMax, int nNodesMax, int fUpdateLevel, int fUseZeros, int fVerbose );
|
||||
|
||||
if ( pGia->pManTime && pGia->vLevels == NULL )
|
||||
Gia_ManLevelWithBoxes( pGia );
|
||||
|
||||
Dar_ManDefaultRwrParams( pParsRwr );
|
||||
Dar_ManDefaultRefParams( pParsRef );
|
||||
pParsRwr->nCutsMax = 250;
|
||||
pParsRef->nLeafMax = 10;
|
||||
pParsRef->nMffcMin = 1;
|
||||
pParsRwr->fUpdateLevel = fUpdateLevel;
|
||||
pParsRef->fUpdateLevel = fUpdateLevel;
|
||||
pParsRwr->fVerbose = 0;
|
||||
pParsRef->fVerbose = 0;
|
||||
|
||||
pAig = Gia_ManToAig( pGia, 0 );
|
||||
if ( fVerbose ) printf( "Starting: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b -l
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 6 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 6, 1, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub6: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rw -l
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Rewrite: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 6 -N 2 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 6, 2, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub6x2: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rf -l
|
||||
Dar_ManRefactor( pAig, pParsRef );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Refactor: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 8 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 8, 1, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub8: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b -l
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 8 -N 2 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 8, 2, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub8x2: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rw -l
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Rewrite: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 10 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 10, 1, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub10: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rwz -l
|
||||
pParsRwr->fUseZeros = 1;
|
||||
pParsRef->fUseZeros = 1;
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RewriteZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 10 -N 2 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 10, 2, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub10x2: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b -l
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 12 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 12, 1, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub12: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rfz -l
|
||||
Dar_ManRefactor( pAig, pParsRef );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RefactorZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rs -K 12 -N 2 -l
|
||||
pAig = Dar_ManResub( pTemp = pAig, 12, 2, fUpdateLevel, 0, 0 );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Resub12x2: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// rwz -l
|
||||
Dar_ManRewrite( pAig, pParsRwr );
|
||||
pAig = Aig_ManDupDfs( pTemp = pAig );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "RewriteZ: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
// b -l
|
||||
pAig = Dar_ManBalance( pTemp = pAig, fUpdateLevel );
|
||||
Aig_ManStop( pTemp );
|
||||
if ( fVerbose ) printf( "Balance: " ), Aig_ManPrintStats( pAig );
|
||||
|
||||
pGiaRes = Gia_ManFromAig( pAig );
|
||||
Aig_ManStop( pAig );
|
||||
Gia_ManTransferTiming( pGiaRes, pGia );
|
||||
return pGiaRes;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
|
|
@ -914,4 +1152,3 @@ pPars->timeSynth = Abc_Clock() - clk;
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ inline void Miaig::release(void) {
|
|||
if (_data->pRequire) free(_data->pRequire);
|
||||
if (_data->pTable) free(_data->pTable);
|
||||
if (_data->pNtkMapped) Vi_Free(_data->pNtkMapped);
|
||||
delete _data;
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -612,4 +612,4 @@ inline void Miaig::attachTiming(vi *vCiArrs, vi *vCoReqs) {
|
|||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
#endif // RW_ABC
|
||||
|
||||
#endif // REWIRE_MIAIG_H
|
||||
#endif // REWIRE_MIAIG_H
|
||||
|
|
|
|||
|
|
@ -111,8 +111,10 @@ int Sfm_TruthToCnf( word Truth, word * pTruth, int nVars, Vec_Int_t * vCover, Ve
|
|||
int i, k, c, RetValue, Literal, Cube, nCubes = 0;
|
||||
assert( nVars > 0 );
|
||||
|
||||
Abc_TtFlipVar5( &Truth, nVars );
|
||||
Abc_TtFlipVar5( pTruth, nVars );
|
||||
if ( nVars <= 6)
|
||||
Abc_TtFlipVar5( &Truth, nVars );
|
||||
else
|
||||
Abc_TtFlipVar5( pTruth, nVars );
|
||||
for ( c = 0; c < 2; c ++ )
|
||||
{
|
||||
if ( nVars <= 6 )
|
||||
|
|
@ -148,7 +150,8 @@ int Sfm_TruthToCnf( word Truth, word * pTruth, int nVars, Vec_Int_t * vCover, Ve
|
|||
Vec_StrPush( vCnf, (char)-1 );
|
||||
}
|
||||
}
|
||||
Abc_TtFlipVar5( pTruth, nVars );
|
||||
if (nVars > 6)
|
||||
Abc_TtFlipVar5( pTruth, nVars );
|
||||
|
||||
return nCubes;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* UifCmd.cpp
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <climits>
|
||||
#include <regex>
|
||||
|
||||
#include "base/wlc/wlc.h"
|
||||
#include "opt/ufar/UfarCmd.h"
|
||||
#include "opt/ufar/UfarMgr.h"
|
||||
#include "opt/untk/NtkNtk.h"
|
||||
#include "opt/util/util.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
using namespace std;
|
||||
|
||||
static UFAR::UfarManager ufar_manager;
|
||||
|
||||
static int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAnalyzeCex( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandCreateAbstraction( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandCreateMiter( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
||||
static inline Wlc_Ntk_t * Wlc_AbcGetNtk( Abc_Frame_t * pAbc ) { return (Wlc_Ntk_t *)pAbc->pAbcWlc; }
|
||||
static inline void Wlc_AbcFreeNtk( Abc_Frame_t * pAbc ) { if ( pAbc->pAbcWlc ) Wlc_NtkFree(Wlc_AbcGetNtk(pAbc)); }
|
||||
static inline void Wlc_AbcUpdateNtk( Abc_Frame_t * pAbc, Wlc_Ntk_t * pNtk ) { Wlc_AbcFreeNtk(pAbc); pAbc->pAbcWlc = pNtk; }
|
||||
|
||||
|
||||
void Ufar_Init(Abc_Frame_t *pAbc)
|
||||
{
|
||||
//Cmd_CommandAdd( pAbc, "Word level Prove", "%%test", Abc_CommandTest, 0 );
|
||||
//Cmd_CommandAdd( pAbc, "Word level Prove", "%%cex", Abc_CommandAnalyzeCex, 0 );
|
||||
//Cmd_CommandAdd( pAbc, "Word level Prove", "%%abs", Abc_CommandCreateAbstraction, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%ufar", Abc_CommandProveUsingUif, 0 );
|
||||
//Cmd_CommandAdd( pAbc, "Word level Prove", "%%miter", Abc_CommandCreateMiter, 0 );
|
||||
}
|
||||
|
||||
static int Abc_CommandCreateMiter( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
Wlc_Ntk_t * pNew = UFAR::CreateMiter(Wlc_AbcGetNtk(pAbc), 0);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Abc_CommandCreateAbstraction( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
Wlc_Ntk_t * pNew = ufar_manager.BuildCurrentAbstraction();
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Abc_CommandAnalyzeCex( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
if ( pAbc->pCex == NULL )
|
||||
{
|
||||
cout << "There is no CEX.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ufar_manager.GetOperatorsInCex(pAbc->pCex);
|
||||
ufar_manager.FindUifPairsUsingCex(pAbc->pCex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Abc_CommandProveUsingUif( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
if (Wlc_AbcGetNtk(pAbc) == NULL) {
|
||||
cout << "There is no current design.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
OptMgr opt_mgr(argv[0]);
|
||||
opt_mgr.AddOpt("--norm", ufar_manager.params.fNorm ? "yes" : "no", "", "toggle using data type normalization");
|
||||
opt_mgr.AddOpt("--adder", "no", "", "toggle including adders");
|
||||
opt_mgr.AddOpt("--cexmin", ufar_manager.params.fCexMin ? "yes" : "no", "", "toggle using CEX minimization");
|
||||
opt_mgr.AddOpt("--sim", "none", "str", "use simulation and specify its setting");
|
||||
opt_mgr.AddOpt("-v", to_string(ufar_manager.params.iVerbosity), "num", "specify verbosity level");
|
||||
opt_mgr.AddOpt("--seq", to_string(ufar_manager.params.nSeqLookBack), "num", "specify the number of look-back frames (0 = no sequential UIF)");
|
||||
opt_mgr.AddOpt("--profile", "no", "", "dump time distribution");
|
||||
opt_mgr.AddOpt("--pba_uif", ufar_manager.params.fPbaUif ? "yes" : "no", "", "toggle using proof-based refinement for UIF pairs");
|
||||
opt_mgr.AddOpt("--lazysim", ufar_manager.params.fLazySim ? "yes" : "no", "", "toggle applying UIF pairs based on simulation");
|
||||
opt_mgr.AddOpt("--pbasim", ufar_manager.params.fPbaSim ? "yes" : "no", "", "toggle combining pba and sim");
|
||||
opt_mgr.AddOpt("--pbacex", ufar_manager.params.fPbaCex ? "yes" : "no", "", "toggle combining pba and cex");
|
||||
opt_mgr.AddOpt("--satmin", ufar_manager.params.fSatMin ? "yes" : "no", "", "toggle using sat-min in pba");
|
||||
opt_mgr.AddOpt("--cbawb", ufar_manager.params.fCbaWb ? "yes" : "no", "", "toggle using cex-based refinement for white boxing");
|
||||
opt_mgr.AddOpt("--grey", ufar_manager.params.fGrey ? "yes" : "no", "", "toggle using grey-box constraints");
|
||||
opt_mgr.AddOpt("--grey2", to_string(ufar_manager.params.nGrey), "float", "specify the greyness threshold");
|
||||
opt_mgr.AddOpt("--dump", "none", "str", "specify file name");
|
||||
opt_mgr.AddOpt("--dump-abs", "none", "str", "specify file name");
|
||||
opt_mgr.AddOpt("--par", "none", "str", "use parallel solvers");
|
||||
opt_mgr.AddOpt("--dump_states", "none", "str", "specify the name for the states file");
|
||||
opt_mgr.AddOpt("--read_states", "none", "str", "specify the name for the states file");
|
||||
opt_mgr.AddOpt("--sp", ufar_manager.params.fSuper_prove ? "yes" : "no", "", "toggle using super_prove");
|
||||
opt_mgr.AddOpt("--simp", ufar_manager.params.fSimple ? "yes" : "no", "", "toggle using simple (prove)");
|
||||
opt_mgr.AddOpt("--syn", ufar_manager.params.fSyn ? "yes" : "no", "", "toggle using simple synthesis");
|
||||
opt_mgr.AddOpt("--pth", ufar_manager.params.fPthread ? "yes" : "no", "", "toggle using pthreads");
|
||||
opt_mgr.AddOpt("--onewb", to_string(ufar_manager.params.iOneWb), "int", "specify the mode for one-white-boxing");
|
||||
opt_mgr.AddOpt("--timeout", to_string(ufar_manager.params.nTimeout), "num", "specify the timeout (sec)");
|
||||
opt_mgr.AddOpt("--exp", to_string(ufar_manager.params.iExp), "int", "specify the exp mode");
|
||||
opt_mgr.AddOpt("--miter", "yes", "", "toggle mitering the problem");
|
||||
opt_mgr.AddOpt("--under", "-1", "num", "try under-approximation with the given size");
|
||||
if(!opt_mgr.Parse(argc, argv)) {
|
||||
opt_mgr.PrintUsage();
|
||||
cout << "\n This command was developed by Yen-Sheng Ho at UC Berkeley in 2015.\n";
|
||||
cout << " https://people.eecs.berkeley.edu/~alanmi/publications/2016/fmcad16_uif.pdf \n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(opt_mgr["--norm"])
|
||||
ufar_manager.params.fNorm ^= 1;
|
||||
if(opt_mgr["--cexmin"])
|
||||
ufar_manager.params.fCexMin ^= 1;
|
||||
if(opt_mgr["--pba_uif"])
|
||||
ufar_manager.params.fPbaUif ^= 1;
|
||||
if(opt_mgr["--pbasim"])
|
||||
ufar_manager.params.fPbaSim ^= 1;
|
||||
if(opt_mgr["--pbacex"])
|
||||
ufar_manager.params.fPbaCex ^= 1;
|
||||
if(opt_mgr["--satmin"])
|
||||
ufar_manager.params.fSatMin ^= 1;
|
||||
if(opt_mgr["--cbawb"])
|
||||
ufar_manager.params.fCbaWb ^= 1;
|
||||
if(opt_mgr["--grey"])
|
||||
ufar_manager.params.fGrey ^= 1;
|
||||
if(opt_mgr["--grey2"])
|
||||
ufar_manager.params.nGrey = stof(opt_mgr.GetOptVal("--grey2"));
|
||||
if(opt_mgr["--sp"])
|
||||
ufar_manager.params.fSuper_prove ^= 1;
|
||||
if(opt_mgr["--simp"])
|
||||
ufar_manager.params.fSimple ^= 1;
|
||||
if(opt_mgr["--syn"])
|
||||
ufar_manager.params.fSyn ^= 1;
|
||||
if(opt_mgr["--pth"])
|
||||
ufar_manager.params.fPthread ^= 1;
|
||||
if(opt_mgr["--onewb"])
|
||||
ufar_manager.params.iOneWb = stoi(opt_mgr.GetOptVal("--onewb"));
|
||||
if(opt_mgr["--exp"])
|
||||
ufar_manager.params.iExp = stoi(opt_mgr.GetOptVal("--exp"));
|
||||
if(opt_mgr["--par"])
|
||||
ufar_manager.params.parSetting = opt_mgr.GetOptVal("--par");
|
||||
if(opt_mgr["--sim"])
|
||||
ufar_manager.params.simSetting = opt_mgr.GetOptVal("--sim");
|
||||
if(opt_mgr["--dump_states"]) {
|
||||
smatch sub_match;
|
||||
string option = opt_mgr.GetOptVal("--dump_states");
|
||||
if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)")))
|
||||
ufar_manager.params.fileStatesOut = sub_match[1].str();
|
||||
else
|
||||
ufar_manager.params.fileStatesOut = opt_mgr.GetOptVal("--dump_states");
|
||||
}
|
||||
if(opt_mgr["--read_states"])
|
||||
ufar_manager.params.fileStatesIn = opt_mgr.GetOptVal("--read_states");
|
||||
if(opt_mgr["--lazysim"])
|
||||
ufar_manager.params.fLazySim ^= 1;
|
||||
if(opt_mgr["-v"])
|
||||
ufar_manager.params.iVerbosity = stoi(opt_mgr.GetOptVal("-v"));
|
||||
if(opt_mgr["--timeout"])
|
||||
ufar_manager.params.nTimeout = stoi(opt_mgr.GetOptVal("--timeout"));
|
||||
if(opt_mgr["--seq"])
|
||||
ufar_manager.params.nSeqLookBack = stoi(opt_mgr.GetOptVal("--seq"));
|
||||
if(opt_mgr["--dump-abs"]) {
|
||||
smatch sub_match;
|
||||
string option = opt_mgr.GetOptVal("--dump-abs");
|
||||
if(regex_search(option, sub_match, regex(R"(/?(\w+)\.v$)")))
|
||||
ufar_manager.params.fileAbs = sub_match[1].str();
|
||||
else
|
||||
ufar_manager.params.fileAbs = opt_mgr.GetOptVal("--dump");
|
||||
}
|
||||
if(opt_mgr["--dump"]) {
|
||||
smatch sub_match;
|
||||
string option = opt_mgr.GetOptVal("--dump");
|
||||
if(regex_search(option, sub_match, regex(R"(/?(\w+\.v)$)")))
|
||||
ufar_manager.params.fileName = sub_match[1].str();
|
||||
else
|
||||
ufar_manager.params.fileName = opt_mgr.GetOptVal("--dump");
|
||||
}
|
||||
|
||||
// ufar_manager.DumpParams();
|
||||
LogT::prefix = "UIF_PROVE";
|
||||
|
||||
set<unsigned> set_op_types;
|
||||
set_op_types.insert(WLC_OBJ_ARI_MULTI);
|
||||
if (opt_mgr["--adder"])
|
||||
set_op_types.insert(WLC_OBJ_ARI_ADD);
|
||||
if (!UFAR::HasOperator(Wlc_AbcGetNtk(pAbc), set_op_types)) {
|
||||
cout << "There is no operator for UIF.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Wlc_Ntk_t * pNew = NULL;
|
||||
timeval t1, t2;
|
||||
gettimeofday(&t1, NULL);
|
||||
|
||||
if (!opt_mgr["--miter"]) {
|
||||
if (Wlc_NtkPoNum(Wlc_AbcGetNtk(pAbc)) != 2) {
|
||||
cout << "The current design doesn't have dual outputs.\n";
|
||||
return 0;
|
||||
}
|
||||
pNew = UFAR::CreateMiter(Wlc_AbcGetNtk(pAbc), 0);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
}
|
||||
|
||||
if (ufar_manager.params.fNorm) {
|
||||
pNew = UFAR::NormalizeDataTypes(Wlc_AbcGetNtk(pAbc), set_op_types, true);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
}
|
||||
|
||||
if (opt_mgr["--under"]) {
|
||||
pNew = UFAR::MakeUnderApprox(Wlc_AbcGetNtk(pAbc), stoi(opt_mgr.GetOptVal("--under")));
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
pNew = UFAR::MakeUnderApprox2(Wlc_AbcGetNtk(pAbc), set_op_types, stoi(opt_mgr.GetOptVal("--under")));
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
Wlc_WriteVer(Wlc_AbcGetNtk(pAbc), "UND.v", 0, 0);
|
||||
}
|
||||
|
||||
Gia_Man_t * pGia = UFAR::BitBlast(Wlc_AbcGetNtk(pAbc));
|
||||
Gia_ManPrintStats( pGia, NULL );
|
||||
Gia_ManStop( pGia );
|
||||
|
||||
ufar_manager.Initialize(Wlc_AbcGetNtk(pAbc), set_op_types);
|
||||
|
||||
int ret = ufar_manager.PerformUIFProve(t1);
|
||||
if (ret == 1) {
|
||||
LOG(0) << "Proved by UIF (UNSAT).";
|
||||
} else if (ret == 0) {
|
||||
LOG(0) << "Falsified by UIF (SAT).";
|
||||
} else {
|
||||
LOG(0) << "Undecided by UIF.";
|
||||
}
|
||||
|
||||
gettimeofday(&t2, NULL);
|
||||
unsigned tTotal = elapsed_time_usec(t1, t2);
|
||||
if(opt_mgr["--profile"]) {
|
||||
auto log_profile = [&](const string& str, abctime t) {
|
||||
LOG(1) << str << " time = " << fixed << setprecision(4) << setw(8) << (double)t/1000000 << " sec [" << setw(7) << (double)t/tTotal*100 << "%]";
|
||||
};
|
||||
log_profile("BLSolver ", ufar_manager.profile.tBLSolver);
|
||||
log_profile("UifRefine ", ufar_manager.profile.tUifRefine);
|
||||
log_profile("WbRefine ", ufar_manager.profile.tWbRefine);
|
||||
log_profile("UifSim ", ufar_manager.profile.tUifSim);
|
||||
log_profile("GbRefine ", ufar_manager.profile.tGbRefine);
|
||||
}
|
||||
|
||||
LOG(0) << "Time = " << setprecision(5) << ((double) (tTotal) / 1000000) << " sec";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Abc_CommandTest( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
LogT::prefix = "TEST::";
|
||||
OptMgr opt_mgr(argv[0]);
|
||||
opt_mgr.AddOpt("--ntk", "none", "str", "specify the file name (*.aig) for the input network");
|
||||
opt_mgr.AddOpt("--adder", "no", "", "toggle including adders");
|
||||
if(!opt_mgr.Parse(argc, argv)) {
|
||||
opt_mgr.PrintUsage();
|
||||
return 0;
|
||||
}
|
||||
set<unsigned> set_op_types;
|
||||
set_op_types.insert(WLC_OBJ_ARI_MULTI);
|
||||
if(opt_mgr["--adder"]) {
|
||||
set_op_types.insert(WLC_OBJ_ARI_ADD);
|
||||
}
|
||||
Wlc_Ntk_t * pNew = UFAR::AddConstFlops(Wlc_AbcGetNtk(pAbc), set_op_types);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
opt_mgr.AddOpt("--ntk", "none", "str", "specify the file name (*.aig) for the input network");
|
||||
opt_mgr.AddOpt("--inv", "none", "str", "specify the file name (*.pla) for the invariant");
|
||||
if(!opt_mgr.Parse(argc, argv)) {
|
||||
opt_mgr.PrintUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
string nameNtk = opt_mgr.GetOptVal("--ntk");
|
||||
string nameInv = opt_mgr.GetOptVal("--inv");
|
||||
UFAR::TestInvariant(nameNtk, nameInv);
|
||||
#endif
|
||||
#if 0
|
||||
set<unsigned> set_op_types;
|
||||
set_op_types.insert(WLC_OBJ_ARI_MULTI);
|
||||
|
||||
OptMgr opt_mgr(argv[0]);
|
||||
opt_mgr.AddOpt("--cube", "no", "", "toggle using cubes for interpolants");
|
||||
if(!opt_mgr.Parse(argc, argv)) {
|
||||
opt_mgr.PrintUsage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
UFAR::TestITP(Wlc_AbcGetNtk(pAbc), set_op_types, opt_mgr["--cube"]);
|
||||
#endif
|
||||
#if 0
|
||||
if ( Wlc_AbcGetNtk(pAbc) == NULL ) {
|
||||
cout << "There is no current design.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Wlc_NtkPoNum(Wlc_AbcGetNtk(pAbc)) != 2) {
|
||||
cout << "The current design doesn't have dual outputs.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
set<unsigned> set_op_types;
|
||||
set_op_types.insert(WLC_OBJ_ARI_MULTI);
|
||||
if (!UFAR::HasOperator(Wlc_AbcGetNtk(pAbc), set_op_types)) {
|
||||
cout << "There is no operator for UIF.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Wlc_Ntk_t * pNew = NULL;
|
||||
|
||||
pNew = UFAR::CreateMiter(Wlc_AbcGetNtk(pAbc), 0);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
|
||||
pNew = UFAR::NormalizeDataTypes(Wlc_AbcGetNtk(pAbc), set_op_types, true);
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
|
||||
ufar_manager.Initialize(Wlc_AbcGetNtk(pAbc), set_op_types);
|
||||
ufar_manager.DumpMgrInfo();
|
||||
|
||||
pNew = ufar_manager.BuildCurrentAbstraction();
|
||||
Wlc_AbcUpdateNtk(pAbc, pNew);
|
||||
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* UifCmd.h
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#ifndef SRC_EXT2_UIF_UIFCMD_H_
|
||||
#define SRC_EXT2_UIF_UIFCMD_H_
|
||||
|
||||
#include "base/main/mainInt.h"
|
||||
|
||||
ABC_NAMESPACE_HEADER_START
|
||||
|
||||
void Ufar_Init(Abc_Frame_t *pAbc);
|
||||
|
||||
ABC_NAMESPACE_HEADER_END
|
||||
|
||||
#endif /* SRC_EXT2_UIF_UIFCMD_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* UifMgr.h
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#ifndef SRC_EXT2_UIF_UIFMGR_H_
|
||||
#define SRC_EXT2_UIF_UIFMGR_H_
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
typedef struct Wlc_Ntk_t_ Wlc_Ntk_t;
|
||||
typedef struct Abc_Cex_t_ Abc_Cex_t;
|
||||
typedef struct Gia_Man_t_ Gia_Man_t;
|
||||
|
||||
namespace UFAR {
|
||||
|
||||
using VecVecInt = std::vector<std::vector<int> >;
|
||||
using VecVecStr = std::vector<std::vector<std::string> >;
|
||||
using VecChar = std::vector<char>;
|
||||
using VecStr = std::vector<std::string>;
|
||||
using IntPair = std::pair<int, int>;
|
||||
|
||||
struct OperatorID;
|
||||
struct UifPair;
|
||||
class Greyness;
|
||||
using UIF_PAIR = UifPair;
|
||||
|
||||
class SimUifPairFinder;
|
||||
class CexUifPairFinder;
|
||||
|
||||
class UfarManager {
|
||||
public:
|
||||
struct Params {
|
||||
Params();
|
||||
bool fCexMin;
|
||||
bool fPbaUif;
|
||||
bool fLazySim;
|
||||
bool fPbaSim;
|
||||
bool fPbaCex;
|
||||
bool fSatMin;
|
||||
bool fCbaWb;
|
||||
bool fGrey;
|
||||
float nGrey;
|
||||
bool fNorm;
|
||||
bool fSuper_prove;
|
||||
bool fSimple;
|
||||
bool fSyn;
|
||||
bool fPthread;
|
||||
int iOneWb;
|
||||
int iExp;
|
||||
unsigned nConstraintLimit;
|
||||
unsigned iVerbosity;
|
||||
unsigned nSeqLookBack;
|
||||
unsigned nTimeout;
|
||||
std::string simSetting;
|
||||
std::string parSetting;
|
||||
std::string fileName;
|
||||
std::string fileAbs;
|
||||
std::string fileStatesOut;
|
||||
std::string fileStatesIn;
|
||||
};
|
||||
struct Profile {
|
||||
Profile() : tBLSolver(0), tUifRefine(0), tWbRefine(0), tUifSim(0), tGbRefine(0) {}
|
||||
unsigned tBLSolver;
|
||||
unsigned tUifRefine;
|
||||
unsigned tWbRefine;
|
||||
unsigned tUifSim;
|
||||
unsigned tGbRefine;
|
||||
};
|
||||
|
||||
UfarManager();
|
||||
~UfarManager();
|
||||
|
||||
void Initialize(Wlc_Ntk_t * pNtk, const std::set<unsigned>& types);
|
||||
|
||||
Wlc_Ntk_t * BuildCurrentAbstraction();
|
||||
Wlc_Ntk_t * ApplyUifConstraints(Wlc_Ntk_t * pNtk, std::vector<int>& vec_ids);
|
||||
void FindUifPairsUsingCex(Abc_Cex_t * pCex, Abc_Cex_t ** ppCex = NULL);
|
||||
void FindUifPairsUsingSim();
|
||||
void DetermineWhiteBoxes(Abc_Cex_t * pCex);
|
||||
void DetermineGreyness(Abc_Cex_t * pCex);
|
||||
|
||||
int VerifyCurrentAbstraction(Abc_Cex_t ** ppCex);
|
||||
int PerformUIFProve(const timeval& timer);
|
||||
|
||||
void DumpMgrInfo() const;
|
||||
void DumpParams() const;
|
||||
void GetOperatorsInCex(Abc_Cex_t *pCex, VecVecStr* pRes);
|
||||
|
||||
Params params;
|
||||
Profile profile;
|
||||
|
||||
private:
|
||||
Wlc_Ntk_t * _abstract_operators(Wlc_Ntk_t * pNtk, const std::vector<int>& vec_ids) const;
|
||||
|
||||
Wlc_Ntk_t * _introduce_choices(std::vector<unsigned>& vec_choice2idx, bool fBlack);
|
||||
Wlc_Ntk_t * _introduce_bitwise_choices(std::vector<IntPair>& vec_choice2idx);
|
||||
Wlc_Ntk_t * _set_up_constraints(std::vector<int>& vec_ids);
|
||||
void _compute_core_choices(Wlc_Ntk_t * pChoice, Abc_Cex_t * pCex, std::vector<unsigned>& vec_cores, int num_sel_pis);
|
||||
void _simulate();
|
||||
void _perform_proof_based_white_boxing(Abc_Cex_t * pCex);
|
||||
void _perform_proof_based_grey_boxing(Abc_Cex_t * pCex);
|
||||
void _perform_cex_based_white_boxing();
|
||||
std::string _get_profile_uf_wb();
|
||||
void _massage_state_b();
|
||||
void _dump_states(const std::string& file);
|
||||
void _read_states(const std::string& file);
|
||||
|
||||
void _shrink_final_abstraction();
|
||||
|
||||
Wlc_Ntk_t * _pOrigNtk;
|
||||
std::vector<std::string> _vec_orig_names;
|
||||
|
||||
std::vector<int> _vec_op_ids;
|
||||
std::vector<bool> _vec_op_blackbox_marks;
|
||||
std::vector<std::vector<int> > _vec_vec_op_ffs;
|
||||
std::vector<Greyness> _vec_op_greyness;
|
||||
|
||||
std::set<UIF_PAIR> _set_uif_pairs;
|
||||
std::set<UIF_PAIR> _set_uif_sim_pairs;
|
||||
std::set<OperatorID> _set_prev_ops;
|
||||
|
||||
Wlc_Ntk_t * _pAbsWithAuxPos;
|
||||
|
||||
std::unique_ptr<SimUifPairFinder> _p_sim_mgr;
|
||||
std::unique_ptr<CexUifPairFinder> _p_cex_mgr;
|
||||
|
||||
std::ostringstream _oss;
|
||||
|
||||
struct timespec _timeout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif /* SRC_EXT2_UIF_UIFMGR_H_ */
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sat/bmc/bmc.h"
|
||||
#include "proof/pdr/pdr.h"
|
||||
#include "aig/gia/giaAig.h"
|
||||
#include "opt/util/util.h"
|
||||
#include "opt/untk/NtkNtk.h"
|
||||
#include "UfarPth.h"
|
||||
|
||||
ABC_NAMESPACE_HEADER_START
|
||||
Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pAig );
|
||||
int Abc_NtkDarBmc3( Abc_Ntk_t * pAbcNtk, Saig_ParBmc_t * pBmcPars, int fOrDecomp );
|
||||
Wla_Man_t * Wla_ManStart( Wlc_Ntk_t * pNtk, Wlc_Par_t * pPars );
|
||||
void Wla_ManStop( Wla_Man_t * pWla );
|
||||
int Wla_ManSolve( Wla_Man_t * pWla, Wlc_Par_t * pPars );
|
||||
ABC_NAMESPACE_HEADER_END
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
static volatile int g_nRunIds = 0; // the number of the last prover instance
|
||||
int Ufar_CallBackToStop( int RunId ) { assert( RunId <= g_nRunIds ); return RunId < g_nRunIds; }
|
||||
int Ufar_GetGlobalRunId() { return g_nRunIds; }
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace UFAR {
|
||||
|
||||
// mutext to control access to shared variables
|
||||
pthread_mutex_t g_mutex;
|
||||
// cv to control timer
|
||||
pthread_cond_t g_cond;
|
||||
|
||||
struct Pth_Data_t
|
||||
{
|
||||
Pth_Data_t () : RunId(-1), pGia(NULL), pWlc(NULL), ppCex(NULL), RetValue(-1), engine(NULL) {}
|
||||
void set ( const string * eng, int id, Wlc_Ntk_t * pWL, Gia_Man_t * pBL, Abc_Cex_t ** pp ) { engine = eng; RunId = id; pWlc = pWL; pGia = pBL; ppCex = pp; }
|
||||
int RunId;
|
||||
Gia_Man_t * pGia;
|
||||
Wlc_Ntk_t * pWlc;
|
||||
Abc_Cex_t ** ppCex;
|
||||
int RetValue;
|
||||
const string * engine;
|
||||
};
|
||||
|
||||
class Solver {
|
||||
public:
|
||||
virtual ~Solver() {}
|
||||
virtual int Solve() = 0;
|
||||
virtual void SetCex( Abc_Cex_t ** ppCex ) = 0;
|
||||
};
|
||||
|
||||
class PDR : public Solver {
|
||||
public:
|
||||
PDR( void * pArg ) {
|
||||
Pth_Data_t * pData = (Pth_Data_t *)pArg;
|
||||
|
||||
_pAig = Gia_ManToAigSimple( pData->pGia );
|
||||
|
||||
Pdr_Par_t * pPdrPars = &_PdrPars;
|
||||
Pdr_ManSetDefaultParams(pPdrPars);
|
||||
pPdrPars->nConfLimit = 0;
|
||||
pPdrPars->RunId = pData->RunId;
|
||||
pPdrPars->pFuncStop = Ufar_CallBackToStop;
|
||||
}
|
||||
~PDR() { Aig_ManStop(_pAig); }
|
||||
|
||||
virtual int Solve() {
|
||||
return Pdr_ManSolve( _pAig, &_PdrPars );
|
||||
}
|
||||
|
||||
virtual void SetCex( Abc_Cex_t ** ppCex ) {
|
||||
assert( _pAig->pSeqModel );
|
||||
*(ppCex) = _pAig->pSeqModel;
|
||||
_pAig->pSeqModel = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Aig_Man_t * _pAig;
|
||||
Pdr_Par_t _PdrPars;
|
||||
};
|
||||
|
||||
class PDRA : public Solver {
|
||||
public:
|
||||
PDRA( void * pArg ) {
|
||||
Pth_Data_t * pData = (Pth_Data_t *)pArg;
|
||||
|
||||
_pAig = Gia_ManToAigSimple( pData->pGia );
|
||||
|
||||
Pdr_Par_t * pPdrPars = &_PdrPars;
|
||||
Pdr_ManSetDefaultParams(pPdrPars);
|
||||
pPdrPars->nConfLimit = 0;
|
||||
pPdrPars->RunId = pData->RunId;
|
||||
pPdrPars->pFuncStop = Ufar_CallBackToStop;
|
||||
pPdrPars->fUseAbs = 1; // use 'pdr -t' (on-the-fly abstraction)
|
||||
pPdrPars->fCtgs = 1; // use 'pdr -c' (improved generalization)
|
||||
pPdrPars->fSkipDown = 0; // use 'pdr -n' (improved generalization)
|
||||
pPdrPars->nRestLimit = 500; // reset queue or proof-obligations when it gets larger than this
|
||||
}
|
||||
~PDRA() { Aig_ManStop(_pAig); }
|
||||
|
||||
virtual int Solve() {
|
||||
return Pdr_ManSolve( _pAig, &_PdrPars );
|
||||
}
|
||||
|
||||
virtual void SetCex( Abc_Cex_t ** ppCex ) {
|
||||
assert( _pAig->pSeqModel );
|
||||
*(ppCex) = _pAig->pSeqModel;
|
||||
_pAig->pSeqModel = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Aig_Man_t * _pAig;
|
||||
Pdr_Par_t _PdrPars;
|
||||
};
|
||||
|
||||
class BMC3 : public Solver {
|
||||
public:
|
||||
BMC3 ( void * pArg ) {
|
||||
Pth_Data_t * pData = (Pth_Data_t *)pArg;
|
||||
Aig_Man_t * pAig = Gia_ManToAigSimple( pData->pGia );
|
||||
_pNtk = Abc_NtkFromAigPhase( pAig );
|
||||
Aig_ManStop( pAig );
|
||||
|
||||
Saig_ParBmc_t * pBmcPars = &_Pars;
|
||||
Saig_ParBmcSetDefaultParams( pBmcPars );
|
||||
pBmcPars->RunId = pData->RunId;
|
||||
pBmcPars->pFuncStop = Ufar_CallBackToStop;
|
||||
}
|
||||
~BMC3() { Abc_NtkDelete(_pNtk); }
|
||||
|
||||
virtual int Solve() {
|
||||
return Abc_NtkDarBmc3( _pNtk, &_Pars, 0 );
|
||||
}
|
||||
|
||||
virtual void SetCex( Abc_Cex_t ** ppCex ) {
|
||||
assert( _pNtk->pSeqModel );
|
||||
*(ppCex) = _pNtk->pSeqModel;
|
||||
_pNtk->pSeqModel = NULL;
|
||||
}
|
||||
private:
|
||||
Abc_Ntk_t * _pNtk;
|
||||
Saig_ParBmc_t _Pars;
|
||||
};
|
||||
|
||||
class PDRWLA : public Solver {
|
||||
public:
|
||||
PDRWLA( void * pArg ) {
|
||||
Pth_Data_t * pData = (Pth_Data_t *)pArg;
|
||||
Wlc_Ntk_t * pNtk = pData->pWlc;
|
||||
|
||||
Wlc_Par_t * pWlcPars = &_Pars;
|
||||
Wlc_ManSetDefaultParams( pWlcPars );
|
||||
pWlcPars->nBitsAdd = 8;
|
||||
pWlcPars->nBitsMul = 4;
|
||||
pWlcPars->nBitsMux = 8;
|
||||
pWlcPars->fXorOutput = 0;
|
||||
pWlcPars->nLimit = 50;
|
||||
pWlcPars->fVerbose = 1;
|
||||
pWlcPars->fProofRefine = 1;
|
||||
pWlcPars->fHybrid = 0;
|
||||
pWlcPars->fCheckCombUnsat = 1;
|
||||
pWlcPars->RunId = pData->RunId;
|
||||
pWlcPars->pFuncStop = Ufar_CallBackToStop;
|
||||
|
||||
_pWla = Wla_ManStart( pNtk, pWlcPars );
|
||||
}
|
||||
~PDRWLA() { Wla_ManStop(_pWla); }
|
||||
|
||||
virtual int Solve() {
|
||||
return Wla_ManSolve( _pWla, &_Pars );
|
||||
}
|
||||
|
||||
virtual void SetCex( Abc_Cex_t ** ppCex ) {
|
||||
assert( _pWla->pCex );
|
||||
*(ppCex) = _pWla->pCex;
|
||||
_pWla->pCex = NULL;
|
||||
}
|
||||
private:
|
||||
Wla_Man_t * _pWla;
|
||||
Wlc_Par_t _Pars;
|
||||
};
|
||||
|
||||
void KillOthers() {
|
||||
pthread_cond_signal( &g_cond );
|
||||
++g_nRunIds;
|
||||
}
|
||||
|
||||
void * RunSolver( void * pArg ) {
|
||||
Pth_Data_t * pData = (Pth_Data_t *)pArg;
|
||||
Solver * pSolver = NULL;
|
||||
int status;
|
||||
|
||||
if ( *(pData->engine) == "pdr" )
|
||||
pSolver = new PDR( pArg );
|
||||
else if ( *(pData->engine) == "pdra" )
|
||||
pSolver = new PDRA( pArg );
|
||||
else if ( *(pData->engine) == "bmc3" )
|
||||
pSolver = new BMC3( pArg );
|
||||
else if ( *(pData->engine) == "wla" )
|
||||
pSolver = new PDRWLA( pArg );
|
||||
else {
|
||||
pthread_exit( NULL );
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pData->RetValue = pSolver->Solve();
|
||||
int ret = pData->RetValue;
|
||||
|
||||
status = pthread_mutex_lock(&g_mutex); assert( status == 0 );
|
||||
if ( ret == 0 ) {
|
||||
pSolver->SetCex( pData->ppCex );
|
||||
LOG(2) << *(pData->engine) << " found CEX. RunId = " << pData->RunId;
|
||||
|
||||
KillOthers();
|
||||
} else if ( ret == 1 ) {
|
||||
LOG(2) << *(pData->engine) << " proved the problem. RunId = " << pData->RunId;
|
||||
KillOthers();
|
||||
} else {
|
||||
if ( pData->RunId < g_nRunIds ) {
|
||||
LOG(2) << *(pData->engine) << " was cancelled. RunId = " << pData->RunId;
|
||||
}
|
||||
}
|
||||
status = pthread_mutex_unlock(&g_mutex); assert( status == 0 );
|
||||
|
||||
delete pSolver;
|
||||
|
||||
pthread_exit( NULL );
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void * Timer ( void * pArg ) {
|
||||
struct timespec * pTimeout = ( struct timespec * )pArg;
|
||||
int retcode = 0;
|
||||
int status;
|
||||
|
||||
status = pthread_mutex_lock(&g_mutex); assert( status == 0 );
|
||||
retcode = pthread_cond_timedwait(&g_cond, &g_mutex, pTimeout);
|
||||
if ( retcode == ETIMEDOUT ) {
|
||||
LOG(2) << "Timer reached timeout.";
|
||||
KillOthers();
|
||||
} else {
|
||||
LOG(2) << "Timer was cancelled.";
|
||||
}
|
||||
status = pthread_mutex_unlock(&g_mutex); assert( status == 0 );
|
||||
|
||||
pthread_exit( NULL );
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RunConcurrentSolver( Wlc_Ntk_t * pNtk, const vector<string>& vSolvers, Abc_Cex_t ** ppCex, struct timespec * pTimeout ) {
|
||||
assert( pTimeout );
|
||||
|
||||
int status;
|
||||
vector<Pth_Data_t> vDatas ( vSolvers.size() );
|
||||
vector<pthread_t> vThreads ( vSolvers.size() );
|
||||
pthread_t timer;
|
||||
|
||||
Gia_Man_t * pGia = BitBlast( pNtk );
|
||||
|
||||
status = pthread_create( &timer, NULL, Timer, pTimeout );
|
||||
assert( status == 0 );
|
||||
|
||||
for ( size_t i = 0; i < vSolvers.size(); ++i ) {
|
||||
vDatas[i].set( &vSolvers[i], g_nRunIds, pNtk, pGia, ppCex );
|
||||
status = pthread_create( &vThreads[i], NULL, RunSolver, &vDatas[i] );
|
||||
assert( status == 0 );
|
||||
}
|
||||
|
||||
status = pthread_join( timer, NULL );
|
||||
assert( status == 0 );
|
||||
for ( size_t i = 0; i < vSolvers.size(); ++i ) {
|
||||
status = pthread_join( vThreads[i], NULL );
|
||||
assert( status == 0 );
|
||||
}
|
||||
|
||||
Gia_ManStop( pGia );
|
||||
|
||||
for( auto& x : vDatas ) {
|
||||
if ( x.RetValue != -1 )
|
||||
return x.RetValue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Yen-Sheng Ho on 04/09/17.
|
||||
//
|
||||
|
||||
#ifndef SRC_EXT2_UFAR_PTH_H
|
||||
#define SRC_EXT2_UFAR_PTH_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "base/wlc/wlc.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace UFAR
|
||||
{
|
||||
int RunConcurrentSolver( Wlc_Ntk_t * pNtk, const std::vector<std::string>& vSolvers, Abc_Cex_t ** ppCex, struct timespec * timeout );
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif //SRC_EXT2_UFAR_PTH_H
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC += src/opt/ufar/UfarCmd.cpp \
|
||||
src/opt/ufar/UfarPth.cpp \
|
||||
src/opt/ufar/UfarMgr.cpp
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// Created by Yen-Sheng Ho on 8/9/16.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <base/wlc/wlc.h>
|
||||
#include "Netlist.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace UFAR {
|
||||
|
||||
WNetlist::WNetlist() {
|
||||
_pNtk = Wlc_NtkAlloc("main", 100);
|
||||
}
|
||||
|
||||
WNetlist::WNetlist(Wlc_Ntk_t *pNtk) {
|
||||
if (pNtk)
|
||||
_pNtk = Wlc_NtkDupDfsSimple(pNtk);
|
||||
else
|
||||
_pNtk = NULL;
|
||||
}
|
||||
|
||||
WNetlist::WNetlist(const WNetlist& that) {
|
||||
_pNtk = Wlc_NtkDupDfsSimple(that._pNtk);
|
||||
}
|
||||
|
||||
WNetlist::WNetlist(WNetlist && that) {
|
||||
_pNtk = that._pNtk;
|
||||
that._pNtk = NULL;
|
||||
}
|
||||
|
||||
WNetlist& WNetlist::operator=(const WNetlist& that) {
|
||||
Wlc_Ntk_t * pTemp = _pNtk;
|
||||
_pNtk = Wlc_NtkDupDfsSimple(that._pNtk);
|
||||
if (pTemp) Wlc_NtkFree(pTemp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
WNetlist::~WNetlist() {
|
||||
if (_pNtk) Wlc_NtkFree(_pNtk);
|
||||
}
|
||||
|
||||
void WNetlist::Clear() {
|
||||
if (_pNtk) Wlc_NtkFree(_pNtk);
|
||||
_pNtk = Wlc_NtkAlloc("main", 100);
|
||||
}
|
||||
|
||||
bool WNetlist::Empty() const {
|
||||
if (_pNtk == NULL) return true;
|
||||
|
||||
return Wlc_NtkObjNum(_pNtk) == 0;
|
||||
}
|
||||
|
||||
void WNetlist::Reset(Wlc_Ntk_t *pNtk) {
|
||||
Wlc_Ntk_t * pTemp = _pNtk;
|
||||
_pNtk = Wlc_NtkDupDfsSimple(pNtk);
|
||||
if (pTemp) Wlc_NtkFree(pTemp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by ysho on 8/9/16.
|
||||
//
|
||||
|
||||
#ifndef ABC_WAR_NETLIST_H
|
||||
#define ABC_WAR_NETLIST_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
typedef struct Wlc_Ntk_t_ Wlc_Ntk_t;
|
||||
|
||||
namespace UFAR {
|
||||
|
||||
class WNetlist {
|
||||
public:
|
||||
WNetlist();
|
||||
WNetlist(Wlc_Ntk_t * pNtk);
|
||||
WNetlist(const WNetlist& that);
|
||||
~WNetlist();
|
||||
WNetlist(WNetlist && that);
|
||||
WNetlist& operator=(const WNetlist& that);
|
||||
Wlc_Ntk_t * GetNtk() const {return _pNtk;}
|
||||
void Clear();
|
||||
bool Empty() const;
|
||||
void Reset(Wlc_Ntk_t * pNtk);
|
||||
private:
|
||||
Wlc_Ntk_t * _pNtk;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif //ABC_WAR_NETLIST_H
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* NtkCmd.cpp
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#include "opt/untk/NtkCmd.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
void Ntk_Init (Abc_Frame_t *pAbc)
|
||||
{
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* NtkCmd.h
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#ifndef SRC_EXT2_NTK_NTKCMD_H_
|
||||
#define SRC_EXT2_NTK_NTKCMD_H_
|
||||
|
||||
#include "base/main/mainInt.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
void Ntk_Init(Abc_Frame_t *pAbc);
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif /* SRC_EXT2_NTK_NTKCMD_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* NtkNtk.h
|
||||
*
|
||||
* Created on: Aug 25, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#ifndef SRC_EXT2_NTK_NTKNTK_H_
|
||||
#define SRC_EXT2_NTK_NTKNTK_H_
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <base/wlc/wlc.h>
|
||||
#include "Netlist.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
typedef struct Wlc_Ntk_t_ Wlc_Ntk_t;
|
||||
typedef struct Abc_Cex_t_ Abc_Cex_t;
|
||||
typedef struct Vec_Int_t_ Vec_Int_t;
|
||||
typedef struct Gia_Man_t_ Gia_Man_t;
|
||||
|
||||
namespace UFAR {
|
||||
|
||||
using VecVecChar = std::vector<std::vector<char> >;
|
||||
using VecVecInt = std::vector<std::vector<int> >;
|
||||
using IntPair = std::pair<int, int>;
|
||||
|
||||
struct OperatorID {
|
||||
OperatorID() : idx(-1), timediff(0) {}
|
||||
OperatorID(int i) : idx(i), timediff(0) {}
|
||||
OperatorID(int i, int t) : idx(i), timediff(t) {}
|
||||
bool operator< (const OperatorID& rhs) const {
|
||||
if (timediff != rhs.timediff) return (timediff < rhs.timediff);
|
||||
return (idx < rhs.idx);
|
||||
}
|
||||
bool operator!= (const OperatorID& rhs) const {
|
||||
return ((idx != rhs.idx) || (timediff != rhs.timediff));
|
||||
}
|
||||
int idx;
|
||||
int timediff;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const OperatorID& obj);
|
||||
|
||||
struct UifPair {
|
||||
UifPair(const OperatorID& first_, const OperatorID& second_) : first(first_), second(second_), fMark(false) {}
|
||||
UifPair(const OperatorID& first_, const OperatorID& second_, bool fMark_) : first(first_), second(second_), fMark(fMark_) {}
|
||||
bool operator< (const UifPair& rhs) const {
|
||||
if(first != rhs.first) return (first < rhs.first);
|
||||
if(second != rhs.second) return (second < rhs.second);
|
||||
return (!fMark && rhs.fMark);
|
||||
}
|
||||
OperatorID first;
|
||||
OperatorID second;
|
||||
bool fMark;
|
||||
};
|
||||
|
||||
class Greyness {
|
||||
public:
|
||||
Greyness(Wlc_Ntk_t * pNtk, Wlc_Obj_t * pObj);
|
||||
|
||||
std::string to_string() const {
|
||||
std::ostringstream oss;
|
||||
for (size_t i = 0; i < _vec_black_bits.size(); ++i)
|
||||
oss << ( _vec_black_bits[i] ? '0' : '1' );
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool IsGrey() const {
|
||||
return (!IsBlack() && !IsWhite());
|
||||
}
|
||||
bool IsWhite() const {
|
||||
return (std::find(_vec_black_bits.begin(), _vec_black_bits.end(), true) == _vec_black_bits.end());
|
||||
}
|
||||
bool IsBlack() const {
|
||||
return (std::find(_vec_black_bits.begin(), _vec_black_bits.end(), false) == _vec_black_bits.end());
|
||||
}
|
||||
unsigned TotalCost() const { return _total_cost; }
|
||||
unsigned CurrentCost() const { return _current_cost; }
|
||||
void UpdateCost();
|
||||
|
||||
size_t Size() const { return _vec_black_bits.size(); }
|
||||
bool Get(size_t pos) const { return _vec_black_bits[pos]; }
|
||||
void Set(size_t pos, bool val) { _vec_black_bits[pos] = val; }
|
||||
|
||||
void SetWhite() {
|
||||
_vec_black_bits = std::vector<bool>(_vec_black_bits.size(), false);
|
||||
_current_cost = _total_cost;
|
||||
}
|
||||
bool IsTooWhite(float threshold) const {
|
||||
float ratio = float(_current_cost) / float(_total_cost);
|
||||
if ((ratio > threshold) || (_current_cost == _total_cost))
|
||||
return true;
|
||||
if (ratio > 0.5 && _total_cost < 1000)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<bool> _vec_black_bits;
|
||||
unsigned _total_cost;
|
||||
unsigned _current_cost;
|
||||
unsigned _orig_size;
|
||||
WNetlist _N_white;
|
||||
int _iOpId;
|
||||
};
|
||||
|
||||
Wlc_Ntk_t * AbstractNodes( Wlc_Ntk_t * p, Vec_Int_t * vNodesInit );
|
||||
Wlc_Ntk_t * AddConstFlops( Wlc_Ntk_t * p, const std::set<unsigned>& types );
|
||||
Wlc_Ntk_t * IntroduceChoices( Wlc_Ntk_t * p, Vec_Int_t * vNodes );
|
||||
Wlc_Ntk_t * IntroduceBitwiseChoices( Wlc_Ntk_t * pNtk, std::vector<int>& vec_ids, const std::vector<Greyness>& vec_greys, std::vector<IntPair>& vec_choice2idx );
|
||||
Wlc_Ntk_t * CreateMiter(Wlc_Ntk_t *pNtk, bool fXor);
|
||||
Wlc_Ntk_t * NormalizeDataTypes(Wlc_Ntk_t * p, const std::set<unsigned>& types, bool fUnify);
|
||||
Wlc_Ntk_t * AddAuxPOsForOperators(Wlc_Ntk_t * p, std::vector<int>& vec_ids, int max_input_bw = -1, int max_output_bw = -1);
|
||||
Wlc_Ntk_t * RemoveAuxPOs(Wlc_Ntk_t * p, int iStart);
|
||||
Wlc_Ntk_t * DupNtkAndUpdateIDs(Wlc_Ntk_t * p, std::vector<int>& vec_ids);
|
||||
Wlc_Ntk_t * ApplyGreynessConstraints(Wlc_Ntk_t * pNtk, const std::vector<Greyness>& vec_grey, std::vector<int>& vec_ids);
|
||||
Wlc_Ntk_t * IntroducePrevOperators(Wlc_Ntk_t * pNtk, std::vector<int>& vec_ids, const std::set<OperatorID>& set_prev_ops, VecVecInt& vv_op_ffs);
|
||||
Wlc_Ntk_t * ApplyGreyConstraints(Wlc_Ntk_t * pNtk, std::vector<int>& vec_ids, bool fSeq);
|
||||
int AddOneFanoutFF(Wlc_Ntk_t * pNtk, int obj_id, unsigned& count_bits);
|
||||
int AddOneUifImplication(Wlc_Ntk_t * pNtk, const std::array<int, 3>& wires1, const std::array<int, 3>& wires2);
|
||||
void FoldCombConstraints(Wlc_Ntk_t *pNtk, Vec_Int_t *vConstrs);
|
||||
void FoldSeqConstraints(Wlc_Ntk_t *pNtk, Vec_Int_t *vConstrs);
|
||||
void CollectPoValuesInCex(Gia_Man_t * pGia, Abc_Cex_t * pCex, VecVecChar& po_values, bool fCexMin);
|
||||
bool HasOperator(const Wlc_Ntk_t * p, const std::set<unsigned>& types);
|
||||
|
||||
void ComputeMaxBW(Wlc_Ntk_t * p, const std::vector<int>& vec_ids, int& max_input_bw, int& max_output_bw );
|
||||
|
||||
void PrintWordCEX(Wlc_Ntk_t * pNtk, Abc_Cex_t * pCex, const std::vector<std::string>* names = nullptr);
|
||||
|
||||
unsigned compute_bit_level_pi_num(Wlc_Ntk_t * pNtk);
|
||||
|
||||
int verify_model(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const std::string* pFileName = NULL, const std::string* pParSetting = NULL, bool fSyn = false, struct timespec * timeout = NULL);
|
||||
int bit_level_solve(Wlc_Ntk_t * pNtk, Abc_Cex_t ** ppCex, const std::string* pFileName = NULL, const std::string* pParSetting = NULL, bool fSyn = false);
|
||||
|
||||
Gia_Man_t * BitBlast(Wlc_Ntk_t * pNtk);
|
||||
|
||||
Gia_Man_t * GetInvMiter(Wlc_Ntk_t * pNtk, char * nameInv);
|
||||
void TestInvariant(std::string& nameNtk, std::string& nameInv);
|
||||
|
||||
Wlc_Ntk_t * MakeUnderApprox(Wlc_Ntk_t * pNtk, int num_bits);
|
||||
Wlc_Ntk_t * MakeUnderApprox2(Wlc_Ntk_t * pNtk, const std::set<unsigned>& types, int num_bits);
|
||||
|
||||
|
||||
}
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif /* SRC_EXT2_NTK_NTKNTK_H_ */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC += src/opt/untk/NtkCmd.cpp \
|
||||
src/opt/untk/Netlist.cpp \
|
||||
src/opt/untk/NtkNtk.cpp
|
||||
|
|
@ -0,0 +1 @@
|
|||
SRC += src/opt/util/util.cpp
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* util.cpp
|
||||
*
|
||||
* Created on: Aug 31, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <csignal>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
using namespace std;
|
||||
|
||||
unsigned LogT::loglevel = 0;
|
||||
string LogT::prefix = "LOG";
|
||||
|
||||
bool OptMgr::Parse(int argc, char * argv[]) {
|
||||
if(argc <= 1) return true;
|
||||
|
||||
for(int i = 1; i < argc; i++) {
|
||||
if(_map.count(argv[i]) == 0)
|
||||
return false;
|
||||
|
||||
Option& opt = _map[argv[i]];
|
||||
opt._val = "yes";
|
||||
|
||||
if(!opt.isBool()) {
|
||||
if (i + 1 == argc)
|
||||
return false;
|
||||
opt._val = argv[++i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OptMgr::PrintUsage() {
|
||||
cout << "usage: " << _cmd << endl;
|
||||
cout << " Uninterpreted Function Abstraction and Refinement (UFAR)\n";
|
||||
for (auto x : _map) {
|
||||
ostringstream ss;
|
||||
ss << x.first << " " << (x.second.isBool() ? "" : x.second._arg_type);
|
||||
cout << " " << setw(10) << left << ss.str();
|
||||
cout << " : " << x.second._help << " [default = " << x.second._default << "]" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
void kill_on_parent_death(int sig)
|
||||
{
|
||||
// kill process if parent dies
|
||||
prctl(PR_SET_PDEATHSIG, sig);
|
||||
|
||||
// the parent might have died before calling prctl
|
||||
// in that case, it would be adopted by init, whose pid is 1
|
||||
if (getppid() == 1)
|
||||
{
|
||||
raise(sig);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
template <typename Func>
|
||||
static auto retry_eintr(Func &&fn) -> decltype(fn())
|
||||
{
|
||||
decltype(fn()) rc;
|
||||
do {
|
||||
rc = fn();
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void kill_on_parent_death(int sig)
|
||||
{
|
||||
const int ppid = getppid();
|
||||
|
||||
std::thread monitor_thread([ppid, sig](){
|
||||
|
||||
struct kevent change;
|
||||
EV_SET(&change, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, nullptr);
|
||||
|
||||
int kq = kqueue();
|
||||
assert( kq >= 0 );
|
||||
|
||||
struct kevent event;
|
||||
struct timespec ts = {0, 0};
|
||||
|
||||
// start listening, we are guaranteed to receive a notification if ppid is dead
|
||||
kevent(kq, &change, 1, &event, 1, &ts);
|
||||
|
||||
// however, if ppid died before the call to kevent, ppid might not be the pid of the parent
|
||||
// in that case, it would be adopted by init, whose pid is 1
|
||||
if( getppid() == 1 )
|
||||
{
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
// now block on kevent until the the parent process dies
|
||||
retry_eintr([&](){
|
||||
return kevent(kq, &change, 1, &event, 1, nullptr);
|
||||
});
|
||||
|
||||
raise(sig);
|
||||
});
|
||||
|
||||
monitor_thread.detach();
|
||||
}
|
||||
|
||||
#else // neither linux or OS X
|
||||
|
||||
void kill_on_parent_death(int sig)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* util.h
|
||||
*
|
||||
* Created on: Aug 31, 2015
|
||||
* Author: Yen-Sheng Ho
|
||||
*/
|
||||
|
||||
#ifndef SRC_EXT2_UTIL_UTIL_H_
|
||||
#define SRC_EXT2_UTIL_UTIL_H_
|
||||
|
||||
/* http://stackoverflow.com/questions/6168107/how-to-implement-a-good-debug-logging-feature-in-a-project */
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "misc/util/abc_namespaces.h"
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
class LogT {
|
||||
public:
|
||||
LogT(unsigned _loglevel = 0) {
|
||||
// _buffer << "LOG" << _loglevel << " :" << std::string(_loglevel > 0 ? _loglevel * 4 : 1, ' ');
|
||||
_buffer << prefix << " :" << std::string(_loglevel > 0 ? _loglevel * 4 : 1, ' ');
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LogT & operator<<(T const & value) {
|
||||
_buffer << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~LogT() {
|
||||
std::cout << _buffer.str() << std::endl;
|
||||
}
|
||||
|
||||
static unsigned loglevel;
|
||||
static std::string prefix;
|
||||
private:
|
||||
std::ostringstream _buffer;
|
||||
};
|
||||
|
||||
#define LOG(level) \
|
||||
if (level > LogT::loglevel) ; \
|
||||
else LogT(level)
|
||||
|
||||
class OptMgr {
|
||||
public:
|
||||
OptMgr(const std::string& cmd) : _cmd(cmd) {}
|
||||
bool Parse(int argc, char * argv[]);
|
||||
void AddOpt(const std::string& opt, const std::string& default_val, const std::string& arg_type, const std::string& help) {
|
||||
_map[opt] = Option(default_val, arg_type, help);
|
||||
}
|
||||
std::string GetOptVal(const std::string& opt) {return _map[opt]._val;}
|
||||
bool operator[](const std::string& opt) {return _has_opt(opt);}
|
||||
|
||||
void PrintUsage();
|
||||
private:
|
||||
struct Option {
|
||||
Option(){}
|
||||
Option(const std::string& val, const std::string& arg_type, const std::string& help) :
|
||||
_default(val), _help(help), _arg_type(arg_type){}
|
||||
bool isBool() {return _arg_type == "";}
|
||||
std::string _default;
|
||||
std::string _help;
|
||||
std::string _arg_type;
|
||||
std::string _val;
|
||||
};
|
||||
|
||||
bool _has_opt(const std::string& opt) {return !_map[opt]._val.empty();}
|
||||
|
||||
std::map<std::string, Option> _map;
|
||||
std::string _cmd;
|
||||
};
|
||||
|
||||
static inline unsigned elapsed_time_usec(const timeval& tBefore, const timeval& tAfter) {
|
||||
return (tAfter.tv_sec - tBefore.tv_sec)*1000000 + (tAfter.tv_usec - tBefore.tv_usec);
|
||||
}
|
||||
|
||||
void kill_on_parent_death(int sig);
|
||||
|
||||
int call_python(const char* modulename, const char* funcname, const char* aig, std::vector<int>& cex);
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_END
|
||||
|
||||
#endif /* SRC_EXT2_UTIL_UTIL_H_ */
|
||||
|
|
@ -140,6 +140,9 @@ struct Cec_ParCec_t_
|
|||
int fVeryVerbose; // verbose stats
|
||||
int fVerbose; // verbose stats
|
||||
int iOutFail; // the number of failed output
|
||||
const char * pNameSpec; // name of the first (spec) network
|
||||
const char * pNameImpl; // name of the second (impl) network
|
||||
Vec_Ptr_t * vNamesIn; // input names of the first network
|
||||
};
|
||||
|
||||
// sequential register correspodence parameters
|
||||
|
|
@ -273,4 +276,3 @@ ABC_NAMESPACE_HEADER_END
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -26,15 +26,117 @@
|
|||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// DECLARATIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern void Abc_NtkVerifyPrintCex( const int * pModel, const int * pValues1, const int * pValues2,
|
||||
const char * const * ppInputNames, int nInputs, const char * const * ppOutputNames, int nOutputs,
|
||||
const char * pNtkName1, const char * pNtkName2 );
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int * Cec_ManSimulateCombOutputs( Gia_Man_t * p, const int * pInputs )
|
||||
{
|
||||
Gia_Obj_t * pObj;
|
||||
int * pValues, * pOutputs, i;
|
||||
pValues = ABC_ALLOC( int, Gia_ManObjNum(p) );
|
||||
if ( pValues == NULL )
|
||||
return NULL;
|
||||
pValues[0] = 0;
|
||||
Gia_ManForEachPi( p, pObj, i )
|
||||
pValues[Gia_ObjId(p, pObj)] = pInputs[i];
|
||||
Gia_ManForEachAnd( p, pObj, i )
|
||||
{
|
||||
int v0 = pValues[Gia_ObjFaninId0p(p, pObj)] ^ Gia_ObjFaninC0(pObj);
|
||||
int v1 = pValues[Gia_ObjFaninId1p(p, pObj)] ^ Gia_ObjFaninC1(pObj);
|
||||
pValues[Gia_ObjId(p, pObj)] = v0 & v1;
|
||||
}
|
||||
pOutputs = ABC_ALLOC( int, Gia_ManPoNum(p) );
|
||||
Gia_ManForEachPo( p, pObj, i )
|
||||
pOutputs[i] = pValues[Gia_ObjFaninId0p(p, pObj)] ^ Gia_ObjFaninC0(pObj);
|
||||
ABC_FREE( pValues );
|
||||
return pOutputs;
|
||||
}
|
||||
|
||||
static const char * Cec_ManGetName( const char * pName, const char * pPrefix, int Idx, Vec_Ptr_t * vStore )
|
||||
{
|
||||
if ( pName )
|
||||
return pName;
|
||||
{
|
||||
char Buffer[64];
|
||||
sprintf( Buffer, "%s[%d]", pPrefix, Idx );
|
||||
pName = Abc_UtilStrsav( Buffer );
|
||||
Vec_PtrPush( vStore, (void *)pName );
|
||||
return pName;
|
||||
}
|
||||
}
|
||||
|
||||
void Cec_ManPrintCexSummary( Gia_Man_t * p, Abc_Cex_t * pCex, Cec_ParCec_t * pPars )
|
||||
{
|
||||
Vec_Ptr_t * vToFree = NULL;
|
||||
const char ** ppInNames = NULL;
|
||||
const char ** ppOutNames = NULL;
|
||||
int * pInputs = NULL;
|
||||
int * pOutputs = NULL;
|
||||
int * pOut1 = NULL;
|
||||
int * pOut2 = NULL;
|
||||
int nPis, nPairs, i;
|
||||
if ( (pPars && pPars->fSilent) || pCex == NULL )
|
||||
return;
|
||||
if ( pCex->nRegs || pCex->iFrame || Gia_ManRegNum(p) )
|
||||
return;
|
||||
if ( (Gia_ManPoNum(p) & 1) || Gia_ManPiNum(p) != pCex->nPis )
|
||||
return;
|
||||
nPis = Gia_ManPiNum(p);
|
||||
nPairs = Gia_ManPoNum(p) / 2;
|
||||
pInputs = ABC_ALLOC( int, nPis );
|
||||
for ( i = 0; i < nPis; i++ )
|
||||
pInputs[i] = Abc_InfoHasBit( pCex->pData, pCex->nRegs + i );
|
||||
pOutputs = Cec_ManSimulateCombOutputs( p, pInputs );
|
||||
if ( pOutputs == NULL )
|
||||
goto finish;
|
||||
pOut1 = ABC_ALLOC( int, nPairs );
|
||||
pOut2 = ABC_ALLOC( int, nPairs );
|
||||
for ( i = 0; i < nPairs; i++ )
|
||||
{
|
||||
pOut1[i] = pOutputs[2 * i];
|
||||
pOut2[i] = pOutputs[2 * i + 1];
|
||||
}
|
||||
vToFree = Vec_PtrAlloc( 16 );
|
||||
ppInNames = ABC_ALLOC( const char *, nPis );
|
||||
for ( i = 0; i < nPis; i++ )
|
||||
{
|
||||
const char * pName = Gia_ObjCiName(p, i);
|
||||
if ( pName == NULL && pPars && pPars->vNamesIn && i < Vec_PtrSize(pPars->vNamesIn) )
|
||||
pName = (const char *)Vec_PtrEntry( pPars->vNamesIn, i );
|
||||
ppInNames[i] = Cec_ManGetName( pName, "a", i, vToFree );
|
||||
}
|
||||
ppOutNames = ABC_ALLOC( const char *, nPairs );
|
||||
for ( i = 0; i < nPairs; i++ )
|
||||
ppOutNames[i] = Cec_ManGetName( Gia_ObjCoName(p, 2 * i), "z", i, vToFree );
|
||||
Abc_NtkVerifyPrintCex( pInputs, pOut1, pOut2, ppInNames, nPis, ppOutNames, nPairs,
|
||||
pPars && pPars->pNameSpec ? pPars->pNameSpec : Gia_ManName(p),
|
||||
pPars && pPars->pNameImpl ? pPars->pNameImpl : (p->pSpec ? p->pSpec : Gia_ManName(p)) );
|
||||
|
||||
finish:
|
||||
if ( vToFree )
|
||||
{
|
||||
char * pName;
|
||||
Vec_PtrForEachEntry( char *, vToFree, pName, i )
|
||||
ABC_FREE( pName );
|
||||
Vec_PtrFree( vToFree );
|
||||
}
|
||||
ABC_FREE( ppInNames );
|
||||
ABC_FREE( ppOutNames );
|
||||
ABC_FREE( pOut1 );
|
||||
ABC_FREE( pOut2 );
|
||||
ABC_FREE( pOutputs );
|
||||
ABC_FREE( pInputs );
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis [Saves the input pattern with the given number.]
|
||||
|
|
@ -160,6 +262,7 @@ int Cec_ManHandleSpecialCases( Gia_Man_t * p, Cec_ParCec_t * pPars )
|
|||
}
|
||||
pPars->iOutFail = i/2;
|
||||
Cec_ManTransformPattern( p, i/2, NULL );
|
||||
Cec_ManPrintCexSummary( p, p->pCexComb, pPars );
|
||||
return 0;
|
||||
}
|
||||
// get the drivers
|
||||
|
|
@ -178,6 +281,7 @@ int Cec_ManHandleSpecialCases( Gia_Man_t * p, Cec_ParCec_t * pPars )
|
|||
// if their compl attributes are the same - one should be complemented
|
||||
assert( Gia_ObjFaninC0(pObj1) == Gia_ObjFaninC0(pObj2) );
|
||||
Abc_InfoSetBit( p->pCexComb->pData, Gia_ObjCioId(pDri1) );
|
||||
Cec_ManPrintCexSummary( p, p->pCexComb, pPars );
|
||||
return 0;
|
||||
}
|
||||
// one of the drivers is a PI; another is a constant 0
|
||||
|
|
@ -197,6 +301,7 @@ int Cec_ManHandleSpecialCases( Gia_Man_t * p, Cec_ParCec_t * pPars )
|
|||
Abc_InfoSetBit( p->pCexComb->pData, Gia_ObjCioId(pDri1) );
|
||||
else
|
||||
Abc_InfoSetBit( p->pCexComb->pData, Gia_ObjCioId(pDri2) );
|
||||
Cec_ManPrintCexSummary( p, p->pCexComb, pPars );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -383,6 +488,7 @@ int Cec_ManVerify( Gia_Man_t * pInit, Cec_ParCec_t * pPars )
|
|||
Abc_Print( 1, "Networks are NOT EQUIVALENT. " );
|
||||
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
|
||||
}
|
||||
Cec_ManPrintCexSummary( p, p->pCexComb, pPars );
|
||||
return 0;
|
||||
}
|
||||
Vec_IntFreeP( &pInit->vIdsEquiv );
|
||||
|
|
@ -417,6 +523,8 @@ int Cec_ManVerify( Gia_Man_t * pInit, Cec_ParCec_t * pPars )
|
|||
p->pCexComb = pNew->pCexComb; pNew->pCexComb = NULL;
|
||||
if ( p->pCexComb && !Gia_ManVerifyCex( p, p->pCexComb, 1 ) )
|
||||
Abc_Print( 1, "Counter-example simulation has failed.\n" );
|
||||
if ( RetValue == 0 )
|
||||
Cec_ManPrintCexSummary( p, p->pCexComb, pPars );
|
||||
Gia_ManStop( pNew );
|
||||
return RetValue;
|
||||
}
|
||||
|
|
@ -601,4 +709,3 @@ Aig_Man_t * Cec_FraigCombinational( Aig_Man_t * pAig, int nConfs, int fVerbose )
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ void Cec_ManCecSetDefaultParams( Cec_ParCec_t * p )
|
|||
p->fVeryVerbose = 0; // verbose stats
|
||||
p->fVerbose = 0; // verbose stats
|
||||
p->iOutFail = -1; // the number of failed output
|
||||
p->pNameSpec = NULL; // name of the first (spec) network
|
||||
p->pNameImpl = NULL; // name of the second (impl) network
|
||||
p->vNamesIn = NULL; // input names of the first network
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
|
@ -569,4 +572,3 @@ finalize:
|
|||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ static inline void Exa7_CadicalSetRuntimeLimit( cadical_solver * pSat, int nSeco
|
|||
/// DECLARATIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define MAJ_NOBJS 64 // Const0 + Const1 + nVars + nNodes
|
||||
#define MAJ_NOBJS 64 // Const0 + Const1 + nVars + nNodes
|
||||
#define MAJ_MAX_LUT 8
|
||||
|
||||
typedef struct Exa7_Man_t_ Exa7_Man_t;
|
||||
struct Exa7_Man_t_
|
||||
|
|
@ -71,7 +72,7 @@ struct Exa7_Man_t_
|
|||
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 VarMarks[MAJ_NOBJS][MAJ_MAX_LUT][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
|
||||
|
|
@ -277,6 +278,7 @@ static Exa7_Man_t * Exa7_ManAlloc( Bmc_EsPar_t * pPars, word * pTruth )
|
|||
p->nVars = pPars->nVars;
|
||||
p->nNodes = pPars->nNodes;
|
||||
p->nLutSize = pPars->nLutSize;
|
||||
assert( p->nLutSize <= MAJ_MAX_LUT );
|
||||
p->LutMask = (1 << pPars->nLutSize) - 1;
|
||||
p->nObjs = pPars->nVars + pPars->nNodes;
|
||||
p->nWords = Abc_TtWordNum(pPars->nVars);
|
||||
|
|
@ -291,7 +293,8 @@ static Exa7_Man_t * Exa7_ManAlloc( Bmc_EsPar_t * pPars, word * pTruth )
|
|||
p->pSat = cadical_solver_new();
|
||||
p->nVarAlloc = Exa7_ManVarReserve( p );
|
||||
assert( p->nVarAlloc >= p->iVar );
|
||||
cadical_solver_setnvars( p->pSat, p->nVarAlloc );
|
||||
//cadical_solver_setnvars( p->pSat, p->nVarAlloc );
|
||||
cadical_solver_setnvars( p->pSat, p->nVarAlloc+(p->nLutSize+1)*p->nNodes*(1 << p->nVars) );
|
||||
if ( pPars->RuntimeLim )
|
||||
Exa7_CadicalSetRuntimeLimit( p->pSat, pPars->RuntimeLim );
|
||||
return p;
|
||||
|
|
@ -333,7 +336,7 @@ static inline int Exa7_ManFindFanin( Exa7_Man_t * p, int i, int k )
|
|||
static inline int Exa7_ManEval( Exa7_Man_t * p )
|
||||
{
|
||||
static int Flag = 0;
|
||||
int i, k, j, iMint; word * pFanins[6];
|
||||
int i, k, j, iMint; word * pFanins[MAJ_MAX_LUT];
|
||||
for ( i = p->nVars; i < p->nObjs; i++ )
|
||||
{
|
||||
int iVarStart = 1 + p->LutMask*(i - p->nVars);
|
||||
|
|
@ -404,6 +407,77 @@ static void Exa7_ManPrintSolution( Exa7_Man_t * p, int fCompl )
|
|||
}
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
static Vec_Wrd_t * Exa7_ManSaveTruthTables( Exa7_Man_t * p, int fCompl )
|
||||
{
|
||||
int i, k, nWordsNode, nMintsNode;
|
||||
assert( p->nLutSize <= MAJ_MAX_LUT );
|
||||
nMintsNode = 1 << p->nLutSize;
|
||||
nWordsNode = (p->nLutSize <= 6) ? 1 : (p->nLutSize == 7 ? 2 : 4);
|
||||
Vec_Wrd_t * vTruths = Vec_WrdStart( p->nObjs * nWordsNode );
|
||||
for ( i = p->nVars; i < p->nObjs; i++ )
|
||||
{
|
||||
word Truth[4] = {0, 0, 0, 0};
|
||||
int iVarStart = 1 + p->LutMask*(i - p->nVars);
|
||||
for ( k = 0; k < p->LutMask; k++ )
|
||||
{
|
||||
if ( cadical_solver_get_var_value(p->pSat, iVarStart + k) )
|
||||
{
|
||||
int bit = k + 1; // minterm index (minterm 0 is fixed to 0)
|
||||
int w = bit >> 6;
|
||||
int b = bit & 63;
|
||||
Truth[w] |= ((word)1 << b);
|
||||
}
|
||||
}
|
||||
// complement the output fully if needed (including minterm 0)
|
||||
if ( i == p->nObjs - 1 && fCompl )
|
||||
{
|
||||
for ( int w = 0; w < nWordsNode; w++ )
|
||||
{
|
||||
word Mask;
|
||||
int rem = nMintsNode - w * 64;
|
||||
if ( rem <= 0 )
|
||||
Mask = 0;
|
||||
else if ( rem >= 64 )
|
||||
Mask = ~(word)0;
|
||||
else
|
||||
Mask = (((word)1) << rem) - 1;
|
||||
Truth[w] = (~Truth[w]) & Mask;
|
||||
}
|
||||
}
|
||||
if ( p->nLutSize < 6 )
|
||||
Truth[0] = Abc_Tt6Stretch( Truth[0], p->nLutSize );
|
||||
for ( int w = 0; w < nWordsNode; w++ )
|
||||
Vec_WrdWriteEntry( vTruths, i * nWordsNode + w, Truth[w] );
|
||||
}
|
||||
return vTruths;
|
||||
}
|
||||
static void Exa7_ManPrintPerm( Exa7_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 = Exa7_ManFindFanin( p, i, k );
|
||||
if ( iVar >= 0 && iVar < p->nVars )
|
||||
printf( "%c", 'a'+iVar );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
@ -585,7 +659,7 @@ static int Exa7_ManAddCnf( Exa7_Man_t * p, int 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 );
|
||||
//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++ )
|
||||
{
|
||||
|
|
@ -704,22 +778,27 @@ void Exa7_ManPrint( Exa7_Man_t * p, int i, int iMint, abctime clk )
|
|||
}
|
||||
int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars )
|
||||
{
|
||||
extern int Exa7_ManExactSynthesisIter( Bmc_EsPar_t * pPars );
|
||||
if ( pPars->fMinNodes )
|
||||
return Exa7_ManExactSynthesisIter( pPars );
|
||||
int i, status, Res = 0, iMint = 1;
|
||||
abctime clkTotal = Abc_Clock();
|
||||
Exa7_Man_t * p; int fCompl = 0;
|
||||
word pTruth[64];
|
||||
int nTruthWords = Abc_TtWordNum( pPars->nVars );
|
||||
word * pTruth = ABC_CALLOC( word, nTruthWords );
|
||||
assert( pTruth );
|
||||
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 );
|
||||
if ( !pPars->fSilent && pPars->nVars <= 7 ) 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 );
|
||||
assert( pPars->nVars <= 14 );
|
||||
assert( pPars->nLutSize <= 8 );
|
||||
p = Exa7_ManAlloc( pPars, pTruth );
|
||||
if ( pTruth[0] & 1 ) { fCompl = 1; Abc_TtNot( pTruth, p->nWords ); }
|
||||
status = Exa7_ManAddCnfStart( p, pPars->fOnlyAnd );
|
||||
|
|
@ -744,21 +823,88 @@ int Exa7_ManExactSynthesis( Bmc_EsPar_t * pPars )
|
|||
if ( pPars->fVerbose && status != CADICAL_UNDEC )
|
||||
Exa7_ManPrint( p, i, iMint, Abc_Clock() - clkTotal );
|
||||
if ( iMint == -1 )
|
||||
Exa7_ManPrintSolution( p, fCompl ), Res = 1;
|
||||
{
|
||||
Exa7_ManPrintSolution( p, fCompl );
|
||||
printf( "The variable permutation is \"" );
|
||||
Exa7_ManPrintPerm( p );
|
||||
printf( "\".\n" );
|
||||
if ( pPars->fDumpBlif )
|
||||
Exa7_ManDumpBlif( p, fCompl );
|
||||
if ( p->pPars->fGenTruths ) {
|
||||
if ( p->pPars->vTruths )
|
||||
Vec_WrdFreeP( &p->pPars->vTruths );
|
||||
p->pPars->vTruths = Exa7_ManSaveTruthTables( 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 );
|
||||
ABC_FREE( pTruth );
|
||||
return Res;
|
||||
}
|
||||
|
||||
int Exa7_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++ ) {
|
||||
if ( !pPars->fSilent ) printf( "\nTrying M = %d:\n", n );
|
||||
pPars->nNodes = n;
|
||||
if ( !pPars->fUsePerm && 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 );
|
||||
}
|
||||
else if ( pPars->fUsePerm && 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 );
|
||||
}
|
||||
Result = Exa7_ManExactSynthesis(pPars);
|
||||
fflush( stdout );
|
||||
if ( Result == 1 )
|
||||
break;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@
|
|||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
/*========================================================================*/
|
||||
|
||||
// We support semantic versioning (https://semver.org/), which means that we
|
||||
// aim at not breaking API usage when increasing the minor or patch version,
|
||||
// but assume API breaking changes when increasing the major version.
|
||||
|
||||
#define CADICAL_MAJOR 2 // Major semantic version.
|
||||
#define CADICAL_MINOR 2 // Minor semantic version.
|
||||
#define CADICAL_PATCH 0 // Semantic patch version.
|
||||
|
||||
ABC_NAMESPACE_CXX_HEADER_START
|
||||
|
||||
namespace CaDiCaL {
|
||||
|
|
@ -46,7 +56,9 @@ enum Status {
|
|||
// // ------------------------------------------------------------------
|
||||
// // Encode Problem and check without assumptions.
|
||||
//
|
||||
// enum { TIE = 1, SHIRT = 2 };
|
||||
// int TIE = declare_one_more_variable ();
|
||||
// int SHIRT = declare_one_more_variable ();
|
||||
// CADICAL_assert (vars () >= 2);
|
||||
//
|
||||
// solver->add (-TIE), solver->add (SHIRT), solver->add (0);
|
||||
// solver->add (TIE), solver->add (SHIRT), solver->add (0);
|
||||
|
|
@ -220,6 +232,7 @@ class Terminator;
|
|||
class ClauseIterator;
|
||||
class WitnessIterator;
|
||||
class ExternalPropagator;
|
||||
class EquivalenceTracer;
|
||||
class Tracer;
|
||||
struct InternalTracer;
|
||||
class FileTracer;
|
||||
|
|
@ -297,12 +310,22 @@ public:
|
|||
//
|
||||
int solve ();
|
||||
|
||||
// Get value (-lit=false, lit=true) of valid non-zero literal.
|
||||
// Get the value of a valid non-zero literal. This follows the IPASIR
|
||||
// semantics which says to return 'lit' if 'lit' is assigned to 'true' and
|
||||
// '-lit' if 'lit' is assigned to false. This has the consequence that
|
||||
// the returned literal is always assigned to 'true' and thus might be a
|
||||
// bit confusing. To avoid the headache of these semantics (which we
|
||||
// unfortunately should follow to be compatabile with IPASIR) the user can
|
||||
// simply use positive variable indices instead of literals. Then the
|
||||
// returned integer is negative if the variable is assigned to 'false' and
|
||||
// positive it is assigned to 'true'.
|
||||
//
|
||||
// require (SATISFIED)
|
||||
// ensure (SATISFIED)
|
||||
//
|
||||
int val (int lit);
|
||||
int val (
|
||||
int lit,
|
||||
bool use_default_value_for_declared_but_not_used_variable = true);
|
||||
|
||||
// Try to flip the value of the given literal without falsifying the
|
||||
// formula. Returns 'true' if this was successful. Otherwise the model is
|
||||
|
|
@ -361,7 +384,7 @@ public:
|
|||
void connect_terminator (Terminator *terminator);
|
||||
void disconnect_terminator ();
|
||||
|
||||
// Add call-back which allows to export learned clauses.
|
||||
// Add call-back which allows to export_ learned clauses.
|
||||
//
|
||||
// require (VALID)
|
||||
// ensure (VALID)
|
||||
|
|
@ -486,14 +509,17 @@ public:
|
|||
|
||||
// Returns
|
||||
//
|
||||
// 0 = UNKNOWN (unit propagation did not lead to a conflict nor to a
|
||||
// complete assignment, or limit reached or interrupted
|
||||
// through 'terminate')
|
||||
// 0 = UNKNOWN
|
||||
// 10 = SATISFIABLE
|
||||
// 20 = UNSATISFIABLE
|
||||
|
||||
//
|
||||
// The 'UNKNOWN' result means that unit propagation did not lead to a
|
||||
// conflict nor to a complete assignment, or limit reached or interrupted
|
||||
// through 'terminate'.
|
||||
//
|
||||
// require (READY)
|
||||
// ensure (INCONCLUSIVE | SATISFIED | UNSATISFIED)
|
||||
//
|
||||
int propagate ();
|
||||
|
||||
//
|
||||
|
|
@ -502,6 +528,21 @@ public:
|
|||
//
|
||||
void implied (std::vector<int> &implicants);
|
||||
|
||||
// We are not enforcing 'C++14' yet on all compilers/platforms (clang++
|
||||
// and MacOS in particular). The feature check for this warning is
|
||||
// cumbersome to implement and conflicts with other checks for 'C++11'.
|
||||
// After moving to 'C++14' or better 'C++17' we can add this check back
|
||||
// but by then will probably have removed 'get_entrailed_literals' anyhow
|
||||
// (in version '3.0.0').
|
||||
//
|
||||
#if 0
|
||||
[[deprecated ("use the function implied instead with the same semantics "
|
||||
"and arguments")]]
|
||||
#endif
|
||||
void get_entrailed_literals (std::vector<int> &implicants) {
|
||||
implied (implicants);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// This function determines a good splitting literal. The result can be
|
||||
// zero if the formula is proven to be satisfiable or unsatisfiable. This
|
||||
|
|
@ -510,7 +551,7 @@ public:
|
|||
// returned but the state remains steady.
|
||||
//
|
||||
// require (READY)
|
||||
// ensure (INCONCLUSIVE |SATISFIED|UNSATISFIED)
|
||||
// ensure (INCONCLUSIVE | SATISFIED | UNSATISFIED)
|
||||
//
|
||||
int lookahead (void);
|
||||
|
||||
|
|
@ -565,12 +606,15 @@ public:
|
|||
// literal is used as an argument except for the functions 'val', 'fixed',
|
||||
// 'failed' and 'frozen'. However, the library internally keeps a maximum
|
||||
// variable index, which can be queried.
|
||||
//
|
||||
// With factor (BVA) the solver might also add new variables. In that case
|
||||
// the user is required to use this to check which variables are currently
|
||||
// free before adding new variables of their own.
|
||||
// The alternative is to reserve variables in batches with
|
||||
// 'reserve_difference'. Using 'reserve' in combination with any technique
|
||||
// that could add variables (currently only factor) is not advised.
|
||||
// free before adding new variables of their own. The alternative is to
|
||||
// declare more variables in batches with 'declare_more_variables'. Using
|
||||
// 'resize' in combination with any technique that could add variables
|
||||
// (currently only factor) is not advised. After each application of
|
||||
// `add`, `vars ()` will return an updated value, even if you did not
|
||||
// import the entire clause yet.
|
||||
//
|
||||
// require (VALID | SOLVING)
|
||||
// ensure (VALID | SOLVING)
|
||||
|
|
@ -583,21 +627,44 @@ public:
|
|||
// and has the same state transition and conditions as 'assume' etc.
|
||||
//
|
||||
// require (READY)
|
||||
// ensure (STEADY )
|
||||
// ensure (STEADY)
|
||||
//
|
||||
void reserve (int min_max_var);
|
||||
void resize (int min_max_var);
|
||||
|
||||
// We are not enforcing 'C++14' yet on all compilers/platforms (clang++
|
||||
// and MacOS in particular). The feature check for this warning is
|
||||
// cumbersome to implement and conflicts with other checks for 'C++11'.
|
||||
// After moving to 'C++14' or better 'C++17' we can add this check back
|
||||
// but by then will have removed 'reserve' probably anyhow (in '3.0.0').
|
||||
//
|
||||
#if 0
|
||||
[[deprecated ("use the function resize instead with the same semantics "
|
||||
"and arguments.")]]
|
||||
#endif
|
||||
void reserve (int min_max_var) { resize (min_max_var); }
|
||||
|
||||
// Increase the maximum variable index by a number of new variables.
|
||||
// initializes 'number_of_vars' new variables and protects them from
|
||||
// being used by the solver as extension variables (BVA).
|
||||
//
|
||||
// It returns the new maximum variable index which is the highest
|
||||
// variable name of the consecutive range of newly reserved variables.
|
||||
// It has the same state transition and conditions as 'reserve' above.
|
||||
// variable name of the consecutive range of newly delcared variables.
|
||||
// It has the same state transition and conditions as 'resize' above.
|
||||
//
|
||||
// require (READY)
|
||||
// ensure (STEADY )
|
||||
// ensure (STEADY)
|
||||
//
|
||||
int reserve_difference (int number_of_vars);
|
||||
int declare_more_variables (int number_of_additional_new_vars);
|
||||
|
||||
// Increase the maximum variable index by one. This is a specialized
|
||||
// version of declare_more_variables.
|
||||
|
||||
int declare_one_more_variable ();
|
||||
|
||||
// Get the value of some statistics or -1 if the statistics does not
|
||||
// exist or is not support. Only requires the state to be initialized.
|
||||
//
|
||||
int64_t get_statistic_value (const char *const) const;
|
||||
|
||||
#ifndef CADICAL_NTRACING
|
||||
//------------------------------------------------------------------------
|
||||
|
|
@ -694,19 +761,26 @@ public:
|
|||
//
|
||||
void optimize (int val);
|
||||
|
||||
// Specify search limits, where currently 'name' can be "conflicts",
|
||||
// "decisions", "preprocessing", or "localsearch". The first two limits
|
||||
// are unbounded by default. Thus using a negative limit for conflicts or
|
||||
// decisions switches back to the default of unlimited search (for that
|
||||
// particular limit). The preprocessing limit determines the number of
|
||||
// preprocessing rounds, which is zero by default. Similarly, the local
|
||||
// search limit determines the number of local search rounds (also zero by
|
||||
// default). As with 'set', the return value denotes whether the limit
|
||||
// 'name' is valid. These limits are only valid for the next 'solve' or
|
||||
// 'simplify' call and reset to their default after 'solve' returns (as
|
||||
// well as overwritten and reset during calls to 'simplify' and
|
||||
// 'lookahead'). We actually also have an internal "terminate" limit
|
||||
// which however should only be used for testing and debugging.
|
||||
// Specify search limits, where currently 'name' can be
|
||||
//
|
||||
// "conflicts",
|
||||
// "decisions",
|
||||
// "preprocessing", or
|
||||
// "localsearch".
|
||||
//
|
||||
// The first two limits are unbounded by default. Thus using a negative
|
||||
// limit for conflicts or decisions switches back to the default of
|
||||
// unlimited search (for that particular limit). The preprocessing limit
|
||||
// determines the number of preprocessing rounds, which is zero by
|
||||
// default. Similarly, the local search limit determines the number of
|
||||
// local search rounds (zero by default).
|
||||
//
|
||||
// As with 'set', the return value denotes whether the limit 'name' is
|
||||
// valid. These limits are only valid for the next 'solve' or 'simplify'
|
||||
// call and reset to their default after 'solve' returns (as well as
|
||||
// overwritten and reset during calls to 'simplify' and 'lookahead'). We
|
||||
// actually also have an internal "terminate" limit which however should
|
||||
// only be used for testing and debugging.
|
||||
//
|
||||
// require (READY)
|
||||
// ensure (READY)
|
||||
|
|
@ -733,6 +807,7 @@ public:
|
|||
// similar to 'solve' with 'limits ("preprocessing", rounds)' except that
|
||||
// no CDCL nor local search, nor lucky phases are executed. The result
|
||||
// values are also the same: 0=UNKNOWN, 10=SATISFIABLE, 20=UNSATISFIABLE.
|
||||
//
|
||||
// As 'solve' it resets current assumptions and limits before returning.
|
||||
// The numbers of rounds should not be negative. If the number of rounds
|
||||
// is zero only clauses are restored (if necessary) and top level unit
|
||||
|
|
@ -865,18 +940,16 @@ public:
|
|||
void connect_proof_tracer (FileTracer *tracer, bool antecedents,
|
||||
bool finalize_clauses = false);
|
||||
|
||||
// Triggers the conclusion of incremental proofs.
|
||||
// if the solver is SATISFIED it will trigger extend ()
|
||||
// and give the model to the proof tracer through conclude_sat ()
|
||||
// if the solver is UNSATISFIED it will trigger failing ()
|
||||
// which will learn new clauses as explained below:
|
||||
// In case of failed assumptions will provide a core negated
|
||||
// as a clause through the proof tracer interface.
|
||||
// With a failing constraint these can be multiple clauses.
|
||||
// Then it will trigger a conclude_unsat event with the id(s)
|
||||
// of the newly learnt clauses or the id of the global conflict.
|
||||
// In case the solver is in UNKNOWN, it will collect the currently
|
||||
// entrailed literals and add them to the proof.
|
||||
// Triggers the conclusion of incremental proofs. If the solver is
|
||||
// 'SATISFIED' it will trigger 'extend ()' and give the model to the proof
|
||||
// tracer through 'conclude_sat ()' if the solver is 'UNSATISFIED' it will
|
||||
// trigger 'failing ()' which will learn new clauses as explained below:
|
||||
// In case of failed assumptions will provide a core negated as a clause
|
||||
// through the proof tracer interface. With a failing constraint these
|
||||
// can be multiple clauses. Then it will trigger a 'conclude_unsat ()'
|
||||
// event with the ids of the newly learnt clauses or the id of the global
|
||||
// conflict. In case the solver is in 'UNKNOWN', it will collect the
|
||||
// currently "entrailed" literals and add them to the proof.
|
||||
//
|
||||
// require (SATISFIED || UNSATISFIED || UNKNOWN)
|
||||
// ensure (SATISFIED || UNSATISFIED || UNKNOWN)
|
||||
|
|
@ -895,20 +968,20 @@ public:
|
|||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
static void usage (); // print usage information for long options
|
||||
static void usage (); // Print usage information for long options.
|
||||
|
||||
static void configurations (); // print configuration usage options
|
||||
static void configurations (); // Print configuration usage options.
|
||||
|
||||
// require (!DELETING)
|
||||
// ensure (!DELETING)
|
||||
//
|
||||
void statistics (); // print statistics
|
||||
void resources (); // print resource usage (time and memory)
|
||||
void statistics (); // Print statistics.
|
||||
void resources (); // Print resource usage (time and memory).
|
||||
|
||||
// require (VALID)
|
||||
// ensure (VALID)
|
||||
//
|
||||
void options (); // print current option and value list
|
||||
void options (); // Print current option and value list.
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Traverse irredundant clauses or the extension stack in reverse order.
|
||||
|
|
@ -991,6 +1064,7 @@ private:
|
|||
|
||||
// The solver is in the state ADDING if either the current clause or the
|
||||
// constraint (or both) is not yet terminated.
|
||||
//
|
||||
bool adding_clause;
|
||||
bool adding_constraint;
|
||||
|
||||
|
|
@ -1002,7 +1076,7 @@ private:
|
|||
// public API of 'External' but hides everything else (except for the some
|
||||
// private functions). It is supposed to make it easier to understand the
|
||||
// API and use the solver through the API.
|
||||
|
||||
//
|
||||
// This approach has the benefit of decoupling this header file from all
|
||||
// internal data structures, which is particularly useful if the rest of
|
||||
// the source is not available. For instance if only a CaDiCaL library is
|
||||
|
|
@ -1046,9 +1120,9 @@ private:
|
|||
// The environment variable is read in the constructor and the trace is
|
||||
// opened for writing and then closed again in the destructor.
|
||||
//
|
||||
// Alternatively one case use 'trace_api_calls'. Both
|
||||
// Alternatively one case use 'trace_api_calls'.
|
||||
//
|
||||
bool close_trace_api_file; // Close file if owned by solver it.
|
||||
bool close_trace_api_file; // Close file if owned by solver.
|
||||
FILE *trace_api_file; // Also acts as flag that we are tracing.
|
||||
|
||||
static bool tracing_api_through_environment;
|
||||
|
|
@ -1057,6 +1131,7 @@ private:
|
|||
|
||||
void trace_api_call (const char *) const;
|
||||
void trace_api_call (const char *, int) const;
|
||||
void trace_api_call (const char *, int, int) const;
|
||||
void trace_api_call (const char *, const char *) const;
|
||||
void trace_api_call (const char *, const char *, int) const;
|
||||
#endif
|
||||
|
|
@ -1094,9 +1169,8 @@ private:
|
|||
#endif
|
||||
#endif
|
||||
|
||||
// This gives warning messages for wrong 'printf' style format string
|
||||
// usage. Apparently (on 'gcc 9' at least) the first argument is 'this'
|
||||
// here.
|
||||
// Gives warning messages for wrong 'printf' style format string usage.
|
||||
// Apparently ('gcc 9' at least) the first argument is 'this' here.
|
||||
//
|
||||
// TODO: support for other compilers (beside 'gcc' and 'clang').
|
||||
|
||||
|
|
@ -1113,12 +1187,12 @@ private:
|
|||
// require (VALID | DELETING)
|
||||
// ensure (VALID | DELETING)
|
||||
//
|
||||
void section (const char *); // print section header
|
||||
void message (const char *, ...) // ordinary message
|
||||
void section (const char *); // Print section header.
|
||||
void message (const char *, ...) // ordinary message.
|
||||
CADICAL_ATTRIBUTE_FORMAT (2, 3);
|
||||
|
||||
void message (); // empty line - only prefix
|
||||
void error (const char *, ...) // produce error message
|
||||
void message (); // Empty line - only prefix.
|
||||
void error (const char *, ...) // Produce error message.
|
||||
CADICAL_ATTRIBUTE_FORMAT (2, 3);
|
||||
|
||||
// Explicit verbose level ('section' and 'message' use '0').
|
||||
|
|
@ -1151,7 +1225,8 @@ private:
|
|||
// ensure (!INITIALIZING)
|
||||
//
|
||||
void dump_cnf ();
|
||||
friend struct DumpCall; // Mobical calls 'dump_cnf' in 'DumpCall::execute'
|
||||
friend struct DumpCall; // Mobical calls 'dump_cnf' in
|
||||
// 'DumpCall::execute ()'.
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -1180,7 +1255,7 @@ public:
|
|||
virtual bool terminate () = 0;
|
||||
};
|
||||
|
||||
// Connected learners which can be used to export learned clauses.
|
||||
// Connected learners which can be used to export_ learned clauses.
|
||||
// The 'learning' can check the size of the learn clause and only if it
|
||||
// returns true then the individual literals of the learned clause are given
|
||||
// to the learn through 'learn' one by one terminated by a zero literal.
|
||||
|
|
@ -1193,7 +1268,7 @@ public:
|
|||
};
|
||||
|
||||
// Connected listener gets notified whenever the truth value of a variable
|
||||
// is fixed (for example during inprocessing or due to some derived unit
|
||||
// is fixed (for example during inprocessing or due to derived unit
|
||||
// clauses).
|
||||
|
||||
class FixedAssignmentListener {
|
||||
|
|
@ -1212,9 +1287,10 @@ public:
|
|||
class ExternalPropagator {
|
||||
|
||||
public:
|
||||
bool is_lazy = false; // lazy propagator only checks complete assignments
|
||||
bool is_lazy = false; // Lazy propagator only checks complete assignments.
|
||||
|
||||
bool are_reasons_forgettable =
|
||||
false; // Reason external clauses can be deleted
|
||||
false; // Reason external clauses can be deleted.
|
||||
|
||||
virtual ~ExternalPropagator () {}
|
||||
|
||||
|
|
@ -1223,8 +1299,22 @@ public:
|
|||
// the call of propagator callbacks and when a driving clause is leading
|
||||
// to an assignment.
|
||||
//
|
||||
// virtual void notify_assignment (int lit, bool is_fixed) = 0;
|
||||
virtual void notify_assignment (const std::vector<int> &lits) = 0;
|
||||
|
||||
// The notification for the assignement follow the standard trail
|
||||
// used in SAT solvers. The assignment is a stack with (possibly
|
||||
// empty) decisions. New assignments are pushed at the end of the
|
||||
// stack. When backtracking, you get the information on how many
|
||||
// decision (called levels in SAT solvers) you have to keep:
|
||||
// new_level mean that all decision and decision and assignments
|
||||
// before decision number new_level are kept, all other (at the end
|
||||
// of stack) are removed.
|
||||
//
|
||||
// In particular, when backtracking to level '0', no decision is left and
|
||||
// all assignment done before the first decision are kept. The number
|
||||
// will always be lower than the number of decisions on the trail, so
|
||||
// backtracking will always have an effect.
|
||||
//
|
||||
virtual void notify_new_decision_level () = 0;
|
||||
virtual void notify_backtrack (size_t new_level) = 0;
|
||||
|
||||
|
|
@ -1236,24 +1326,24 @@ public:
|
|||
virtual bool cb_check_found_model (const std::vector<int> &model) = 0;
|
||||
|
||||
// Ask the external propagator for the next decision literal. If it
|
||||
// returns 0, the solver makes its own choice.
|
||||
// returns '0', the solver makes its own choice.
|
||||
//
|
||||
virtual int cb_decide () { return 0; };
|
||||
|
||||
// Ask the external propagator if there is an external propagation to make
|
||||
// under the current assignment. It returns either a literal to be
|
||||
// propagated or 0, indicating that there is no external propagation under
|
||||
// the current assignment.
|
||||
// propagated or '0', indicating that there is no external propagation
|
||||
// under the current assignment.
|
||||
//
|
||||
virtual int cb_propagate () { return 0; };
|
||||
|
||||
// Ask the external propagator for the reason clause of a previous
|
||||
// external propagation step (done by cb_propagate). The clause must be
|
||||
// added literal-by-literal closed with a 0. Further, the clause must
|
||||
// external propagation step (done by 'cb_propagate ()'). The clause must
|
||||
// be added literal-by-literal closed with a '0'. Further, the clause must
|
||||
// contain the propagated literal.
|
||||
//
|
||||
// The clause will be learned as an Irredundant Non-Forgettable Clause
|
||||
// (see below at 'cb_has_external_clause' more details about it).
|
||||
// (see below at 'cb_has_external_clause ()' more details about it).
|
||||
//
|
||||
virtual int cb_add_reason_clause_lit (int propagated_lit) {
|
||||
(void) propagated_lit;
|
||||
|
|
@ -1263,22 +1353,25 @@ public:
|
|||
// The following two functions are used to add external clauses to the
|
||||
// solver during the CDCL loop. The external clause is added
|
||||
// literal-by-literal and learned by the solver as an irredundant
|
||||
// (original) input clause. The clause can be arbitrary, but if it is
|
||||
// root-satisfied or tautology, the solver will ignore it without learning
|
||||
// it. Root-falsified literals are eagerly removed from the clause.
|
||||
// Falsified clauses trigger conflict analysis, propagating clauses
|
||||
// trigger propagation. In case chrono is 0, the solver backtracks to
|
||||
// propagate the new literal on the right decision level, otherwise it
|
||||
// potentially will be an out-of-order assignment on the current level.
|
||||
// Unit clauses always (unless root-satisfied, see above) trigger
|
||||
// backtracking (independently from the value of the chrono option and
|
||||
// independently from being falsified or satisfied or unassigned) to level
|
||||
// 0. Empty clause (or root falsified clause, see above) makes the problem
|
||||
// unsat and stops the search immediately. A literal 0 must close the
|
||||
// clause.
|
||||
// (original) input clause.
|
||||
//
|
||||
// The external propagator indicates that there is a clause to add.
|
||||
// The parameter of the function allows the user to indicate that how
|
||||
// The clause can be arbitrary, but if it is root-satisfied or tautology,
|
||||
// the solver will ignore it without learning it. Root-falsified literals
|
||||
// are eagerly removed from the clause. Falsified clauses trigger
|
||||
// conflict analysis, propagating clauses trigger propagation. In case
|
||||
// 'chrono' is '0', the solver backtracks to propagate the new literal on
|
||||
// the correct decision level, as otherwise it potentially will be an
|
||||
// out-of-order assignment on the current level.
|
||||
//
|
||||
// Unit clauses always (unless root-satisfied, see above) trigger
|
||||
// backtracking (independently from the value of the 'chrono' option and
|
||||
// independently from being falsified or satisfied or unassigned) to level
|
||||
// '0'. Empty clause (or root falsified clause, see above) makes the
|
||||
// problem 'UNSATISFIABLE' and stops the search immediately. A literal '0'
|
||||
// must close the clause.
|
||||
//
|
||||
// The external propagator indicates that there is a clause to add. The
|
||||
// parameter of the function allows the user to indicate that how
|
||||
// 'forgettable' is the external clause. Forgettable clauses are allowed
|
||||
// to be removed by the SAT solver during clause database reduction.
|
||||
// However, it is up to the solver to decide when actually the clause is
|
||||
|
|
@ -1313,7 +1406,7 @@ public:
|
|||
// a unit literal is frozen. Falsified literals are skipped. If the solver
|
||||
// is inconsistent only the empty clause is traversed.
|
||||
//
|
||||
// If 'clause' returns false traversal aborts early.
|
||||
// If 'clause' returns 'false' traversal aborts early.
|
||||
|
||||
class ClauseIterator {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -238,16 +238,17 @@ int cadical_solver_addvar(cadical_solver* s) {
|
|||
SeeAlso []
|
||||
|
||||
***********************************************************************/
|
||||
void cadical_solver_setnvars(cadical_solver* s,int n) {
|
||||
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);
|
||||
}
|
||||
void cadical_solver_setnvars(cadical_solver* s, int n) {
|
||||
// make sure current number of variables are already fetched
|
||||
// (also allow cases where addvar has been called)
|
||||
assert(s->nVars >= ccadical_vars((CCaDiCaL*)s->p));
|
||||
// invalid to set fewer variables than current
|
||||
assert(s->nVars <= n);
|
||||
// set and resize if appropriate
|
||||
s->nVars = n;
|
||||
if(ccadical_vars((CCaDiCaL*)s->p) == 0) {
|
||||
ccadical_resize((CCaDiCaL*)s->p, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ int Internal::recompute_glue (Clause *c) {
|
|||
int res = 0;
|
||||
const int64_t stamp = ++stats.recomputed;
|
||||
for (const auto &lit : *c) {
|
||||
CADICAL_assert (val (lit));
|
||||
int level = var (lit).level;
|
||||
CADICAL_assert (gtab[level] <= stamp);
|
||||
if (gtab[level] == stamp)
|
||||
|
|
@ -535,7 +536,7 @@ Clause *Internal::new_driving_clause (const int glue, int &jump) {
|
|||
|
||||
jump = var (clause[1]).level;
|
||||
res = new_learned_redundant_clause (glue);
|
||||
res->used = 1 + (glue <= opts.reducetier2glue);
|
||||
res->used = max_used;
|
||||
}
|
||||
|
||||
LOG ("jump level %d", jump);
|
||||
|
|
@ -912,7 +913,7 @@ void Internal::otfs_strengthen_clause (Clause *c, int lit, int new_size,
|
|||
mark_removed (lit);
|
||||
}
|
||||
mini_chain.clear ();
|
||||
c->used = true;
|
||||
c->used = max_used;
|
||||
LOG (c, "strengthened");
|
||||
external->check_shrunken_clause (c);
|
||||
}
|
||||
|
|
@ -1145,6 +1146,26 @@ void Internal::analyze () {
|
|||
|
||||
uip = 0;
|
||||
while (!uip) {
|
||||
if (!i) {
|
||||
lazy_external_propagator_out_of_order_clause (uip);
|
||||
if (unsat)
|
||||
return;
|
||||
else if (uip) {
|
||||
open = 1;
|
||||
break;
|
||||
} else {
|
||||
LOG (reason, "restarting the analysis on the new conflict");
|
||||
++stats.conflicts;
|
||||
reason = conflict;
|
||||
resolvent_size = 0;
|
||||
antecedent_size = 1;
|
||||
resolved = 0;
|
||||
open = 0;
|
||||
analyze_reason (0, reason, open, resolvent_size, antecedent_size);
|
||||
conflict_size = antecedent_size - 1;
|
||||
CADICAL_assert (open > 1);
|
||||
}
|
||||
}
|
||||
CADICAL_assert (i > 0);
|
||||
const int lit = (*t)[--i];
|
||||
if (!flags (lit).seen)
|
||||
|
|
@ -1270,6 +1291,64 @@ void Internal::analyze () {
|
|||
recompute_tier ();
|
||||
}
|
||||
|
||||
// In the special case where the external propagator is lazy, the same
|
||||
// invariants as OTFS break (but even more complicated). There are three
|
||||
// possible cases:
|
||||
// - the clause becomes empty (unsat must be answered)
|
||||
// - the clause is a unit (backtrack and set the clause)
|
||||
// - the clause is a new conflict on lower level and we restart the
|
||||
// analysis
|
||||
//
|
||||
// TODO: we do not really need to keep the clause longer than the conflict
|
||||
// analysis.
|
||||
void Internal::lazy_external_propagator_out_of_order_clause (int &uip) {
|
||||
CADICAL_assert (!opts.exteagerreasons);
|
||||
CADICAL_assert (external_prop);
|
||||
LOG (clause, "out-of-order conflict");
|
||||
if (clause.empty ()) {
|
||||
LOG (lrat_chain, "lrat_chain:");
|
||||
LOG (clause, "clause:");
|
||||
LOG (unit_chain, "units:");
|
||||
if (lrat) {
|
||||
LOG (unit_chain, "unit chain: ");
|
||||
for (auto id : unit_chain)
|
||||
lrat_chain.push_back (id);
|
||||
unit_chain.clear ();
|
||||
reverse (lrat_chain.begin (), lrat_chain.end ());
|
||||
}
|
||||
LOG (lrat_chain, "lrat_chain:");
|
||||
learn_empty_clause ();
|
||||
if (external->learner)
|
||||
external->export_learned_empty_clause ();
|
||||
conflict = 0;
|
||||
} else if (clause.size () == 1) {
|
||||
LOG ("found out-of-order unit");
|
||||
uip = -clause[0];
|
||||
CADICAL_assert (uip);
|
||||
backtrack (var (uip).level);
|
||||
CADICAL_assert (val (uip) > 0);
|
||||
clause.clear ();
|
||||
} else {
|
||||
int jump;
|
||||
const int glue = clause.size () - 1;
|
||||
conflict = new_driving_clause (glue, jump);
|
||||
UPDATE_AVERAGE (averages.current.level, jump);
|
||||
backtrack (jump);
|
||||
LOG (conflict, "new conflict");
|
||||
}
|
||||
// Clean up.
|
||||
//
|
||||
clear_analyzed_literals ();
|
||||
clear_unit_analyzed_literals ();
|
||||
clear_analyzed_levels ();
|
||||
clause.clear ();
|
||||
|
||||
if (unsat) {
|
||||
lrat_chain.clear ();
|
||||
STOP (analyze);
|
||||
}
|
||||
}
|
||||
|
||||
// We wait reporting a learned unit until propagation of that unit is
|
||||
// completed. Otherwise the 'i' report gives the number of remaining
|
||||
// variables before propagating the unit (and hides the actual remaining
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace CaDiCaL {
|
|||
// adds an assumption literal onto the assumption stack.
|
||||
|
||||
void Internal::assume (int lit) {
|
||||
if (level && !opts.ilbassumptions)
|
||||
if (level && !opts.ilb)
|
||||
backtrack ();
|
||||
else if (val (lit) < 0)
|
||||
backtrack (max (0, var (lit).level - 1));
|
||||
|
|
@ -552,9 +552,16 @@ struct sort_assumptions_smaller {
|
|||
// to the first place where the assumptions and the current trail differ.
|
||||
|
||||
void Internal::sort_and_reuse_assumptions () {
|
||||
CADICAL_assert (opts.ilbassumptions);
|
||||
if (assumptions.empty ())
|
||||
return;
|
||||
CADICAL_assert (opts.ilb >= 1);
|
||||
if (assumptions.empty ()) {
|
||||
if (opts.ilb == 1) {
|
||||
LOG ("no assumptions, reusing nothing (ilb == 1)");
|
||||
backtrack (0);
|
||||
} else { // reuse full trail
|
||||
LOG ("no assumptions, reusing everything (ilb == 2)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
MSORT (opts.radixsortlim, assumptions.begin (), assumptions.end (),
|
||||
sort_assumptions_positive_rank (this),
|
||||
sort_assumptions_smaller (this));
|
||||
|
|
@ -599,10 +606,12 @@ void Internal::sort_and_reuse_assumptions () {
|
|||
lit, alit);
|
||||
break;
|
||||
}
|
||||
if (opts.ilb == 1 &&
|
||||
(size_t) target > assumptions.size ()) // reusing only assumptions
|
||||
target = assumptions.size ();
|
||||
if (target < level)
|
||||
backtrack (target);
|
||||
backtrack_without_updating_phases (target);
|
||||
LOG ("assumptions allow for reuse of trail up to level %d", level);
|
||||
// COVER (target > 1);
|
||||
if ((size_t) level > assumptions.size ())
|
||||
stats.assumptionsreused += assumptions.size ();
|
||||
else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,637 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "internal.hpp"
|
||||
#include "message.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
namespace CaDiCaL {
|
||||
|
||||
inline void Internal::backbone_lrat_for_units (int lit, Clause *reason) {
|
||||
if (!lrat)
|
||||
return;
|
||||
if (level)
|
||||
return; // not decision level 0
|
||||
LOG ("backbone building chain for units");
|
||||
CADICAL_assert (lrat_chain.empty ());
|
||||
CADICAL_assert (reason);
|
||||
for (auto &reason_lit : *reason) {
|
||||
if (lit == reason_lit)
|
||||
continue;
|
||||
CADICAL_assert (val (reason_lit));
|
||||
if (!val (reason_lit))
|
||||
continue;
|
||||
const int signed_reason_lit = val (reason_lit) * reason_lit;
|
||||
int64_t id = unit_id (signed_reason_lit);
|
||||
lrat_chain.push_back (id);
|
||||
}
|
||||
lrat_chain.push_back (reason->id);
|
||||
}
|
||||
|
||||
inline bool Internal::backbone_propagate (int64_t &ticks) {
|
||||
require_mode (BACKBONE);
|
||||
CADICAL_assert (!unsat);
|
||||
START (propagate);
|
||||
int64_t before = propagated2 = propagated;
|
||||
for (;;) {
|
||||
if (propagated2 != trail.size ()) {
|
||||
const int lit = -trail[propagated2++];
|
||||
LOG ("backbone propagating %d over binary clauses", -lit);
|
||||
Watches &ws = watches (lit);
|
||||
ticks +=
|
||||
1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
|
||||
for (const auto &w : ws) {
|
||||
if (!w.binary ())
|
||||
continue;
|
||||
const signed char b = val (w.blit);
|
||||
if (b > 0)
|
||||
continue;
|
||||
if (b < 0)
|
||||
conflict = w.clause; // but continue
|
||||
else {
|
||||
ticks++;
|
||||
build_chain_for_units (w.blit, w.clause, 0);
|
||||
backbone_assign (w.blit, w.clause);
|
||||
lrat_chain.clear ();
|
||||
}
|
||||
}
|
||||
} else if (!conflict && propagated != trail.size ()) {
|
||||
const int lit = -trail[propagated++];
|
||||
LOG ("backbone propagating %d over large clauses", -lit);
|
||||
Watches &ws = watches (lit);
|
||||
const const_watch_iterator eow = ws.end ();
|
||||
const_watch_iterator i = ws.begin ();
|
||||
ticks += 1 + cache_lines (ws.size (), sizeof (*i));
|
||||
watch_iterator j = ws.begin ();
|
||||
while (i != eow) {
|
||||
const Watch w = *j++ = *i++;
|
||||
if (w.binary ())
|
||||
continue;
|
||||
if (val (w.blit) > 0)
|
||||
continue;
|
||||
ticks++;
|
||||
if (w.clause->garbage) {
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
literal_iterator lits = w.clause->begin ();
|
||||
const int other = lits[0] ^ lits[1] ^ lit;
|
||||
const signed char u = val (other);
|
||||
if (u > 0)
|
||||
j[-1].blit = other;
|
||||
else {
|
||||
const int size = w.clause->size;
|
||||
const const_literal_iterator end = lits + size;
|
||||
const literal_iterator middle = lits + w.clause->pos;
|
||||
literal_iterator k = middle;
|
||||
signed char v = -1;
|
||||
int r = 0;
|
||||
while (k != end && (v = val (r = *k)) < 0)
|
||||
k++;
|
||||
if (v < 0) {
|
||||
k = lits + 2;
|
||||
CADICAL_assert (w.clause->pos <= size);
|
||||
while (k != middle && (v = val (r = *k)) < 0)
|
||||
k++;
|
||||
}
|
||||
w.clause->pos = k - lits;
|
||||
CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ());
|
||||
if (v > 0)
|
||||
j[-1].blit = r;
|
||||
else if (!v) {
|
||||
LOG (w.clause, "unwatch %d in", r);
|
||||
lits[0] = other;
|
||||
lits[1] = r;
|
||||
*k = lit;
|
||||
ticks++;
|
||||
watch_literal (r, lit, w.clause);
|
||||
j--;
|
||||
} else if (!u) {
|
||||
ticks++;
|
||||
CADICAL_assert (v < 0);
|
||||
build_chain_for_units (other, w.clause, 0);
|
||||
backbone_assign_any (other, w.clause);
|
||||
lrat_chain.clear ();
|
||||
} else {
|
||||
if (w.clause == ignore) {
|
||||
LOG ("ignoring conflict due to clause to vivify");
|
||||
continue;
|
||||
}
|
||||
CADICAL_assert (u < 0);
|
||||
CADICAL_assert (v < 0);
|
||||
conflict = w.clause;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j != i) {
|
||||
while (i != eow)
|
||||
*j++ = *i++;
|
||||
ws.resize (j - ws.begin ());
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
int64_t delta = propagated2 - before;
|
||||
stats.propagations.backbone += delta;
|
||||
if (conflict)
|
||||
LOG (conflict, "conflict");
|
||||
STOP (propagate);
|
||||
return !conflict;
|
||||
}
|
||||
|
||||
inline void Internal::backbone_propagate2 (int64_t &ticks) {
|
||||
require_mode (BACKBONE);
|
||||
CADICAL_assert (propagated2 <= trail.size ());
|
||||
int64_t before = propagated2;
|
||||
while (propagated2 != trail.size ()) {
|
||||
const int lit = -trail[propagated2++];
|
||||
LOG ("probe propagating %d over binary clauses", -lit);
|
||||
Watches &ws = watches (lit);
|
||||
ticks += 1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
|
||||
for (const auto &w : ws) {
|
||||
if (!w.binary ())
|
||||
break;
|
||||
const signed char b = val (w.blit);
|
||||
if (b > 0)
|
||||
continue;
|
||||
ticks++;
|
||||
if (b < 0) {
|
||||
conflict = w.clause; // no need to continue
|
||||
break;
|
||||
} else {
|
||||
CADICAL_assert (lrat_chain.empty ());
|
||||
backbone_lrat_for_units (w.blit, w.clause);
|
||||
backbone_assign (w.blit, w.clause);
|
||||
lrat_chain.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int64_t delta = propagated2 - before;
|
||||
stats.propagations.backbone += delta;
|
||||
}
|
||||
|
||||
void Internal::schedule_backbone_cands (std::vector<int> &candidates) {
|
||||
|
||||
unsigned not_rescheduled = 0;
|
||||
for (auto v : vars) {
|
||||
const Flags f = flags (v);
|
||||
if (!f.active ())
|
||||
continue;
|
||||
if (f.backbone0) {
|
||||
LOG ("scheduling backbone literal candidate %s", LOGLIT (v));
|
||||
candidates.push_back (v);
|
||||
} else
|
||||
++not_rescheduled;
|
||||
if (f.backbone1) {
|
||||
LOG ("scheduling backbone literal candidate %s", LOGLIT (-v));
|
||||
candidates.push_back (-v);
|
||||
} else
|
||||
++not_rescheduled;
|
||||
}
|
||||
|
||||
if (not_rescheduled) {
|
||||
for (auto v : vars) {
|
||||
const Flags f = flags (v);
|
||||
if (!f.active ())
|
||||
continue;
|
||||
if (!f.backbone0) {
|
||||
LOG ("scheduling backbone literal candidate %s", LOGLIT (v));
|
||||
candidates.push_back (v);
|
||||
}
|
||||
if (!f.backbone1) {
|
||||
LOG ("scheduling backbone literal candidate %s", LOGLIT (-v));
|
||||
candidates.push_back (-v);
|
||||
}
|
||||
}
|
||||
}
|
||||
CADICAL_assert (candidates.size () <= 2 * (size_t) max_var);
|
||||
|
||||
VERBOSE (3,
|
||||
"backbone schedule %zu backbone candidates in total %f "
|
||||
"(rescheduled: %f%%)",
|
||||
candidates.size (), percent (candidates.size (), 2 * max_var),
|
||||
percent (not_rescheduled, 2 * max_var));
|
||||
}
|
||||
|
||||
int Internal::backbone_analyze (Clause *, int64_t &ticks) {
|
||||
CADICAL_assert (conflict);
|
||||
CADICAL_assert (conflict->size == 2);
|
||||
analyzed.push_back (std::abs (conflict->literals[0]));
|
||||
flags (conflict->literals[0]).seen = true;
|
||||
analyzed.push_back (std::abs (conflict->literals[1]));
|
||||
flags (conflict->literals[1]).seen = true;
|
||||
LOG (conflict, "analyzing conflict");
|
||||
if (lrat)
|
||||
lrat_chain.push_back (conflict->id);
|
||||
conflict = nullptr;
|
||||
|
||||
for (auto t = trail.rbegin ();;) {
|
||||
CADICAL_assert (t < trail.rend ());
|
||||
int lit = *t++;
|
||||
LOG ("analyzing %s", LOGLIT (lit));
|
||||
if (!flags (lit).seen)
|
||||
continue;
|
||||
Clause *reason = var (lit).reason;
|
||||
LOG (reason, "resolving with reason of %s", LOGLIT (lit));
|
||||
CADICAL_assert (reason), CADICAL_assert (reason != decision_reason);
|
||||
++ticks;
|
||||
const int other = reason->literals[0] ^ reason->literals[1] ^ lit;
|
||||
Flags &f_o = flags (other);
|
||||
if (lrat)
|
||||
lrat_chain.push_back (reason->id);
|
||||
if (!f_o.seen) {
|
||||
f_o.seen = true;
|
||||
analyzed.push_back (other);
|
||||
} else {
|
||||
LOG ("backbone UIP %s", LOGLIT (other));
|
||||
for (auto lit : analyzed)
|
||||
flags (lit).seen = false;
|
||||
analyzed.clear ();
|
||||
if (lrat)
|
||||
reverse (begin (lrat_chain), end (lrat_chain));
|
||||
return other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Internal::backbone_unit_reassign (int lit) {
|
||||
#ifdef LOGGING
|
||||
LOG ("reassigning %s to level 0", LOGLIT (lit));
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
CADICAL_assert (val (-lit) < 0);
|
||||
#else
|
||||
(void) lit;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
inline void Internal::backbone_unit_assign (int lit) {
|
||||
LOG ("assigning %s to level 0", LOGLIT (lit));
|
||||
require_mode (BACKBONE);
|
||||
const int idx = vidx (lit);
|
||||
CADICAL_assert (!vals[idx]);
|
||||
Var &v = var (idx);
|
||||
v.level = 0; // required to reuse decisions
|
||||
v.trail = (int) trail.size (); // used in 'vivify_better_watch'
|
||||
CADICAL_assert ((int) num_assigned < max_var);
|
||||
num_assigned++;
|
||||
v.reason = 0; // for conflict analysis
|
||||
learn_unit_clause (lit);
|
||||
lrat_chain.clear ();
|
||||
const signed char tmp = sign (lit);
|
||||
vals[idx] = tmp;
|
||||
vals[-idx] = -tmp;
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
CADICAL_assert (val (-lit) < 0);
|
||||
trail.push_back (lit);
|
||||
LOG ("backbone assign %d to level 0", lit);
|
||||
}
|
||||
|
||||
inline void Internal::backbone_assign_any (int lit, Clause *reason) {
|
||||
require_mode (BACKBONE);
|
||||
const int idx = vidx (lit);
|
||||
CADICAL_assert (!vals[idx]);
|
||||
CADICAL_assert (!flags (idx).eliminated () || !reason);
|
||||
CADICAL_assert (reason == decision_reason || !reason || reason->size >= 2);
|
||||
Var &v = var (idx);
|
||||
v.level = level; // required to reuse decisions
|
||||
v.trail = (int) trail.size (); // used in 'vivify_better_watch'
|
||||
CADICAL_assert ((int) num_assigned < max_var);
|
||||
num_assigned++;
|
||||
v.reason = level ? reason : 0; // for conflict analysis
|
||||
if (!level)
|
||||
learn_unit_clause (lit);
|
||||
const signed char tmp = sign (lit);
|
||||
vals[idx] = tmp;
|
||||
vals[-idx] = -tmp;
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
CADICAL_assert (val (-lit) < 0);
|
||||
trail.push_back (lit);
|
||||
LOG (reason, "backbone assign %d", lit);
|
||||
}
|
||||
|
||||
inline void Internal::backbone_assign (int lit, Clause *reason) {
|
||||
require_mode (BACKBONE);
|
||||
const int idx = vidx (lit);
|
||||
CADICAL_assert (!vals[idx]);
|
||||
CADICAL_assert (!flags (idx).eliminated () || !reason);
|
||||
CADICAL_assert (reason == decision_reason || !reason || reason->size == 2);
|
||||
Var &v = var (idx);
|
||||
v.level = level; // required to reuse decisions
|
||||
v.trail = (int) trail.size (); // used in 'vivify_better_watch'
|
||||
CADICAL_assert ((int) num_assigned < max_var);
|
||||
num_assigned++;
|
||||
v.reason = level ? reason : 0; // for conflict analysis
|
||||
if (!level)
|
||||
learn_unit_clause (lit);
|
||||
const signed char tmp = sign (lit);
|
||||
vals[idx] = tmp;
|
||||
vals[-idx] = -tmp;
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
CADICAL_assert (val (-lit) < 0);
|
||||
trail.push_back (lit);
|
||||
LOG (reason, "backbone assign %d", lit);
|
||||
}
|
||||
|
||||
void Internal::backbone_decision (int lit) {
|
||||
require_mode (BACKBONE);
|
||||
CADICAL_assert (propagated2 == trail.size ());
|
||||
new_trail_level (lit);
|
||||
notify_decision ();
|
||||
LOG ("search decide %d", lit);
|
||||
backbone_assign (lit, decision_reason);
|
||||
}
|
||||
|
||||
unsigned Internal::compute_backbone_round (std::vector<int> &candidates,
|
||||
std::vector<int> &units,
|
||||
const int64_t ticks_limit,
|
||||
int64_t &ticks,
|
||||
unsigned inconsistent) {
|
||||
CADICAL_assert (!conflict);
|
||||
auto p = begin (candidates);
|
||||
auto q = p;
|
||||
const auto end = std::end (candidates);
|
||||
size_t failed = 0;
|
||||
++stats.backbone.rounds;
|
||||
|
||||
LOG (candidates, "candidates: ");
|
||||
ticks += 1 + cache_lines (candidates.size (),
|
||||
sizeof (std::vector<int>::iterator *));
|
||||
while (p != end) {
|
||||
CADICAL_assert (p < end);
|
||||
CADICAL_assert (q <= p);
|
||||
CADICAL_assert (!conflict);
|
||||
const int probe = (*q = *p);
|
||||
++stats.backbone.probes;
|
||||
|
||||
++p, ++q;
|
||||
const signed char v = val (probe);
|
||||
if (v > 0) {
|
||||
q--;
|
||||
LOG ("removing satisfied backbone probe %s", LOGLIT (probe));
|
||||
if (probe < 0)
|
||||
flags (probe).backbone1 = false;
|
||||
else
|
||||
flags (probe).backbone0 = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v < 0) {
|
||||
if (var (probe).level)
|
||||
LOG ("skipping falsified backbone probe %s", LOGLIT (probe));
|
||||
else {
|
||||
LOG ("removing root-level falsified backbone probe %s",
|
||||
LOGLIT (probe));
|
||||
q--;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ticks >= ticks_limit)
|
||||
break;
|
||||
backbone_decision (probe);
|
||||
backbone_propagate2 (ticks);
|
||||
if (!conflict) {
|
||||
LOG (candidates,
|
||||
"propagating backbone probe %s successful; candidates:",
|
||||
LOGLIT (probe));
|
||||
continue;
|
||||
}
|
||||
|
||||
++failed;
|
||||
++stats.backbone.units;
|
||||
int uip = backbone_analyze (conflict, ticks);
|
||||
backtrack_without_updating_phases (level - 1);
|
||||
backbone_unit_assign (uip);
|
||||
++stats.units;
|
||||
CADICAL_assert (!conflict);
|
||||
if (external->learner)
|
||||
external->export_learned_unit_clause (uip);
|
||||
|
||||
backbone_propagate2 (ticks);
|
||||
if (conflict) {
|
||||
LOG ("propagating backbone forced %s failed", LOGLIT (uip));
|
||||
inconsistent = uip;
|
||||
// we have to give up on the current conflict
|
||||
conflict = nullptr;
|
||||
break;
|
||||
}
|
||||
units.push_back (uip);
|
||||
}
|
||||
while (p != end)
|
||||
*q++ = *p++;
|
||||
CADICAL_assert (q <= end);
|
||||
candidates.resize (q - begin (candidates));
|
||||
LOG (candidates, "candidates: ");
|
||||
|
||||
if (!inconsistent) {
|
||||
LOG ("flushing satisfied probe candidates");
|
||||
auto p = begin (candidates);
|
||||
auto q = p;
|
||||
const auto end = std::end (candidates);
|
||||
|
||||
while (p != end) {
|
||||
const int probe = (*q++ = *p++);
|
||||
const signed char v = val (probe);
|
||||
if (v > 0) {
|
||||
q--;
|
||||
LOG ("removing satisfied backbone probe %s", LOGLIT (probe));
|
||||
if (probe < 0)
|
||||
flags (probe).backbone1 = false;
|
||||
else
|
||||
flags (probe).backbone0 = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v < 0) {
|
||||
LOG ("keeping falsified probe %s", LOGLIT (probe));
|
||||
continue;
|
||||
}
|
||||
CADICAL_assert (!v);
|
||||
LOG ("keeping unassigned probe %s", LOGLIT (probe));
|
||||
}
|
||||
candidates.resize (q - begin (candidates));
|
||||
}
|
||||
LOG (candidates, "candidates after !inconsistent: ");
|
||||
if (level)
|
||||
backtrack_without_updating_phases ();
|
||||
if (!inconsistent && !units.empty ()) {
|
||||
for (auto l : units) {
|
||||
backbone_unit_reassign (l);
|
||||
}
|
||||
units.clear ();
|
||||
if (!backbone_propagate (ticks)) {
|
||||
LOG (conflict, "final repropagation yielded conflict");
|
||||
learn_empty_clause ();
|
||||
}
|
||||
} else {
|
||||
if (!backbone_propagate (ticks)) {
|
||||
learn_empty_clause ();
|
||||
}
|
||||
}
|
||||
LOG (candidates, "candidates end of loop: ");
|
||||
|
||||
LOG (candidates, "candidates end of backbone_round: ");
|
||||
return failed;
|
||||
}
|
||||
|
||||
void Internal::keep_backbone_candidates (
|
||||
const std::vector<int> &candidates) {
|
||||
size_t remain = 0;
|
||||
size_t prioritized = 0;
|
||||
for (auto v : candidates) {
|
||||
const Flags &f = flags (v);
|
||||
if (!f.active ())
|
||||
continue;
|
||||
++remain;
|
||||
if (v < 0)
|
||||
prioritized += f.backbone1;
|
||||
else
|
||||
prioritized += f.backbone0;
|
||||
}
|
||||
CADICAL_assert (prioritized <= remain);
|
||||
if (!remain) {
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto v : candidates) {
|
||||
const Flags &f = flags (v);
|
||||
if (!f.active ())
|
||||
continue;
|
||||
CADICAL_assert (!f.backbone0);
|
||||
CADICAL_assert (!f.backbone1);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (prioritized == remain) {
|
||||
LOG ("keeping all remaining backbones");
|
||||
} else if (!prioritized) {
|
||||
for (auto v : candidates) {
|
||||
Flags &f = flags (v);
|
||||
if (!f.active ())
|
||||
continue;
|
||||
++remain;
|
||||
if (v < 0) {
|
||||
CADICAL_assert (!f.backbone1);
|
||||
f.backbone1 = true;
|
||||
} else {
|
||||
CADICAL_assert (!f.backbone0);
|
||||
f.backbone0 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Internal::compute_backbone () {
|
||||
size_t failed = 0;
|
||||
|
||||
int64_t ticks = 0;
|
||||
backbone_propagate2 (ticks);
|
||||
CADICAL_assert (!conflict);
|
||||
|
||||
std::vector<int> candidates, units;
|
||||
unsigned inconsistent = 0;
|
||||
CADICAL_assert (!conflict);
|
||||
|
||||
++stats.backbone.phases;
|
||||
schedule_backbone_cands (candidates);
|
||||
|
||||
const size_t max_rounds = opts.backbonemaxrounds;
|
||||
size_t round_limit = opts.backbonerounds;
|
||||
round_limit *= stats.backbone.phases;
|
||||
if (round_limit > max_rounds)
|
||||
round_limit = max_rounds;
|
||||
|
||||
SET_EFFORT_LIMIT (totalticks, backbone, false);
|
||||
int64_t ticks_limit = totalticks - stats.ticks.backbone;
|
||||
PHASE ("backbone", stats.backbone.phases,
|
||||
"backbone limit of %" PRId64 " ticks", ticks_limit);
|
||||
size_t rounds = 0;
|
||||
for (; ++rounds;) {
|
||||
if (rounds >= round_limit) {
|
||||
LOG ("backround round limit %zu rounds", rounds);
|
||||
break;
|
||||
}
|
||||
if (ticks >= ticks_limit) {
|
||||
LOG ("backround round limit %" PRIu64 " ticks", ticks);
|
||||
break;
|
||||
}
|
||||
VERBOSE (3,
|
||||
"backbone round %zu of %zu with %" PRId64
|
||||
" ticks (%f %% done) with %zu failed so far",
|
||||
rounds, max_rounds, ticks, percent (ticks, ticks_limit),
|
||||
failed);
|
||||
size_t new_failed = compute_backbone_round (
|
||||
candidates, units, ticks_limit, ticks, inconsistent);
|
||||
failed += new_failed;
|
||||
if (inconsistent)
|
||||
break;
|
||||
if (candidates.empty ())
|
||||
break;
|
||||
if (unsat)
|
||||
break;
|
||||
}
|
||||
|
||||
if (inconsistent && !unsat) {
|
||||
LOG ("using forced unit %s by repropagating at level 0",
|
||||
LOGLIT (inconsistent));
|
||||
backtrack_without_updating_phases ();
|
||||
propagate ();
|
||||
learn_empty_clause ();
|
||||
}
|
||||
if (unsat) {
|
||||
PHASE ("backbone", stats.backbone.phases,
|
||||
"inconsistent binary clauses");
|
||||
} else {
|
||||
PHASE ("backbone", stats.backbone.phases,
|
||||
"found %zu backbone literals %zu round in %" PRId64 " ticks",
|
||||
failed, rounds, ticks);
|
||||
}
|
||||
|
||||
keep_backbone_candidates (candidates);
|
||||
if (level) {
|
||||
backtrack_without_updating_phases ();
|
||||
if (!backbone_propagate (ticks)) {
|
||||
learn_empty_clause ();
|
||||
}
|
||||
}
|
||||
stats.ticks.backbone += ticks;
|
||||
return failed;
|
||||
}
|
||||
|
||||
void Internal::binary_clauses_backbone () {
|
||||
if (unsat)
|
||||
return;
|
||||
if (!opts.backbone)
|
||||
return;
|
||||
if (level)
|
||||
backtrack_without_updating_phases ();
|
||||
propagated2 = 0; // TODO: why?
|
||||
if (!propagate ()) {
|
||||
LOG ("propagation after connecting watches in inconsistency");
|
||||
learn_empty_clause ();
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto lit : lits) {
|
||||
Watches &w = watches (lit);
|
||||
std::stable_partition (begin (w), end (w),
|
||||
[] (Watch w) { return w.binary (); });
|
||||
}
|
||||
CADICAL_assert (propagated2 <= trail.size ());
|
||||
private_steps = true;
|
||||
|
||||
CADICAL_assert (watching ());
|
||||
START_SIMPLIFIER (backbone, BACKBONE);
|
||||
int failed = compute_backbone ();
|
||||
CADICAL_assert (!level);
|
||||
private_steps = false;
|
||||
|
||||
report ('k', !failed);
|
||||
STOP_SIMPLIFIER (backbone, BACKBONE);
|
||||
}
|
||||
|
||||
} // namespace CaDiCaL
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -49,6 +49,9 @@ inline void Internal::unassign (int lit) {
|
|||
|
||||
void Internal::update_target_and_best () {
|
||||
|
||||
if (opts.rephase == 2 && !stable)
|
||||
return;
|
||||
|
||||
bool reset = (rephased && stats.conflicts > last.rephase.conflicts);
|
||||
|
||||
if (reset) {
|
||||
|
|
@ -131,7 +134,8 @@ void Internal::backtrack_without_updating_phases (int new_level) {
|
|||
// backtracking. It is possible to just keep out-of-order assigned
|
||||
// literals on the trail without breaking the solver (after some
|
||||
// modifications to 'analyze' - see 'opts.chrono' guarded code there).
|
||||
CADICAL_assert (opts.chrono || external_prop || did_external_prop);
|
||||
CADICAL_assert ((in_mode (BACKBONE)) || opts.chrono || external_prop ||
|
||||
did_external_prop);
|
||||
#ifdef LOGGING
|
||||
if (!v.level)
|
||||
LOG ("reassign %d @ 0 unit clause %d", lit, lit);
|
||||
|
|
|
|||
|
|
@ -196,12 +196,24 @@ int ccadical_vars (CCaDiCaL *ptr) {
|
|||
return ((Wrapper *) ptr)->solver->vars ();
|
||||
}
|
||||
|
||||
int ccadical_reserve_difference (CCaDiCaL *ptr, int number_of_vars) {
|
||||
return ((Wrapper *) ptr)->solver->reserve_difference (number_of_vars);
|
||||
int ccadical_declare_more_variables (CCaDiCaL *ptr, int number_of_vars) {
|
||||
return ((Wrapper *) ptr)->solver->declare_more_variables (number_of_vars);
|
||||
}
|
||||
|
||||
void ccadical_reserve(CCaDiCaL *ptr, int min_max_var) {
|
||||
((Wrapper *) ptr)->solver->reserve(min_max_var);
|
||||
int ccadical_declare_one_more_variable (CCaDiCaL *ptr) {
|
||||
return ((Wrapper *) ptr)->solver->declare_one_more_variable ();
|
||||
}
|
||||
|
||||
void ccadical_phase (CCaDiCaL *wrapper, int lit) {
|
||||
((Wrapper *) wrapper)->solver->phase (lit);
|
||||
}
|
||||
|
||||
void ccadical_unphase (CCaDiCaL *wrapper, int lit) {
|
||||
((Wrapper *) wrapper)->solver->unphase (lit);
|
||||
}
|
||||
|
||||
void ccadical_resize(CCaDiCaL *ptr, int min_max_var) {
|
||||
((Wrapper *) ptr)->solver->resize(min_max_var);
|
||||
}
|
||||
|
||||
int ccadical_is_inconsistent(CCaDiCaL *ptr) {
|
||||
|
|
|
|||
|
|
@ -561,7 +561,8 @@ void Checker::add_original_clause (int64_t id, bool, const vector<int> &c,
|
|||
STOP (checking);
|
||||
}
|
||||
|
||||
void Checker::add_derived_clause (int64_t id, bool, const vector<int> &c,
|
||||
void Checker::add_derived_clause (int64_t id, bool, int,
|
||||
const vector<int> &c,
|
||||
const vector<int64_t> &) {
|
||||
if (inconsistent)
|
||||
return;
|
||||
|
|
@ -627,7 +628,7 @@ void Checker::delete_clause (int64_t id, bool, const vector<int> &c) {
|
|||
|
||||
void Checker::add_assumption_clause (int64_t id, const vector<int> &c,
|
||||
const vector<int64_t> &chain) {
|
||||
add_derived_clause (id, true, c, chain);
|
||||
add_derived_clause (id, true, 0, c, chain);
|
||||
delete_clause (id, true, c);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ inline void Internal::mark_added (int lit, int size, bool redundant) {
|
|||
mark_ternary (lit);
|
||||
if (!redundant)
|
||||
mark_block (lit);
|
||||
if (!redundant || size == 2)
|
||||
if ((!redundant || size == 2))
|
||||
mark_factor (lit);
|
||||
}
|
||||
|
||||
|
|
@ -151,6 +151,7 @@ Clause *Internal::new_clause (bool red, int glue) {
|
|||
|
||||
void Internal::promote_clause (Clause *c, int new_glue) {
|
||||
CADICAL_assert (c->redundant);
|
||||
CADICAL_assert (new_glue);
|
||||
const int tier1limit = tier1[false];
|
||||
const int tier2limit = max (tier1limit, tier2[false]);
|
||||
if (!c->redundant)
|
||||
|
|
@ -160,10 +161,10 @@ void Internal::promote_clause (Clause *c, int new_glue) {
|
|||
int old_glue = c->glue;
|
||||
if (new_glue >= old_glue)
|
||||
return;
|
||||
c->used = max_used;
|
||||
if (old_glue > tier1limit && new_glue <= tier1limit) {
|
||||
LOG (c, "promoting with new glue %d to tier1", new_glue);
|
||||
stats.promoted1++;
|
||||
c->used = max_used;
|
||||
} else if (old_glue > tier2limit && new_glue <= tier2limit) {
|
||||
LOG (c, "promoting with new glue %d to tier2", new_glue);
|
||||
stats.promoted2++;
|
||||
|
|
@ -178,6 +179,7 @@ void Internal::promote_clause (Clause *c, int new_glue) {
|
|||
|
||||
void Internal::promote_clause_glue_only (Clause *c, int new_glue) {
|
||||
CADICAL_assert (c->redundant);
|
||||
CADICAL_assert (new_glue);
|
||||
if (c->hyper)
|
||||
return;
|
||||
int old_glue = c->glue;
|
||||
|
|
@ -188,7 +190,6 @@ void Internal::promote_clause_glue_only (Clause *c, int new_glue) {
|
|||
if (new_glue <= tier1limit) {
|
||||
LOG (c, "promoting with new glue %d to tier1", new_glue);
|
||||
stats.promoted1++;
|
||||
c->used = max_used;
|
||||
} else if (old_glue > tier2limit && new_glue <= tier2limit) {
|
||||
LOG (c, "promoting with new glue %d to tier2", new_glue);
|
||||
stats.promoted2++;
|
||||
|
|
@ -582,13 +583,17 @@ Clause *Internal::new_hyper_ternary_resolved_clause (bool red) {
|
|||
return res;
|
||||
}
|
||||
|
||||
Clause *Internal::new_factor_clause () {
|
||||
Clause *Internal::new_factor_clause (int witness) {
|
||||
external->check_learned_clause ();
|
||||
stats.factor_added++;
|
||||
stats.literals_factored += clause.size ();
|
||||
Clause *res = new_clause (false, 0);
|
||||
if (proof) {
|
||||
proof->add_derived_clause (res, lrat_chain);
|
||||
if (witness)
|
||||
proof->add_derived_rat_clause (res, externalize (witness),
|
||||
lrat_chain);
|
||||
else
|
||||
proof->add_derived_clause (res, lrat_chain);
|
||||
}
|
||||
CADICAL_assert (!watching ());
|
||||
CADICAL_assert (occurring ());
|
||||
|
|
@ -644,6 +649,48 @@ Clause *Internal::new_resolved_irredundant_clause () {
|
|||
return res;
|
||||
}
|
||||
|
||||
void Internal::decay_clauses_upon_incremental_clauses () {
|
||||
if (!opts.incdecay)
|
||||
return;
|
||||
if (!stats.searches)
|
||||
return;
|
||||
if (stats.conflicts < lim.incremental_decay)
|
||||
return;
|
||||
|
||||
PHASE ("decay", stats.incremental_decay,
|
||||
"decaying clauses with next decaying at conflict %" PRId64
|
||||
"(after the next incremental call)",
|
||||
lim.incremental_decay);
|
||||
|
||||
for (auto c : clauses) {
|
||||
if (c->garbage)
|
||||
continue;
|
||||
if (!c->redundant)
|
||||
continue;
|
||||
if (c->id >= last.incremental_decay.last_id)
|
||||
continue;
|
||||
switch (opts.incdecay) {
|
||||
case 1: // my intuition
|
||||
++c->glue;
|
||||
break;
|
||||
case 2: // Armin's idea
|
||||
if (c->glue < tier1[false])
|
||||
c->used = 1;
|
||||
break;
|
||||
case 3:
|
||||
if (c->glue < tier1[false])
|
||||
c->used = 1;
|
||||
++c->glue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lim.incremental_decay += stats.conflicts + opts.incdecayint;
|
||||
++stats.incremental_decay;
|
||||
last.incremental_decay.last_id = clause_id;
|
||||
}
|
||||
} // namespace CaDiCaL
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
|
|||
|
|
@ -354,7 +354,6 @@ void Internal::compact () {
|
|||
mapper.map_vector (phases.target);
|
||||
mapper.map_vector (phases.best);
|
||||
mapper.map_vector (phases.prev);
|
||||
mapper.map_vector (phases.min);
|
||||
|
||||
// Special code for 'frozentab'.
|
||||
//
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -41,7 +41,83 @@ int Internal::next_decision_variable_with_best_score () {
|
|||
return res;
|
||||
}
|
||||
|
||||
void Internal::start_random_sequence () {
|
||||
if (!opts.randec)
|
||||
return;
|
||||
|
||||
CADICAL_assert (!stable || opts.randecstable);
|
||||
CADICAL_assert (stable || opts.randecfocused);
|
||||
CADICAL_assert (!randomized_deciding);
|
||||
|
||||
const uint64_t count = ++stats.randec.random_decision_phases;
|
||||
const unsigned length = opts.randeclength * log (count + 10);
|
||||
VERBOSE (3,
|
||||
"starting random decision sequence "
|
||||
"at %" PRId64 " conflicts for %u conflicts",
|
||||
stats.conflicts, length);
|
||||
randomized_deciding = length;
|
||||
|
||||
const double delta = stats.randec.random_decision_phases *
|
||||
log (stats.randec.random_decision_phases);
|
||||
lim.random_decision = stats.conflicts + delta * opts.randecint;
|
||||
VERBOSE (3,
|
||||
"next random decision sequence "
|
||||
"at %" PRId64 " conflicts current conflict: %" PRId64
|
||||
" conflicts",
|
||||
lim.random_decision, stats.conflicts);
|
||||
}
|
||||
|
||||
int Internal::next_random_decision () {
|
||||
CADICAL_assert (max_var);
|
||||
if (!opts.randec)
|
||||
return 0;
|
||||
if (stable && !opts.randecstable)
|
||||
return 0;
|
||||
if (!stable && !opts.randecfocused)
|
||||
return 0;
|
||||
if (stats.conflicts < lim.random_decision)
|
||||
return 0;
|
||||
if (satisfied ())
|
||||
return 0;
|
||||
|
||||
if (!randomized_deciding) {
|
||||
if (level > (int) assumptions.size () + !!constraint.size ()) {
|
||||
LOG ("random decision delayed because too deep");
|
||||
return 0;
|
||||
}
|
||||
start_random_sequence ();
|
||||
}
|
||||
LOG ("searching for random decision");
|
||||
Random random (internal->opts.seed);
|
||||
random += stats.decisions;
|
||||
++stats.randec.random_decisions;
|
||||
for (;;) {
|
||||
int idx = 1 + (random.next () % max_var);
|
||||
LOG ("trying lit %s", LOGLIT (idx));
|
||||
/*
|
||||
// Kissat filters out active literals but we cannot do that because
|
||||
// eliminated variables are not actively removed.
|
||||
if (!flags (idx).active())
|
||||
continue;
|
||||
*/
|
||||
if (val (idx))
|
||||
continue;
|
||||
return idx;
|
||||
}
|
||||
CADICAL_assert (false);
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
__assume(false);
|
||||
#else
|
||||
__builtin_unreachable ();
|
||||
#endif
|
||||
}
|
||||
|
||||
int Internal::next_decision_variable () {
|
||||
int res = next_random_decision ();
|
||||
if (res) {
|
||||
LOG ("randomized decision %s", LOGLIT (res));
|
||||
return res;
|
||||
}
|
||||
if (use_scores ())
|
||||
return next_decision_variable_with_best_score ();
|
||||
else
|
||||
|
|
@ -57,16 +133,39 @@ int Internal::next_decision_variable () {
|
|||
int Internal::decide_phase (int idx, bool target) {
|
||||
const int initial_phase = opts.phase ? 1 : -1;
|
||||
int phase = 0;
|
||||
if (force_saved_phase)
|
||||
if (force_saved_phase) {
|
||||
phase = phases.saved[idx];
|
||||
if (!phase)
|
||||
LOG ("trying force_saved_phase, i.e., %d", phase);
|
||||
}
|
||||
CADICAL_assert (force_saved_phase || !phase);
|
||||
if (!phase) {
|
||||
phase = phases.forced[idx]; // swapped with opts.forcephase case!
|
||||
if (!phase && opts.forcephase)
|
||||
LOG ("trying forced phase, i.e., %d", phase);
|
||||
}
|
||||
if (!phase && opts.forcephase) {
|
||||
phase = initial_phase;
|
||||
if (!phase && target)
|
||||
LOG ("trying initial phase, i.e., %d", phase);
|
||||
}
|
||||
if (!phase && target) {
|
||||
phase = phases.target[idx];
|
||||
if (!phase)
|
||||
phase = phases.saved[idx];
|
||||
}
|
||||
if (!phase) {
|
||||
// ported from kissat where it does not seem very useful
|
||||
if (opts.stubbornIOfocused && opts.rephase == 2)
|
||||
switch ((stats.rephased.total >> 1) & 7) {
|
||||
case 1:
|
||||
phase = initial_phase;
|
||||
break;
|
||||
case 5: // kissat has 3 but 5 looks better
|
||||
phase = -initial_phase;
|
||||
break;
|
||||
default:
|
||||
phase = phases.saved[idx];
|
||||
break;
|
||||
}
|
||||
else
|
||||
phase = phases.saved[idx];
|
||||
}
|
||||
|
||||
// The following should not be necessary and in some version we had even
|
||||
// a hard 'COVER' CADICAL_assertion here to check for this. Unfortunately it
|
||||
|
|
|
|||
|
|
@ -473,6 +473,11 @@ bool Internal::decompose_round () {
|
|||
}
|
||||
external->push_binary_clause_on_extension_stack (id2, idx, -other);
|
||||
decompose_ids[vlit (idx)] = id2;
|
||||
for (auto &tracer : tracers) {
|
||||
const int eidx = externalize (idx);
|
||||
const int eother = externalize (other);
|
||||
tracer->notify_equivalence (eidx, eother);
|
||||
}
|
||||
|
||||
clause.clear ();
|
||||
lrat_chain.clear ();
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ void DratTracer::drat_delete_clause (const vector<int> &clause) {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void DratTracer::add_derived_clause (int64_t, bool,
|
||||
void DratTracer::add_derived_clause (int64_t, bool, int,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &) {
|
||||
if (file->closed ())
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@ namespace CaDiCaL {
|
|||
|
||||
inline double Internal::compute_elim_score (unsigned lit) {
|
||||
CADICAL_assert (1 <= lit), CADICAL_assert (lit <= (unsigned) max_var);
|
||||
const unsigned uidx = 2 * lit;
|
||||
const double pos = internal->ntab[uidx];
|
||||
const double neg = internal->ntab[uidx + 1];
|
||||
const double pos = noccs (lit);
|
||||
const double neg = noccs (-lit);
|
||||
if (!pos)
|
||||
return -neg;
|
||||
if (!neg)
|
||||
|
|
@ -1043,7 +1042,7 @@ void Internal::elim (bool update_limits) {
|
|||
#endif
|
||||
|
||||
// Make sure there was a complete subsumption phase since last
|
||||
// elimination including vivification etc.
|
||||
// elimination
|
||||
//
|
||||
if (last.elim.subsumephases == stats.subsumephases)
|
||||
subsume ();
|
||||
|
|
|
|||
|
|
@ -196,17 +196,18 @@ void Internal::try_to_fasteliminate_variable (Eliminator &eliminator,
|
|||
|
||||
// First flush garbage clauses and check limits.
|
||||
|
||||
const int64_t occ_bound = opts.fastelimocclim;
|
||||
int64_t bound = opts.fastelimbound;
|
||||
|
||||
int64_t pos = flush_elimfast_occs (pivot);
|
||||
if (pos > bound) {
|
||||
int64_t neg = flush_elimfast_occs (-pivot);
|
||||
if (neg && pos > occ_bound) {
|
||||
LOG ("too many occurrences thus not eliminated %d", pivot);
|
||||
CADICAL_assert (!eliminator.schedule.contains (abs (pivot)));
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t neg = flush_elimfast_occs (-pivot);
|
||||
if (neg > bound) {
|
||||
if (pos && neg > occ_bound) {
|
||||
LOG ("too many occurrences thus not eliminated %d", -pivot);
|
||||
CADICAL_assert (!eliminator.schedule.contains (abs (pivot)));
|
||||
return;
|
||||
|
|
@ -286,7 +287,6 @@ int Internal::elimfast_round (bool &completed,
|
|||
delta = opts.elimmineff;
|
||||
if (delta > opts.elimmaxeff)
|
||||
delta = opts.elimmaxeff;
|
||||
delta = max (delta, (int64_t) 2l * active ());
|
||||
|
||||
PHASE ("fastelim-round", stats.elimfastrounds,
|
||||
"limit of %" PRId64 " resolutions", delta);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,14 @@ void External::push_id_on_extension_stack (int64_t id) {
|
|||
void External::push_clause_literal_on_extension_stack (int ilit) {
|
||||
CADICAL_assert (ilit);
|
||||
const int elit = internal->externalize (ilit);
|
||||
const int eidx = abs (elit);
|
||||
const bool is_extension_var = ervars[eidx];
|
||||
Flags &f = internal->flags (ilit);
|
||||
if (is_extension_var) {
|
||||
f.factored_but_on_reconstruction_stack = true;
|
||||
LOG ("marking lit %s as tainted", LOGLIT (ilit));
|
||||
}
|
||||
|
||||
CADICAL_assert (elit);
|
||||
extension.push_back (elit);
|
||||
LOG ("pushing clause literal %d on extension stack (internal %d)", elit,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "internal.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
|
@ -43,6 +45,11 @@ void External::init (int new_max_var, bool extension) {
|
|||
if ((size_t) new_max_var >= vsize)
|
||||
enlarge (new_max_var);
|
||||
LOG ("initialized %d external variables", new_vars);
|
||||
reserve_at_least (ext_units, 2 * new_max_var + 2);
|
||||
reserve_at_least (e2i, new_max_var + 1);
|
||||
reserve_at_least (ervars, new_max_var + 1);
|
||||
reserve_at_least (ext_flags, new_max_var + 1);
|
||||
reserve_at_least (internal->i2e, new_max_var + 1);
|
||||
if (!max_var) {
|
||||
CADICAL_assert (e2i.empty ());
|
||||
e2i.push_back (0);
|
||||
|
|
@ -74,8 +81,6 @@ void External::init (int new_max_var, bool extension) {
|
|||
internal->stats.variables_extension += new_vars;
|
||||
else
|
||||
internal->stats.variables_original += new_vars;
|
||||
if (new_max_var >= (int64_t) is_observed.size ())
|
||||
is_observed.resize (1 + (size_t) new_max_var, false);
|
||||
if (internal->opts.checkfrozen)
|
||||
if (new_max_var >= (int64_t) moltentab.size ())
|
||||
moltentab.resize (1 + (size_t) new_max_var, false);
|
||||
|
|
@ -415,6 +420,8 @@ void External::remove_observed_var (int elit) {
|
|||
if (eidx > max_var)
|
||||
return;
|
||||
|
||||
if ((size_t) eidx <= is_observed.size ())
|
||||
return;
|
||||
if (is_observed[eidx]) {
|
||||
// Follow opposite order of add_observed_var, first remove internal
|
||||
// is_observed
|
||||
|
|
@ -438,11 +445,11 @@ void External::reset_observed_vars () {
|
|||
if (!is_observed.size ())
|
||||
return;
|
||||
|
||||
CADICAL_assert (!max_var || (size_t) max_var + 1 == is_observed.size ());
|
||||
|
||||
for (auto elit : vars) {
|
||||
int eidx = abs (elit);
|
||||
CADICAL_assert (eidx <= max_var);
|
||||
if ((size_t) eidx >= is_observed.size ())
|
||||
break;
|
||||
if (is_observed[eidx]) {
|
||||
int ilit = internalize (elit);
|
||||
internal->remove_observed_var (ilit);
|
||||
|
|
@ -514,7 +521,7 @@ void External::implied (std::vector<int> &trailed) {
|
|||
// (Internal does not see these marks, so no earlier filter is
|
||||
// possible.)
|
||||
|
||||
trailed.clear();
|
||||
trailed.clear ();
|
||||
|
||||
for (const auto &ilit : ilit_implicants) {
|
||||
CADICAL_assert (ilit);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "internal.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
namespace CaDiCaL {
|
||||
|
|
@ -99,6 +101,7 @@ void Internal::set_tainted_literal () {
|
|||
}
|
||||
|
||||
void Internal::renotify_trail_after_ilb () {
|
||||
CADICAL_assert (opts.ilb);
|
||||
if (!external_prop || external_prop_is_lazy || !trail.size () ||
|
||||
!opts.ilb) {
|
||||
return;
|
||||
|
|
@ -124,9 +127,57 @@ void Internal::renotify_trail_after_local_search () {
|
|||
renotify_full_trail ();
|
||||
}
|
||||
|
||||
void Internal::renotify_full_trail_between_trail_pos (
|
||||
int start_level, int end_level, int propagator_level,
|
||||
std::vector<int> &assigned, bool start_new_level) {
|
||||
CADICAL_assert (assigned.empty ());
|
||||
int j = start_level;
|
||||
#ifdef LOGGING
|
||||
LOG ("starting notification of level %d from trail %d .. %d",
|
||||
propagator_level, start_level, end_level);
|
||||
#else
|
||||
(void) propagator_level;
|
||||
#endif
|
||||
if (start_new_level) {
|
||||
if (assigned.size ())
|
||||
external->propagator->notify_assignment (assigned);
|
||||
assigned.clear ();
|
||||
external->propagator->notify_new_decision_level ();
|
||||
}
|
||||
for (; j < end_level; ++j) {
|
||||
int ilit = trail[j];
|
||||
// In theory, 0 ilit can happen due to pseudo-decision levels
|
||||
if (!ilit)
|
||||
continue;
|
||||
|
||||
if (!observed (ilit))
|
||||
continue;
|
||||
|
||||
int elit = externalize (ilit); // TODO: double-check tainting
|
||||
|
||||
LOG ("notifying elit %d @ %d aka %s", propagator_level, elit,
|
||||
LOGLIT (ilit));
|
||||
CADICAL_assert (elit);
|
||||
// Fixed variables might get mapped (during compact) to another
|
||||
// non-observed but fixed variable.
|
||||
// This happens on root level, so notification about their assignment
|
||||
// is already done.
|
||||
CADICAL_assert (external->observed (elit) || fixed (ilit));
|
||||
if (!external->ervars[abs (elit)])
|
||||
assigned.push_back (elit);
|
||||
}
|
||||
|
||||
if (assigned.size ())
|
||||
external->propagator->notify_assignment (assigned);
|
||||
assigned.clear ();
|
||||
}
|
||||
|
||||
// It repeats ALL assignments of the trail, so the already notified
|
||||
// root-level assignments will be notified multiple times.
|
||||
|
||||
//
|
||||
// As CaDiCaL is missing some '0' seperators, it is important to go
|
||||
// over slices from the control stack instead of going over the trail
|
||||
// directly.
|
||||
void Internal::renotify_full_trail () {
|
||||
const size_t end_of_trail = trail.size ();
|
||||
if (level) {
|
||||
|
|
@ -136,56 +187,38 @@ void Internal::renotify_full_trail () {
|
|||
}
|
||||
std::vector<int> assigned;
|
||||
|
||||
int prev_max_level = 0;
|
||||
int current_level = 0;
|
||||
int propagator_level = 0;
|
||||
|
||||
while (notified < end_of_trail) {
|
||||
int ilit = trail[notified++];
|
||||
// In theory, 0 ilit can happen due to pseudo-decision levels
|
||||
if (!ilit)
|
||||
current_level = prev_max_level + 1;
|
||||
else
|
||||
current_level = var (ilit).level;
|
||||
|
||||
if (current_level > propagator_level) {
|
||||
if (assigned.size ())
|
||||
external->propagator->notify_assignment (assigned);
|
||||
while (current_level > propagator_level) {
|
||||
external->propagator->notify_new_decision_level ();
|
||||
propagator_level++;
|
||||
}
|
||||
assigned.clear ();
|
||||
}
|
||||
// Current level can be smaller than prev_max_level due to chrono
|
||||
if (current_level > prev_max_level)
|
||||
prev_max_level = current_level;
|
||||
|
||||
if (!observed (ilit))
|
||||
continue;
|
||||
|
||||
int elit = externalize (ilit); // TODO: double-check tainting
|
||||
CADICAL_assert (elit);
|
||||
// Fixed variables might get mapped (during compact) to another
|
||||
// non-observed but fixed variable.
|
||||
// This happens on root level, so notification about their assignment is
|
||||
// already done.
|
||||
CADICAL_assert (external->observed (elit) || fixed (ilit));
|
||||
if (!external->ervars[abs (elit)])
|
||||
assigned.push_back (elit);
|
||||
const int c_size = control.size ();
|
||||
{ // first all root-level literals
|
||||
const int start_level = 0;
|
||||
const int end_level =
|
||||
(control.size () > 1 ? control[1].trail : end_of_trail);
|
||||
renotify_full_trail_between_trail_pos (
|
||||
start_level, end_level, propagator_level, assigned, false);
|
||||
}
|
||||
if (assigned.size ())
|
||||
external->propagator->notify_assignment (assigned);
|
||||
assigned.clear ();
|
||||
|
||||
// In case there are some left over empty levels on the top of the trail,
|
||||
// the external propagtor must be notified about them so the levels are
|
||||
// synced
|
||||
while (level > propagator_level) {
|
||||
external->propagator->notify_new_decision_level ();
|
||||
// notify all intermediate levels
|
||||
for (int i = 2; i < c_size; ++i) {
|
||||
const int start_level = control[i - 1].trail;
|
||||
const int end_level = control[i].trail;
|
||||
propagator_level++;
|
||||
LOG ("notification of %d", propagator_level);
|
||||
|
||||
renotify_full_trail_between_trail_pos (
|
||||
start_level, end_level, propagator_level, assigned, true);
|
||||
}
|
||||
|
||||
// and the current level if there is non-root level one
|
||||
if (level) {
|
||||
const int start_level = control.back ().trail;
|
||||
propagator_level++;
|
||||
renotify_full_trail_between_trail_pos (
|
||||
start_level, end_of_trail, propagator_level, assigned, true);
|
||||
}
|
||||
CADICAL_assert (propagator_level == level);
|
||||
notified = trail.size ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +882,10 @@ bool Internal::external_check_solution () {
|
|||
// Here the variables must be filtered by external->is_observed,
|
||||
// because fixed variables are internally not necessarily observed
|
||||
// anymore.
|
||||
for (int idx = 1; idx <= external->max_var; idx++) {
|
||||
for (int idx = 1;
|
||||
idx <= std::min ((int) external->is_observed.size () - 1,
|
||||
external->max_var);
|
||||
idx++) {
|
||||
if (!external->is_observed[idx])
|
||||
continue;
|
||||
const int lit = external->ival (idx);
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ void Internal::add_self_subsuming_factor (Quotient *q, Quotient *p) {
|
|||
CADICAL_assert (lrat_chain.size () == 2);
|
||||
}
|
||||
if (clause.size () > 1) {
|
||||
new_factor_clause ();
|
||||
new_factor_clause (0);
|
||||
} else {
|
||||
const int unit = clause[0];
|
||||
const signed char tmp = val (unit);
|
||||
|
|
@ -599,9 +599,9 @@ bool Internal::self_subsuming_factor (Quotient *q) {
|
|||
void Internal::add_factored_divider (Quotient *q, int fresh) {
|
||||
const int factor = q->factor;
|
||||
LOG ("factored %d divider %d", factor, fresh);
|
||||
clause.push_back (factor);
|
||||
clause.push_back (fresh);
|
||||
new_factor_clause ();
|
||||
clause.push_back (factor);
|
||||
new_factor_clause (fresh);
|
||||
clause.clear ();
|
||||
if (lrat)
|
||||
mini_chain.push_back (-clause_id);
|
||||
|
|
@ -616,11 +616,12 @@ void Internal::blocked_clause (Quotient *q, int not_fresh) {
|
|||
int64_t new_id = ++clause_id;
|
||||
q->bid = new_id;
|
||||
CADICAL_assert (clause.empty ());
|
||||
clause.push_back (not_fresh);
|
||||
for (Quotient *p = q; p; p = p->prev)
|
||||
clause.push_back (-p->factor);
|
||||
clause.push_back (not_fresh);
|
||||
CADICAL_assert (!lrat || mini_chain.size ());
|
||||
proof->add_derived_clause (new_id, true, clause, mini_chain);
|
||||
proof->add_derived_rat_clause (new_id, true, externalize (not_fresh),
|
||||
clause, mini_chain);
|
||||
mini_chain.clear ();
|
||||
clause.clear ();
|
||||
}
|
||||
|
|
@ -654,15 +655,15 @@ void Internal::add_factored_quotient (Quotient *q, int not_fresh) {
|
|||
lrat_chain.push_back (q->bid);
|
||||
}
|
||||
clause.push_back (not_fresh);
|
||||
new_factor_clause ();
|
||||
new_factor_clause (0);
|
||||
clause.clear ();
|
||||
lrat_chain.clear ();
|
||||
}
|
||||
if (proof) {
|
||||
clause.push_back (not_fresh);
|
||||
for (Quotient *p = q; p; p = p->prev) {
|
||||
clause.push_back (-p->factor);
|
||||
}
|
||||
clause.push_back (not_fresh);
|
||||
proof->delete_clause (q->bid, true, clause);
|
||||
clause.clear ();
|
||||
}
|
||||
|
|
@ -769,6 +770,79 @@ void Internal::schedule_factorization (Factoring &factoring) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void Internal::adjust_scores_and_phases_of_fresh_variables (
|
||||
Factoring &factoring) {
|
||||
if (!opts.factorunbump) {
|
||||
factoring.fresh.clear ();
|
||||
return;
|
||||
}
|
||||
if (factoring.fresh.empty ())
|
||||
return;
|
||||
|
||||
#if 0 // the scores are very low anyway
|
||||
for (auto lit : factoring.fresh) {
|
||||
CADICAL_assert (lit > 0 && internal->max_var);
|
||||
const double old_score = internal->stab[lit];
|
||||
// make the scores a little different from each other with the newest having the highest score
|
||||
const double new_score = 1.0 / (double)(internal->max_var - lit);
|
||||
if (old_score == new_score)
|
||||
continue;
|
||||
if (!scores.contains (lit))
|
||||
continue;
|
||||
LOG ("unbumping %s", LOGLIT(lit));
|
||||
internal->stab[lit] = new_score;
|
||||
scores.update (lit);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto lit : factoring.fresh) {
|
||||
LOG ("dequeuing %s", LOGLIT (lit));
|
||||
queue.dequeue (links, lit);
|
||||
}
|
||||
|
||||
for (auto lit : factoring.fresh) {
|
||||
LOG ("dequeuing %s", LOGLIT (lit));
|
||||
queue.bury (links, lit);
|
||||
}
|
||||
|
||||
// fix the scores with negative numbers
|
||||
int lit = queue.first;
|
||||
queue.bumped = 0;
|
||||
while (lit) {
|
||||
btab[lit] = ++queue.bumped;
|
||||
lit = links[lit].next;
|
||||
}
|
||||
stats.bumped = queue.bumped;
|
||||
update_queue_unassigned (queue.last);
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto v : vars)
|
||||
CADICAL_assert (val (v) || scores.contains (v));
|
||||
lit = queue.first;
|
||||
int next_lit = links[lit].next;
|
||||
while (next_lit) {
|
||||
CADICAL_assert (btab[lit] < btab[next_lit]);
|
||||
const int tmp = links[next_lit].next;
|
||||
CADICAL_assert (!tmp || links[tmp].prev == next_lit);
|
||||
lit = next_lit;
|
||||
next_lit = tmp;
|
||||
}
|
||||
|
||||
lit = queue.last;
|
||||
next_lit = links[lit].prev;
|
||||
while (next_lit) {
|
||||
CADICAL_assert (btab[lit] > btab[next_lit]);
|
||||
const int tmp = links[next_lit].prev;
|
||||
CADICAL_assert (!tmp || links[tmp].next == next_lit);
|
||||
lit = next_lit;
|
||||
next_lit = tmp;
|
||||
}
|
||||
CADICAL_assert (queue.first);
|
||||
CADICAL_assert (queue.last);
|
||||
#endif
|
||||
factoring.fresh.clear ();
|
||||
}
|
||||
|
||||
bool Internal::run_factorization (int64_t limit) {
|
||||
Factoring factoring = Factoring (this, limit);
|
||||
schedule_factorization (factoring);
|
||||
|
|
@ -834,8 +908,7 @@ bool Internal::run_factorization (int64_t limit) {
|
|||
const unsigned idx = factoring.schedule.front ();
|
||||
completed = occs (u2i (idx)).empty ();
|
||||
}
|
||||
// kissat initializes scores for new variables at this point, however
|
||||
// this is actually done already during resize of internal
|
||||
adjust_scores_and_phases_of_fresh_variables (factoring);
|
||||
#ifndef CADICAL_QUIET
|
||||
report ('f', !factored);
|
||||
#endif
|
||||
|
|
@ -863,6 +936,19 @@ bool Internal::factor () {
|
|||
return false;
|
||||
if (!opts.factor)
|
||||
return false;
|
||||
|
||||
int v_active = active ();
|
||||
size_t log_active = log10 (v_active);
|
||||
size_t eliminations = stats.elimrounds;
|
||||
size_t delay = opts.factordelay;
|
||||
size_t delay_limit = eliminations + delay;
|
||||
if (log_active > delay_limit) {
|
||||
VERBOSE (3,
|
||||
"factorization delayed as %zu = log10 (%u)"
|
||||
"> eliminations + delay = %zu + %zu = %zu",
|
||||
log_active, v_active, eliminations, delay, delay_limit);
|
||||
return false;
|
||||
}
|
||||
// The following CADICAL_assertion fails if there are *only* user propagator
|
||||
// clauses (which are redundant).
|
||||
// CADICAL_assert (stats.mark.factor || clauses.empty ());
|
||||
|
|
@ -879,6 +965,8 @@ bool Internal::factor () {
|
|||
if (!stats.factor)
|
||||
limit += opts.factoriniticks * 1e6;
|
||||
|
||||
mark_duplicated_binary_clauses_as_garbage ();
|
||||
|
||||
START_SIMPLIFIER (factor, FACTOR);
|
||||
stats.factor++;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void Internal::mark_fixed (int lit) {
|
|||
// to know about it.
|
||||
// But at that point it is not guaranteed to be already on the trail, so
|
||||
// notification will happen only later.
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (!level || in_mode (BACKBONE));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ void FratTracer::add_original_clause (int64_t id, bool,
|
|||
frat_add_original_clause (id, clause);
|
||||
}
|
||||
|
||||
void FratTracer::add_derived_clause (int64_t id, bool,
|
||||
void FratTracer::add_derived_clause (int64_t id, bool, int,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &chain) {
|
||||
if (file->closed ())
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ void IdrupTracer::idrup_solve_query () {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void IdrupTracer::add_derived_clause (int64_t, bool,
|
||||
void IdrupTracer::add_derived_clause (int64_t, bool, int,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &) {
|
||||
if (file->closed ())
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ Internal::Internal ()
|
|||
tainted_literal (0), notified (0), probe_reason (0), propagated (0),
|
||||
propagated2 (0), propergated (0), best_assigned (0),
|
||||
target_assigned (0), no_conflict_until (0), unsat_constraint (false),
|
||||
marked_failed (true), sweep_incomplete (false), citten (0),
|
||||
num_assigned (0), proof (0), opts (this),
|
||||
marked_failed (true), sweep_incomplete (false),
|
||||
randomized_deciding (false), citten (0), num_assigned (0), proof (0),
|
||||
opts (this),
|
||||
#ifndef CADICAL_QUIET
|
||||
profiles (this), force_phase_messages (false),
|
||||
#endif
|
||||
|
|
@ -38,8 +39,10 @@ Internal::Internal ()
|
|||
control.push_back (Level (0, 0));
|
||||
|
||||
// The 'dummy_binary' is used in 'try_to_subsume_clause' to fake a real
|
||||
// clause, which then can be used to subsume or strengthen the given
|
||||
// clause in one routine for both binary and non binary clauses. This
|
||||
// clause (which then can be used to subsume or strengthen the given
|
||||
// clause in one routine for both binary and non binary clauses) and
|
||||
// in walk (which is only used as a placeholder in the watch lists
|
||||
// when logging is off, since the clause is not accessed). This
|
||||
// fake binary clause is always kept non-redundant (and not-moved etc.)
|
||||
// due to the following 'memset'. Only literals will be changed.
|
||||
|
||||
|
|
@ -51,6 +54,8 @@ Internal::Internal ()
|
|||
dummy_binary = (Clause *) new char[bytes];
|
||||
memset (dummy_binary, 0, bytes);
|
||||
dummy_binary->size = 2;
|
||||
|
||||
/*with C++17: static_*/ CADICAL_assert (max_used == (1 << USED_SIZE) - 1);
|
||||
}
|
||||
|
||||
Internal::~Internal () {
|
||||
|
|
@ -147,7 +152,6 @@ void Internal::enlarge (int new_max_var) {
|
|||
enlarge_zero (phases.target, new_vsize);
|
||||
enlarge_zero (phases.best, new_vsize);
|
||||
enlarge_zero (phases.prev, new_vsize);
|
||||
enlarge_zero (phases.min, new_vsize);
|
||||
enlarge_zero (marks, new_vsize);
|
||||
}
|
||||
|
||||
|
|
@ -348,8 +352,8 @@ int Internal::propagate_assumptions () {
|
|||
if (proof)
|
||||
proof->solve_query ();
|
||||
if (opts.ilb) {
|
||||
if (opts.ilbassumptions)
|
||||
sort_and_reuse_assumptions ();
|
||||
sort_and_reuse_assumptions ();
|
||||
CADICAL_assert (opts.ilb == 2 || (size_t) level <= assumptions.size ());
|
||||
stats.ilbtriggers++;
|
||||
stats.ilbsuccess += (level > 0);
|
||||
stats.levelsreused += level;
|
||||
|
|
@ -419,9 +423,9 @@ void Internal::implied (std::vector<int> &entrailed) {
|
|||
int last_assumption_level = assumptions.size ();
|
||||
if (constraint.size ())
|
||||
last_assumption_level++;
|
||||
|
||||
size_t trail_limit = trail.size();
|
||||
if (level > last_assumption_level)
|
||||
|
||||
size_t trail_limit = trail.size ();
|
||||
if (level > last_assumption_level)
|
||||
trail_limit = control[last_assumption_level + 1].trail;
|
||||
|
||||
for (size_t i = 0; i < trail_limit; i++)
|
||||
|
|
@ -559,6 +563,7 @@ void Internal::init_search_limits () {
|
|||
|
||||
lim.rephase = stats.conflicts + opts.rephaseint;
|
||||
lim.rephased[0] = lim.rephased[1] = 0;
|
||||
last.stabilize.rephased = 0;
|
||||
LOG ("new rephase limit %" PRId64 " after %" PRId64 " conflicts",
|
||||
lim.rephase, lim.rephase - stats.conflicts);
|
||||
|
||||
|
|
@ -589,17 +594,18 @@ void Internal::init_search_limits () {
|
|||
} else
|
||||
LOG ("keeping non-stable phase");
|
||||
|
||||
if (!incremental) {
|
||||
inc.stabilize = 0;
|
||||
lim.stabilize = stats.conflicts + opts.stabilizeinit;
|
||||
LOG ("initial stabilize limit %" PRId64 " after %d conflicts",
|
||||
lim.stabilize, (int) opts.stabilizeinit);
|
||||
}
|
||||
inc.stabilize = 0;
|
||||
last.stabilize.conflicts = stats.conflicts;
|
||||
lim.stabilize = stats.conflicts + opts.stabilizeinit;
|
||||
last.stabilize.ticks = stats.ticks.search[0];
|
||||
stats.stabphases = 0;
|
||||
LOG ("new ticks-based stabilize limit %" PRId64 " after %d conflicts",
|
||||
lim.stabilize, (int) opts.stabilizeinit);
|
||||
|
||||
if (opts.stabilize && opts.reluctant) {
|
||||
if (opts.stabilize && opts.reluctant && opts.reluctantint) {
|
||||
LOG ("new restart reluctant doubling sequence period %d",
|
||||
opts.reluctant);
|
||||
reluctant.enable (opts.reluctant, opts.reluctantmax);
|
||||
reluctant.enable (opts.reluctantint, opts.reluctantmax);
|
||||
} else
|
||||
reluctant.disable ();
|
||||
|
||||
|
|
@ -622,11 +628,20 @@ void Internal::init_search_limits () {
|
|||
LOG ("no limit on decisions");
|
||||
} else {
|
||||
lim.decisions = stats.decisions + inc.decisions;
|
||||
LOG ("conflict limit after %" PRId64 " decisions at %" PRId64
|
||||
LOG ("decision limit after %" PRId64 " decisions at %" PRId64
|
||||
" decisions",
|
||||
inc.decisions, lim.decisions);
|
||||
}
|
||||
|
||||
if (inc.ticks < 0) {
|
||||
lim.ticks = -1;
|
||||
LOG ("no limit on ticks");
|
||||
} else {
|
||||
lim.ticks = stats.ticks.search[0] + stats.ticks.search[1] + inc.ticks;
|
||||
LOG ("ticks limit after %" PRId64 " ticks at %" PRId64 " ticks",
|
||||
inc.ticks, lim.ticks);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
// Initial preprocessing rounds.
|
||||
|
|
@ -639,6 +654,41 @@ void Internal::init_search_limits () {
|
|||
LOG ("limiting to %" PRId64 " local search rounds", lim.localsearch);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
// tier 1 and tier 2 limits
|
||||
if (incremental && opts.recomputetier) {
|
||||
for (auto m : {true, false})
|
||||
for (auto &u : stats.used[m])
|
||||
u = 0;
|
||||
stats.bump_used = {0, 0};
|
||||
for (auto u : {true, false}) {
|
||||
tier1[u] = max (tier1[u], opts.tier1minglue ? opts.tier1minglue : 2);
|
||||
tier2[u] = max (tier2[u], opts.tier2minglue ? opts.tier2minglue : 6);
|
||||
}
|
||||
stats.tierecomputed = 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
// clause decaying
|
||||
if (incremental)
|
||||
last.incremental_decay.last_id = 0;
|
||||
else {
|
||||
lim.incremental_decay = opts.incdecayint;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
if (incremental)
|
||||
mode = "keeping";
|
||||
else {
|
||||
lim.random_decision = stats.conflicts + opts.randecinit;
|
||||
mode = "initial";
|
||||
}
|
||||
(void) mode;
|
||||
LOG ("%s randomize decision limit %" PRId64 " after %" PRId64
|
||||
" conflicts",
|
||||
mode, lim.random_decision, lim.random_decision - stats.conflicts);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
lim.initialized = true;
|
||||
|
|
@ -693,28 +743,34 @@ bool Internal::preprocess_round (int round) {
|
|||
}
|
||||
|
||||
// for now counts as one of the preprocessing rounds TODO: change this?
|
||||
void Internal::preprocess_quickly () {
|
||||
void Internal::preprocess_quickly (bool always) {
|
||||
if (unsat)
|
||||
return;
|
||||
if (!max_var)
|
||||
return;
|
||||
if (!opts.preprocesslight)
|
||||
return;
|
||||
if (!always && stats.searches > 1)
|
||||
return;
|
||||
START (preprocess);
|
||||
#ifndef CADICAL_QUIET
|
||||
struct {
|
||||
int64_t vars, clauses;
|
||||
} before, after;
|
||||
before.vars = active ();
|
||||
before.clauses = stats.current.irredundant;
|
||||
#endif
|
||||
// stats.preprocessings++;
|
||||
CADICAL_assert (!preprocessing);
|
||||
preprocessing = true;
|
||||
report ('(');
|
||||
PHASE ("preprocessing", stats.preprocessings,
|
||||
"starting with %" PRId64 " variables and %" PRId64 " clauses",
|
||||
before.vars, before.clauses);
|
||||
|
||||
if (extract_gates ())
|
||||
if (extract_gates (true))
|
||||
decompose ();
|
||||
binary_clauses_backbone ();
|
||||
|
||||
if (sweep ())
|
||||
decompose ();
|
||||
|
|
@ -724,10 +780,12 @@ void Internal::preprocess_quickly () {
|
|||
|
||||
if (opts.fastelim)
|
||||
elimfast ();
|
||||
// if (opts.condition)
|
||||
// condition (false);
|
||||
// if (opts.condition)
|
||||
// condition (false);
|
||||
#ifndef CADICAL_QUIET
|
||||
after.vars = active ();
|
||||
after.clauses = stats.current.irredundant;
|
||||
#endif
|
||||
CADICAL_assert (preprocessing);
|
||||
preprocessing = false;
|
||||
PHASE ("preprocessing", stats.preprocessings,
|
||||
|
|
@ -737,11 +795,17 @@ void Internal::preprocess_quickly () {
|
|||
report ('P');
|
||||
}
|
||||
|
||||
int Internal::preprocess () {
|
||||
preprocess_quickly ();
|
||||
int Internal::preprocess (bool always) {
|
||||
int res = 0;
|
||||
if (!level && !unsat && opts.luckyearly)
|
||||
res = lucky_phases ();
|
||||
if (res)
|
||||
return res;
|
||||
preprocess_quickly (always);
|
||||
for (int i = 0; i < lim.preprocessing; i++)
|
||||
if (!preprocess_round (i))
|
||||
break;
|
||||
report (')');
|
||||
if (unsat)
|
||||
return 20;
|
||||
return 0;
|
||||
|
|
@ -836,7 +900,11 @@ int Internal::local_search_round (int round) {
|
|||
else
|
||||
limit = LONG_MAX;
|
||||
|
||||
int res = walk_round (limit, true);
|
||||
int res;
|
||||
if (opts.walkfullocc)
|
||||
res = walk_full_occs_round (limit, true);
|
||||
else
|
||||
res = walk_round (limit, true);
|
||||
|
||||
CADICAL_assert (localsearching);
|
||||
localsearching = false;
|
||||
|
|
@ -883,12 +951,13 @@ int Internal::local_search () {
|
|||
//
|
||||
int Internal::solve (bool preprocess_only) {
|
||||
CADICAL_assert (clause.empty ());
|
||||
stats.searches++;
|
||||
START (solve);
|
||||
if (proof)
|
||||
proof->solve_query ();
|
||||
if (opts.ilb) {
|
||||
if (opts.ilbassumptions)
|
||||
sort_and_reuse_assumptions ();
|
||||
sort_and_reuse_assumptions ();
|
||||
CADICAL_assert (opts.ilb || (size_t) level <= assumptions.size ());
|
||||
stats.ilbtriggers++;
|
||||
stats.ilbsuccess += (level > 0);
|
||||
stats.levelsreused += level;
|
||||
|
|
@ -919,12 +988,14 @@ int Internal::solve (bool preprocess_only) {
|
|||
res = local_search ();
|
||||
}
|
||||
if (!res && !level)
|
||||
res = preprocess ();
|
||||
res = preprocess (preprocess_only);
|
||||
if (!preprocess_only) {
|
||||
if (!res && !level && opts.luckylate)
|
||||
res = lucky_phases ();
|
||||
if (!res && !level)
|
||||
res = local_search ();
|
||||
if (!res && !level)
|
||||
res = lucky_phases ();
|
||||
if (!res)
|
||||
decay_clauses_upon_incremental_clauses ();
|
||||
if (!res || (res == 10 && external_prop)) {
|
||||
if (res == 10 && external_prop && level)
|
||||
backtrack ();
|
||||
|
|
|
|||
|
|
@ -497,11 +497,12 @@ static void clear_cadical_kitten (cadical_kitten *cadical_kitten) {
|
|||
void *OLD_PTR = (P); \
|
||||
CALLOC (T, (P), new_size / 2); \
|
||||
const size_t BYTES = old_vars * sizeof *(P); \
|
||||
memcpy ((P), OLD_PTR, BYTES); \
|
||||
if ((P) && OLD_PTR) /* nullptr not allowed */ \
|
||||
memcpy ((P), OLD_PTR, BYTES); \
|
||||
void *NEW_PTR = (P); \
|
||||
(P) = (T*)OLD_PTR; \
|
||||
DEALLOC ((P), old_size / 2); \
|
||||
(P) = (T*)NEW_PTR; \
|
||||
(P) = (T*)NEW_PTR; \
|
||||
} while (0)
|
||||
|
||||
#define RESIZE2(T, P) \
|
||||
|
|
@ -509,7 +510,8 @@ static void clear_cadical_kitten (cadical_kitten *cadical_kitten) {
|
|||
void *OLD_PTR = (P); \
|
||||
CALLOC (T, (P), new_size); \
|
||||
const size_t BYTES = old_lits * sizeof *(P); \
|
||||
memcpy ((P), OLD_PTR, BYTES); \
|
||||
if ((P) && OLD_PTR) /* nullptr not allowed */ \
|
||||
memcpy ((P), OLD_PTR, BYTES); \
|
||||
void *NEW_PTR = (P); \
|
||||
(P) = (T*)OLD_PTR; \
|
||||
DEALLOC ((P), old_size); \
|
||||
|
|
@ -839,7 +841,8 @@ static void enlarge_external (cadical_kitten *cadical_kitten, size_t eidx) {
|
|||
unsigned *old_import = cadical_kitten->import;
|
||||
CALLOC (unsigned, cadical_kitten->import, new_size);
|
||||
const size_t bytes = old_evars * sizeof *cadical_kitten->import;
|
||||
memcpy (cadical_kitten->import, old_import, bytes);
|
||||
if (cadical_kitten->import && old_import)
|
||||
memcpy (cadical_kitten->import, old_import, bytes);
|
||||
DEALLOC (old_import, old_size);
|
||||
cadical_kitten->esize = new_size;
|
||||
}
|
||||
|
|
@ -927,10 +930,14 @@ void cadical_kitten_clear (cadical_kitten *cadical_kitten) {
|
|||
CADICAL_assert (!cadical_kitten->marks[i]);
|
||||
#endif
|
||||
|
||||
memset (cadical_kitten->phases, 0, vars);
|
||||
memset (cadical_kitten->values, 0, lits);
|
||||
memset (cadical_kitten->failed, 0, lits);
|
||||
memset (cadical_kitten->vars, 0, vars);
|
||||
if (cadical_kitten->phases)
|
||||
memset (cadical_kitten->phases, 0, vars);
|
||||
if (cadical_kitten->values)
|
||||
memset (cadical_kitten->values, 0, lits);
|
||||
if (cadical_kitten->failed)
|
||||
memset (cadical_kitten->failed, 0, lits);
|
||||
if (cadical_kitten->vars)
|
||||
memset (cadical_kitten->vars, 0, vars);
|
||||
|
||||
clear_cadical_kitten (cadical_kitten);
|
||||
}
|
||||
|
|
@ -2441,14 +2448,6 @@ int cadical_kitten_compute_prime_implicant (cadical_kitten *cadical_kitten, void
|
|||
return res;
|
||||
}
|
||||
|
||||
static bool contains_blit (cadical_kitten *cadical_kitten, klause *c, const unsigned blit) {
|
||||
for (all_literals_in_klause (lit, c)) {
|
||||
if (lit == blit)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool prime_propagate_blit (cadical_kitten *cadical_kitten, const unsigned idx,
|
||||
const unsigned blit) {
|
||||
unsigned lit = 2 * idx;
|
||||
|
|
@ -2518,7 +2517,9 @@ static bool prime_propagate_blit (cadical_kitten *cadical_kitten, const unsigned
|
|||
|
||||
static int compute_prime_implicant_for (cadical_kitten *cadical_kitten, unsigned blit) {
|
||||
value *values = cadical_kitten->values;
|
||||
#ifndef CADICAL_NDEBUG
|
||||
kar *vars = cadical_kitten->vars;
|
||||
#endif
|
||||
unsigneds unassigned;
|
||||
INIT_STACK (unassigned);
|
||||
bool limit_hit = false;
|
||||
|
|
@ -2532,7 +2533,7 @@ static int compute_prime_implicant_for (cadical_kitten *cadical_kitten, unsigned
|
|||
values[blit] = 0;
|
||||
values[blit ^ 1] = 0;
|
||||
PUSH_STACK (unassigned, tmp > 0 ? blit : blit ^ 1);
|
||||
PUSH_STACK (cadical_kitten->prime[i], block); // will be negated!
|
||||
PUSH_STACK (cadical_kitten->prime[ignoring], block); // will be negated!
|
||||
} else
|
||||
CADICAL_assert (false);
|
||||
for (all_stack (unsigned, lit, cadical_kitten->trail)) {
|
||||
|
|
@ -2546,7 +2547,6 @@ static int compute_prime_implicant_for (cadical_kitten *cadical_kitten, unsigned
|
|||
continue;
|
||||
CADICAL_assert (values[lit]); // not true when flipping is involved
|
||||
const unsigned idx = lit / 2;
|
||||
const unsigned ref = vars[idx].reason;
|
||||
CADICAL_assert (vars[idx].level);
|
||||
LOG ("non-prime candidate var %d", idx);
|
||||
if (prime_propagate_blit (cadical_kitten, idx, block)) {
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ void LidrupTracer::lidrup_solve_query () {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void LidrupTracer::add_derived_clause (int64_t id, bool,
|
||||
void LidrupTracer::add_derived_clause (int64_t id, bool, int,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &chain) {
|
||||
if (file->closed ())
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Last::Last () { memset (this, 0, sizeof *this); }
|
|||
|
||||
Inc::Inc () {
|
||||
memset (this, 0, sizeof *this);
|
||||
decisions = conflicts = -1; // unlimited
|
||||
ticks = decisions = conflicts = -1; // unlimited
|
||||
}
|
||||
|
||||
void Internal::limit_terminate (int l) {
|
||||
|
|
@ -66,6 +66,18 @@ void Internal::limit_decisions (int l) {
|
|||
}
|
||||
}
|
||||
|
||||
void Internal::limit_ticks (int64_t l) {
|
||||
if (l < 0 && inc.ticks < 0) {
|
||||
LOG ("keeping unbounded ticks limit");
|
||||
} else if (l < 0) {
|
||||
LOG ("reset ticks limit to be unbounded");
|
||||
inc.ticks = -1;
|
||||
} else {
|
||||
inc.ticks = l;
|
||||
LOG ("new ticks limit of %" PRId64 " ticks", l);
|
||||
}
|
||||
}
|
||||
|
||||
void Internal::limit_preprocessing (int l) {
|
||||
if (l < 0) {
|
||||
LOG ("ignoring invalid preprocessing limit %d", l);
|
||||
|
|
@ -101,6 +113,8 @@ bool Internal::is_valid_limit (const char *name) {
|
|||
return true;
|
||||
if (!strcmp (name, "localsearch"))
|
||||
return true;
|
||||
if (!strcmp (name, "ticks"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +130,8 @@ bool Internal::limit (const char *name, int l) {
|
|||
limit_preprocessing (l);
|
||||
else if (!strcmp (name, "localsearch"))
|
||||
limit_local_search (l);
|
||||
else if (!strcmp (name, "ticks"))
|
||||
limit_ticks (l);
|
||||
else
|
||||
res = false;
|
||||
return res;
|
||||
|
|
@ -128,6 +144,7 @@ void Internal::reset_limits () {
|
|||
limit_decisions (-1);
|
||||
limit_preprocessing (0);
|
||||
limit_local_search (0);
|
||||
limit_ticks (-1);
|
||||
}
|
||||
|
||||
} // namespace CaDiCaL
|
||||
|
|
|
|||
|
|
@ -92,9 +92,8 @@ void Logger::log (Internal *internal, const Gate *g, const char *fmt, ...) {
|
|||
vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
if (g) {
|
||||
printf ("%s%s%s gate[%" PRIu64 "] (arity: %ld) %s := %s",
|
||||
g->degenerated_and_pos ? " deg+" : "",
|
||||
g->degenerated_and_neg ? " deg-" : "",
|
||||
printf ("%s%s gate[%" PRIu64 "] (arity: %zu) %s := %s",
|
||||
special_gate_str (g->degenerated_gate).c_str (),
|
||||
g->garbage ? " garbage" : "", g->id, g->arity (),
|
||||
loglit (internal, g->lhs).c_str (),
|
||||
string_of_gate (g->tag).c_str ());
|
||||
|
|
|
|||
|
|
@ -478,16 +478,20 @@ void LratChecker::add_original_clause (int64_t id, bool,
|
|||
STOP (checking);
|
||||
}
|
||||
|
||||
void LratChecker::add_derived_clause (int64_t id, bool,
|
||||
void LratChecker::add_derived_clause (int64_t id, bool, int w,
|
||||
const vector<int> &c,
|
||||
const vector<int64_t> &proof_chain) {
|
||||
START (checking);
|
||||
LOG (c, "LRAT CHECKER addition of derived clause[%" PRId64 "]", id);
|
||||
LOG (c, "LRAT CHECKER addition of derived %d clause[%" PRId64 "]", w, id);
|
||||
CADICAL_assert (!w || c[0] == w);
|
||||
if (w)
|
||||
stats.rat++;
|
||||
stats.added++;
|
||||
stats.derived++;
|
||||
import_clause (c);
|
||||
last_id = id;
|
||||
CADICAL_assert (id == current_id + 1);
|
||||
CADICAL_assert (!w || w == c[0]);
|
||||
current_id = id;
|
||||
if (size_clauses) {
|
||||
LratCheckerClause **p = find (id), *d = *p;
|
||||
|
|
@ -541,7 +545,7 @@ void LratChecker::add_assumption_clause (int64_t id, const vector<int> &c,
|
|||
stderr);
|
||||
fatal_message_end ();
|
||||
}
|
||||
add_derived_clause (id, true, c, chain);
|
||||
add_derived_clause (id, true, 0, c, chain);
|
||||
delete_clause (id, true, c);
|
||||
assumption_clauses.push_back (id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ void LratTracer::lrat_delete_clause (int64_t id) {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void LratTracer::add_derived_clause (int64_t id, bool,
|
||||
void LratTracer::add_derived_clause (int64_t id, bool, int,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &chain) {
|
||||
if (file->closed ())
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace CaDiCaL {
|
|||
|
||||
int Internal::unlucky (int res) {
|
||||
if (level > 0)
|
||||
backtrack ();
|
||||
backtrack_without_updating_phases ();
|
||||
if (conflict)
|
||||
conflict = 0;
|
||||
return res;
|
||||
|
|
@ -34,7 +34,9 @@ int Internal::unlucky (int res) {
|
|||
int Internal::trivially_false_satisfiable () {
|
||||
LOG ("checking that all clauses contain a negative literal");
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (const auto &c : clauses) {
|
||||
if (terminated_asynchronously (100))
|
||||
return unlucky (-1);
|
||||
|
|
@ -81,7 +83,9 @@ int Internal::trivially_false_satisfiable () {
|
|||
int Internal::trivially_true_satisfiable () {
|
||||
LOG ("checking that all clauses contain a positive literal");
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (const auto &c : clauses) {
|
||||
if (terminated_asynchronously (100))
|
||||
return unlucky (-1);
|
||||
|
|
@ -132,7 +136,8 @@ inline bool Internal::lucky_propagate_discrepency (int dec) {
|
|||
if (no_conflict)
|
||||
return false;
|
||||
if (level > 1) {
|
||||
backtrack (level - 1);
|
||||
conflict = nullptr;
|
||||
backtrack_without_updating_phases (level - 1);
|
||||
search_assume_decision (-dec);
|
||||
no_conflict = propagate ();
|
||||
if (no_conflict)
|
||||
|
|
@ -155,7 +160,9 @@ int Internal::forward_false_satisfiable () {
|
|||
LOG ("checking increasing variable index false assignment");
|
||||
CADICAL_assert (!unsat);
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (auto idx : vars) {
|
||||
START:
|
||||
if (terminated_asynchronously (100))
|
||||
|
|
@ -180,7 +187,9 @@ int Internal::forward_true_satisfiable () {
|
|||
LOG ("checking increasing variable index true assignment");
|
||||
CADICAL_assert (!unsat);
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (auto idx : vars) {
|
||||
START:
|
||||
if (terminated_asynchronously (10))
|
||||
|
|
@ -207,8 +216,11 @@ int Internal::backward_false_satisfiable () {
|
|||
LOG ("checking decreasing variable index false assignment");
|
||||
CADICAL_assert (!unsat);
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
for (int idx = max_var; idx > 0; idx--) {
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (auto it = vars.rbegin (); it != vars.rend (); ++it) {
|
||||
int idx = *it;
|
||||
START:
|
||||
if (terminated_asynchronously (10))
|
||||
return unlucky (-1);
|
||||
|
|
@ -232,8 +244,11 @@ int Internal::backward_true_satisfiable () {
|
|||
LOG ("checking decreasing variable index true assignment");
|
||||
CADICAL_assert (!unsat);
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
for (int idx = max_var; idx > 0; idx--) {
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (auto it = vars.rbegin (); it != vars.rend (); ++it) {
|
||||
int idx = *it;
|
||||
START:
|
||||
if (terminated_asynchronously (10))
|
||||
return unlucky (-1);
|
||||
|
|
@ -264,7 +279,9 @@ int Internal::backward_true_satisfiable () {
|
|||
int Internal::positive_horn_satisfiable () {
|
||||
LOG ("checking that all clauses are positive horn satisfiable");
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (const auto &c : clauses) {
|
||||
if (terminated_asynchronously (10))
|
||||
return unlucky (-1);
|
||||
|
|
@ -320,10 +337,50 @@ int Internal::positive_horn_satisfiable () {
|
|||
return 10;
|
||||
}
|
||||
|
||||
int Internal::negative_horn_satisfiable () {
|
||||
LOG ("checking that all clauses are negative horn satisfiable");
|
||||
int Internal::lucky_decide_assumptions () {
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (assumptions.empty ());
|
||||
CADICAL_assert (!constraint.size ());
|
||||
int res = 0;
|
||||
while ((size_t) level < assumptions.size ()) {
|
||||
res = decide ();
|
||||
if (res == 20) {
|
||||
marked_failed = false;
|
||||
return 20;
|
||||
}
|
||||
if (!propagate ()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (conflict) {
|
||||
// analyze and learn from the conflict.
|
||||
LOG (conflict, "setting assumption lead to conflict");
|
||||
analyze_wrapper ();
|
||||
backtrack (0);
|
||||
CADICAL_assert (!conflict);
|
||||
int res = 0;
|
||||
while (!res) {
|
||||
CADICAL_assert ((size_t) level <= assumptions.size ());
|
||||
if (unsat)
|
||||
res = 20;
|
||||
else if (!propagate ()) {
|
||||
analyze_wrapper ();
|
||||
} else {
|
||||
res = decide_wrapper ();
|
||||
}
|
||||
}
|
||||
CADICAL_assert (res == 20);
|
||||
return 20;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Internal::negative_horn_satisfiable () {
|
||||
CADICAL_assert (!level);
|
||||
LOG ("checking that all clauses are negative horn satisfiable");
|
||||
int res = lucky_decide_assumptions ();
|
||||
if (res)
|
||||
return res;
|
||||
for (const auto &c : clauses) {
|
||||
if (terminated_asynchronously (10))
|
||||
return unlucky (-1);
|
||||
|
|
@ -350,7 +407,7 @@ int Internal::negative_horn_satisfiable () {
|
|||
continue;
|
||||
if (!negative_literal) {
|
||||
if (level > 0)
|
||||
backtrack ();
|
||||
backtrack_without_updating_phases ();
|
||||
LOG (c, "no negative unassigned literal in");
|
||||
return unlucky (0);
|
||||
}
|
||||
|
|
@ -389,15 +446,21 @@ int Internal::lucky_phases () {
|
|||
if (!opts.lucky)
|
||||
return 0;
|
||||
|
||||
// TODO: Some of the lucky assignments can also be found if there are
|
||||
// assumptions, but this is not completely implemented nor tested yet.
|
||||
// Nothing done for constraint either.
|
||||
// External propagator assumes a CDCL loop, so lucky is not tried here.
|
||||
if (!assumptions.empty () || !constraint.empty () || external_prop)
|
||||
if (!opts.luckyassumptions && !assumptions.empty ())
|
||||
return 0;
|
||||
// TODO: Some of the lucky assignments can also be found if there are
|
||||
// constraint.
|
||||
// External propagator assumes a CDCL loop, so lucky is not tried here.
|
||||
if (!constraint.empty () || external_prop)
|
||||
return 0;
|
||||
if (!propagate ()) {
|
||||
learn_empty_clause ();
|
||||
return 20;
|
||||
}
|
||||
|
||||
START (search);
|
||||
START (lucky);
|
||||
LOG ("starting lucky");
|
||||
CADICAL_assert (!searching_lucky_phases);
|
||||
searching_lucky_phases = true;
|
||||
stats.lucky.tried++;
|
||||
|
|
@ -405,18 +468,18 @@ int Internal::lucky_phases () {
|
|||
int res = trivially_false_satisfiable ();
|
||||
if (!res)
|
||||
res = trivially_true_satisfiable ();
|
||||
if (!res)
|
||||
res = forward_true_satisfiable ();
|
||||
if (!res)
|
||||
res = forward_false_satisfiable ();
|
||||
if (!res)
|
||||
res = forward_true_satisfiable ();
|
||||
if (!res)
|
||||
res = backward_false_satisfiable ();
|
||||
if (!res)
|
||||
res = backward_true_satisfiable ();
|
||||
if (!res)
|
||||
res = positive_horn_satisfiable ();
|
||||
if (!res)
|
||||
res = negative_horn_satisfiable ();
|
||||
if (!res)
|
||||
res = positive_horn_satisfiable ();
|
||||
if (res < 0)
|
||||
CADICAL_assert (termination_forced), res = 0;
|
||||
if (res == 10)
|
||||
|
|
@ -424,11 +487,20 @@ int Internal::lucky_phases () {
|
|||
report ('l', !res);
|
||||
CADICAL_assert (searching_lucky_phases);
|
||||
|
||||
CADICAL_assert (res || !level);
|
||||
if (res != 20) {
|
||||
if (!propagate ()) {
|
||||
LOG ("propagating units after elimination results in empty clause");
|
||||
learn_empty_clause ();
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t units = active_before - stats.active;
|
||||
|
||||
if (!res && units)
|
||||
LOG ("lucky %zd units", units);
|
||||
LOG ("lucky %" PRId64 " units", units);
|
||||
searching_lucky_phases = false;
|
||||
|
||||
STOP (lucky);
|
||||
STOP (search);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ void Internal::vmessage (const char *fmt, va_list &ap) {
|
|||
}
|
||||
|
||||
void Internal::message (const char *fmt, ...) {
|
||||
#ifdef LOGGING
|
||||
if (!opts.log)
|
||||
#endif
|
||||
if (opts.quiet)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start (ap, fmt);
|
||||
vmessage (fmt, ap);
|
||||
|
|
|
|||
|
|
@ -52,6 +52,18 @@ inline const char *Parser::parse_positive_int (int &ch, int &res,
|
|||
return 0;
|
||||
}
|
||||
|
||||
inline const char *Parser::parse_positive_uint64_t (int &ch, uint64_t &res,
|
||||
const char *name) {
|
||||
CADICAL_assert (isdigit (ch));
|
||||
res = ch - '0';
|
||||
while (isdigit (ch = parse_char ())) {
|
||||
int digit = ch - '0';
|
||||
if (UINT64_MAX / 10 < res || UINT64_MAX - digit < 10 * res)
|
||||
PER ("too large '%s' in header", name);
|
||||
res = 10 * res + digit;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static const char *cube_token = "unexpected 'a' in CNF";
|
||||
|
||||
inline const char *Parser::parse_lit (int &ch, int &lit, int &vars,
|
||||
|
|
@ -99,7 +111,8 @@ const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
|
|||
#endif
|
||||
|
||||
bool found_inccnf_header = false;
|
||||
int ch, clauses = 0;
|
||||
int ch = 0;
|
||||
uint64_t clauses = 0;
|
||||
vars = 0;
|
||||
|
||||
// First read comments before header with possibly embedded options.
|
||||
|
|
@ -162,11 +175,12 @@ const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
|
|||
PER ("expected ' ' after 'p cnf %d'", vars);
|
||||
if (!isdigit (ch = parse_char ()))
|
||||
PER ("expected digit after 'p cnf %d '", vars);
|
||||
err = parse_positive_int (ch, clauses, "<num-clauses>");
|
||||
err = parse_positive_uint64_t (ch, clauses, "<num-clauses>");
|
||||
if (err)
|
||||
return err;
|
||||
if (ch != '\n')
|
||||
PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
|
||||
PER ("expected new-line after 'p cnf %d %" PRIu64 "'", vars,
|
||||
clauses);
|
||||
} else {
|
||||
if (parse_char () != 'n')
|
||||
PER ("expected 'n' after 'p c'");
|
||||
|
|
@ -190,21 +204,22 @@ const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
|
|||
while (isspace (ch));
|
||||
if (!isdigit (ch))
|
||||
PER ("expected digit after 'p cnf %d '", vars);
|
||||
err = parse_positive_int (ch, clauses, "<num-clauses>");
|
||||
err = parse_positive_uint64_t (ch, clauses, "<num-clauses>");
|
||||
if (err)
|
||||
return err;
|
||||
while (ch != '\n') {
|
||||
if (ch != '\r' && !isspace (ch))
|
||||
PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
|
||||
PER ("expected new-line after 'p cnf %d %" PRIu64 "'", vars,
|
||||
clauses);
|
||||
ch = parse_char ();
|
||||
}
|
||||
}
|
||||
|
||||
MSG ("found %s'p cnf %d %d'%s header", tout.green_code (), vars,
|
||||
clauses, tout.normal_code ());
|
||||
MSG ("found %s'p cnf %d %" PRIu64 "'%s header", tout.green_code (),
|
||||
vars, clauses, tout.normal_code ());
|
||||
|
||||
if (strict != FORCED)
|
||||
solver->reserve (vars);
|
||||
solver->resize (vars);
|
||||
internal->reserve_ids (clauses);
|
||||
} else if (!parse_inccnf_too)
|
||||
PER ("expected 'c' after 'p '");
|
||||
|
|
@ -237,7 +252,8 @@ const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
|
|||
|
||||
// Now read body of DIMACS part.
|
||||
//
|
||||
int lit = 0, parsed = 0;
|
||||
int lit = 0;
|
||||
uint64_t parsed = 0;
|
||||
while ((ch = parse_char ()) != EOF) {
|
||||
if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r')
|
||||
continue;
|
||||
|
|
@ -272,8 +288,8 @@ const char *Parser::parse_dimacs_non_profiled (int &vars, int strict) {
|
|||
|
||||
#ifndef CADICAL_QUIET
|
||||
double end = internal->time ();
|
||||
MSG ("parsed %d clauses in %.2f seconds %s time", parsed, end - start,
|
||||
internal->opts.realtime ? "real" : "process");
|
||||
MSG ("parsed %" PRIu64 " clauses in %.2f seconds %s time", parsed,
|
||||
end - start, internal->opts.realtime ? "real" : "process");
|
||||
#endif
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
|
|
|
|||
|
|
@ -8,8 +8,20 @@ namespace CaDiCaL {
|
|||
|
||||
void Internal::copy_phases (vector<signed char> &dst) {
|
||||
START (copy);
|
||||
for (auto i : vars)
|
||||
dst[i] = phases.saved[i];
|
||||
for (auto i : vars) {
|
||||
const signed char tmp = phases.saved[i];
|
||||
if (tmp)
|
||||
dst[i] = tmp;
|
||||
}
|
||||
STOP (copy);
|
||||
}
|
||||
|
||||
void Internal::save_assigned_phases (vector<signed char> &dst) {
|
||||
START (copy);
|
||||
for (auto i : vars) {
|
||||
if (vals[i])
|
||||
dst[i] = vals[i];
|
||||
}
|
||||
STOP (copy);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -426,8 +426,8 @@ bool Internal::probe_propagate () {
|
|||
const int lit = -trail[propagated++];
|
||||
LOG ("probe propagating %d over large clauses", -lit);
|
||||
Watches &ws = watches (lit);
|
||||
ticks += 1 + cache_lines (ws.size (),
|
||||
sizeof (sizeof (const_watch_iterator *)));
|
||||
ticks +=
|
||||
1 + cache_lines (ws.size (), sizeof (const_watch_iterator *));
|
||||
size_t i = 0, j = 0;
|
||||
while (i != ws.size ()) {
|
||||
const Watch w = ws[j++] = ws[i++];
|
||||
|
|
@ -838,7 +838,7 @@ bool Internal::probe () {
|
|||
LOG ("probing %d", probe);
|
||||
probe_assign_decision (probe);
|
||||
if (probe_propagate ())
|
||||
backtrack ();
|
||||
backtrack_without_updating_phases ();
|
||||
else
|
||||
failed_literal (probe);
|
||||
clean_probehbr_lrat ();
|
||||
|
|
@ -944,13 +944,16 @@ void CaDiCaL::Internal::inprobe (bool update_limits) {
|
|||
if (probe ())
|
||||
decompose ();
|
||||
|
||||
if (extract_gates ())
|
||||
if (extract_gates (preprocessing))
|
||||
decompose ();
|
||||
binary_clauses_backbone ();
|
||||
mark_duplicated_binary_clauses_as_garbage ();
|
||||
if (sweep ()) // full occurrence list
|
||||
decompose (); // ... and (ELS) afterwards.
|
||||
(void) vivify (); // resets watches
|
||||
transred (); // builds big.
|
||||
factor (); // resets watches, partial occurrence list
|
||||
binary_clauses_backbone ();
|
||||
factor (); // resets watches, partial occurrence list
|
||||
}
|
||||
|
||||
if (external_prop) {
|
||||
|
|
|
|||
|
|
@ -199,7 +199,9 @@ void Internal::flush_trace (bool print) {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Proof::Proof (Internal *s) : internal (s) { LOG ("PROOF new"); }
|
||||
Proof::Proof (Internal *s) : internal (s), witness (0) {
|
||||
LOG ("PROOF new");
|
||||
}
|
||||
|
||||
Proof::~Proof () { LOG ("PROOF delete"); }
|
||||
|
||||
|
|
@ -292,6 +294,20 @@ void Proof::add_derived_clause (Clause *c, const vector<int64_t> &chain) {
|
|||
add_derived_clause ();
|
||||
}
|
||||
|
||||
void Proof::add_derived_rat_clause (Clause *c, int w,
|
||||
const vector<int64_t> &chain) {
|
||||
LOG (c, "PROOF adding to proof derived witness %d", w);
|
||||
CADICAL_assert (clause.empty ());
|
||||
CADICAL_assert (proof_chain.empty ());
|
||||
add_literals (c);
|
||||
for (const auto &cid : chain)
|
||||
proof_chain.push_back (cid);
|
||||
clause_id = c->id;
|
||||
redundant = c->redundant;
|
||||
witness = w;
|
||||
add_derived_clause ();
|
||||
}
|
||||
|
||||
void Proof::add_derived_clause (int64_t id, bool r, const vector<int> &c,
|
||||
const vector<int64_t> &chain) {
|
||||
LOG (c, "PROOF adding derived clause");
|
||||
|
|
@ -306,6 +322,22 @@ void Proof::add_derived_clause (int64_t id, bool r, const vector<int> &c,
|
|||
add_derived_clause ();
|
||||
}
|
||||
|
||||
void Proof::add_derived_rat_clause (int64_t id, bool r, int l,
|
||||
const vector<int> &c,
|
||||
const vector<int64_t> &chain) {
|
||||
LOG (c, "PROOF adding derived witness %d clause", l);
|
||||
CADICAL_assert (clause.empty ());
|
||||
CADICAL_assert (proof_chain.empty ());
|
||||
for (const auto &lit : c)
|
||||
add_literal (lit);
|
||||
for (const auto &cid : chain)
|
||||
proof_chain.push_back (cid);
|
||||
clause_id = id;
|
||||
redundant = r;
|
||||
witness = l;
|
||||
add_derived_clause ();
|
||||
}
|
||||
|
||||
void Proof::add_assumption_clause (int64_t id, const vector<int> &c,
|
||||
const vector<int64_t> &chain) {
|
||||
// literals of c are already external
|
||||
|
|
@ -530,11 +562,13 @@ void Proof::add_derived_clause () {
|
|||
redundant);
|
||||
CADICAL_assert (clause_id);
|
||||
for (auto &tracer : tracers) {
|
||||
tracer->add_derived_clause (clause_id, redundant, clause, proof_chain);
|
||||
tracer->add_derived_clause (clause_id, redundant, witness, clause,
|
||||
proof_chain);
|
||||
}
|
||||
proof_chain.clear ();
|
||||
clause.clear ();
|
||||
clause_id = 0;
|
||||
witness = 0;
|
||||
}
|
||||
|
||||
void Proof::delete_clause () {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace CaDiCaL {
|
|||
// relevant in conflict analysis or in root-level fixing steps.
|
||||
|
||||
static Clause decision_reason_clause;
|
||||
static Clause *decision_reason = &decision_reason_clause;
|
||||
Clause *Internal::decision_reason = &decision_reason_clause;
|
||||
|
||||
// If chronological backtracking is used the actual assignment level might
|
||||
// be lower than the current decision level. In this case the assignment
|
||||
|
|
@ -89,7 +89,7 @@ void Internal::build_chain_for_units (int lit, Clause *reason,
|
|||
void Internal::build_chain_for_empty () {
|
||||
if (!lrat || !lrat_chain.empty ())
|
||||
return;
|
||||
CADICAL_assert (!level);
|
||||
CADICAL_assert (!level || in_mode (BACKBONE));
|
||||
CADICAL_assert (lrat_chain.empty ());
|
||||
CADICAL_assert (conflict);
|
||||
LOG (conflict, "lrat for global empty clause with conflict");
|
||||
|
|
@ -320,6 +320,7 @@ bool Internal::propagate () {
|
|||
}
|
||||
|
||||
literal_iterator lits = w.clause->begin ();
|
||||
CADICAL_assert (lits[0] == lit || lits[1] == lit);
|
||||
|
||||
// Simplify code by forcing 'lit' to be the second literal in the
|
||||
// clause. This goes back to MiniSAT. We use a branch-less version
|
||||
|
|
@ -351,7 +352,8 @@ bool Internal::propagate () {
|
|||
literal_iterator k = middle;
|
||||
|
||||
// Find replacement watch 'r' at position 'k' with value 'v'.
|
||||
|
||||
CADICAL_assert (lits + 2 <= k);
|
||||
LOG (w.clause, "search starting at %d", w.clause->pos);
|
||||
int r = 0;
|
||||
signed char v = -1;
|
||||
|
||||
|
|
@ -492,6 +494,10 @@ bool Internal::propagate () {
|
|||
}
|
||||
}
|
||||
|
||||
if (conflict && randomized_deciding) {
|
||||
if (!--randomized_deciding)
|
||||
VERBOSE (3, "last random decision conflict");
|
||||
}
|
||||
STOP (propagate);
|
||||
|
||||
return !conflict;
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ void Internal::mark_clauses_to_be_flushed () {
|
|||
const unsigned used = c->used;
|
||||
if (used)
|
||||
c->used--;
|
||||
if (c->glue < tier1limit && used)
|
||||
if (c->glue <= tier1limit && used)
|
||||
continue;
|
||||
if (c->glue < tier2limit && used >= max_used - 1)
|
||||
if (c->glue <= tier2limit && used >= max_used - 1)
|
||||
continue;
|
||||
mark_garbage (c); // flush unused clauses
|
||||
if (c->hyper)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ bool Internal::rephasing () {
|
|||
return false;
|
||||
if (opts.forcephase)
|
||||
return false;
|
||||
if (opts.rephase == 2) {
|
||||
if (stable)
|
||||
return stats.stabconflicts > lim.rephase;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return stats.conflicts > lim.rephase;
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +105,10 @@ char Internal::rephase_walk () {
|
|||
stats.rephased.walk++;
|
||||
PHASE ("rephase", stats.rephased.total,
|
||||
"starting local search to improve current phase");
|
||||
walk ();
|
||||
if (opts.walkfullocc)
|
||||
walk_full_occs ();
|
||||
else
|
||||
walk ();
|
||||
return 'W';
|
||||
}
|
||||
|
||||
|
|
@ -108,9 +117,12 @@ char Internal::rephase_walk () {
|
|||
void Internal::rephase () {
|
||||
|
||||
stats.rephased.total++;
|
||||
last.stabilize.rephased++;
|
||||
CADICAL_assert (last.stabilize.rephased <= stats.rephased.total);
|
||||
PHASE ("rephase", stats.rephased.total,
|
||||
"reached rephase limit %" PRId64 " after %" PRId64 " conflicts",
|
||||
lim.rephase, stats.conflicts);
|
||||
lim.rephase,
|
||||
opts.rephase == 2 ? stats.stabconflicts : stats.conflicts);
|
||||
|
||||
// Report current 'target' and 'best' and then set 'rephased' below, which
|
||||
// will trigger reporting the new 'target' and 'best' after updating it in
|
||||
|
|
@ -119,8 +131,6 @@ void Internal::rephase () {
|
|||
report ('~', 1);
|
||||
|
||||
backtrack ();
|
||||
clear_phases (phases.target);
|
||||
target_assigned = 0;
|
||||
|
||||
size_t count = lim.rephased[stable]++;
|
||||
bool single;
|
||||
|
|
@ -208,6 +218,52 @@ void Internal::rephase () {
|
|||
type = 0;
|
||||
break;
|
||||
}
|
||||
} else if (opts.rephase == 2 && opts.walk) {
|
||||
// (inverted,best,walk,
|
||||
// flipping,best,walk,
|
||||
// random,best,walk,
|
||||
// original,best,walk)^\omega
|
||||
switch (count % 12) {
|
||||
case 0:
|
||||
type = rephase_inverted ();
|
||||
break;
|
||||
case 1:
|
||||
type = rephase_best ();
|
||||
break;
|
||||
case 2:
|
||||
type = rephase_walk ();
|
||||
break;
|
||||
case 3:
|
||||
type = rephase_flipping ();
|
||||
break;
|
||||
case 4:
|
||||
type = rephase_best ();
|
||||
break;
|
||||
case 5:
|
||||
type = rephase_walk ();
|
||||
break;
|
||||
case 6:
|
||||
type = rephase_random ();
|
||||
break;
|
||||
case 7:
|
||||
type = rephase_best ();
|
||||
break;
|
||||
case 8:
|
||||
type = rephase_walk ();
|
||||
break;
|
||||
case 9:
|
||||
type = rephase_original ();
|
||||
break;
|
||||
case 10:
|
||||
type = rephase_best ();
|
||||
break;
|
||||
case 11:
|
||||
type = rephase_walk ();
|
||||
break;
|
||||
default:
|
||||
type = 0;
|
||||
break;
|
||||
}
|
||||
} else if (stable && !opts.walk) {
|
||||
// original,inverted,(best,original,best,inverted)^\omega
|
||||
if (!count)
|
||||
|
|
@ -288,7 +344,7 @@ void Internal::rephase () {
|
|||
CADICAL_assert (!stable && opts.walk && opts.walknonstable);
|
||||
// flipping,(random,best,walk,flipping,best,walk)^\omega
|
||||
if (!count)
|
||||
type = rephase_flipping ();
|
||||
type = rephase_original ();
|
||||
else
|
||||
switch ((count - 1) % 6) {
|
||||
case 0:
|
||||
|
|
@ -316,8 +372,14 @@ void Internal::rephase () {
|
|||
}
|
||||
CADICAL_assert (type);
|
||||
|
||||
// clear after walk such that random walk can still access the target
|
||||
// by using the saved phases
|
||||
copy_phases (phases.target);
|
||||
target_assigned = 0;
|
||||
|
||||
int64_t delta = opts.rephaseint * (stats.rephased.total + 1);
|
||||
lim.rephase = stats.conflicts + delta;
|
||||
lim.rephase =
|
||||
(opts.rephase == 2 ? stats.stabconflicts : stats.conflicts) + delta;
|
||||
|
||||
PHASE ("rephase", stats.rephased.total,
|
||||
"new rephase limit %" PRId64 " after %" PRId64 " conflicts",
|
||||
|
|
@ -331,6 +393,10 @@ void Internal::rephase () {
|
|||
last.rephase.conflicts = stats.conflicts;
|
||||
rephased = type;
|
||||
|
||||
if (!marked_failed || unsat_constraint) {
|
||||
CADICAL_assert (opts.warmup);
|
||||
return;
|
||||
}
|
||||
if (stable)
|
||||
shuffle_scores ();
|
||||
else
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ r start of solving after restoring clauses
|
|||
1 end of solving returns satisfiable
|
||||
0 end of solving returns unsatisfiable
|
||||
? end of solving due to interrupt
|
||||
k binary backbone extraction ('kernel')
|
||||
l lucky phase solving
|
||||
p failed literal probing round (lower case 'p')
|
||||
. before reducing redundant clauses
|
||||
|
|
@ -138,8 +139,13 @@ Report::Report (const char *h, int precision, int min, double value)
|
|||
REPORT ("rate", 0, 2, averages.current.decisions) \
|
||||
REPORT ("conflicts", 0, 4, stats.conflicts) \
|
||||
REPORT ("redundant", 0, 4, stats.current.redundant) \
|
||||
REPORT ("trail", -1, 2, TRAIL) \
|
||||
REPORT ("size/glue", 1, 2, \
|
||||
relative (averages.current.size, averages.current.glue.slow)) \
|
||||
REPORT ("size", 0, 1, averages.current.size) \
|
||||
REPORT ("glue", 0, 1, averages.current.glue.slow) \
|
||||
REPORT ("tier1", 0, 1, tier1[stable]) \
|
||||
REPORT ("tier2", 0, 1, tier2[stable]) \
|
||||
REPORT ("trail", -1, 2, TRAIL) \
|
||||
REPORT ("irredundant", 0, 4, stats.current.irredundant) \
|
||||
REPORT ("variables", 0, 3, active ()) \
|
||||
REPORT ("remaining", -1, 2, REMAINING)
|
||||
|
|
@ -273,12 +279,23 @@ void Internal::report (char type, int verbose) {
|
|||
tout.bold ();
|
||||
tout.underline ();
|
||||
break;
|
||||
case '(':
|
||||
case ')':
|
||||
tout.bold ();
|
||||
tout.yellow ();
|
||||
break;
|
||||
case '{':
|
||||
case '}':
|
||||
tout.normal ();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fputc (type, stdout);
|
||||
if (stable || type == ']')
|
||||
tout.magenta ();
|
||||
else if (preprocessing || type == ')')
|
||||
tout.bold (), tout.yellow ();
|
||||
else if (type != 'L' && type != 'P')
|
||||
tout.normal ();
|
||||
for (int i = 0; i < n; i++) {
|
||||
|
|
|
|||
|
|
@ -35,12 +35,19 @@ bool Internal::stabilizing () {
|
|||
STOP (stable);
|
||||
else
|
||||
STOP (unstable);
|
||||
//const int64_t delta_conflicts =
|
||||
// stats.conflicts - last.stabilize.conflicts;
|
||||
|
||||
CADICAL_assert (last.stabilize.ticks >= 0);
|
||||
CADICAL_assert (last.stabilize.conflicts >= 0 &&
|
||||
last.stabilize.conflicts <= stats.conflicts);
|
||||
CADICAL_assert (last.stabilize.ticks <= stats.ticks.search[stable]);
|
||||
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";
|
||||
#ifndef CADICAL_QUIET
|
||||
const int64_t delta_conflicts =
|
||||
stats.conflicts - last.stabilize.conflicts;
|
||||
const char *current_mode = stable ? "stable" : "unstable";
|
||||
const char *next_mode = stable ? "unstable" : "stable";
|
||||
#endif
|
||||
PHASE ("stabilizing", stats.stabphases,
|
||||
"reached %s stabilization limit %" PRId64 " after %" PRId64
|
||||
" conflicts and %" PRId64 " ticks at %" PRId64
|
||||
|
|
@ -53,24 +60,26 @@ bool Internal::stabilizing () {
|
|||
// ticks
|
||||
inc.stabilize = 1;
|
||||
|
||||
stable = !stable; // Switch!!!!!
|
||||
|
||||
int64_t next_delta_ticks = inc.stabilize;
|
||||
int64_t stabphases = stats.stabphases + 1;
|
||||
next_delta_ticks *= stabphases * stabphases;
|
||||
|
||||
lim.stabilize = stats.ticks.search[stable] + next_delta_ticks;
|
||||
if (lim.stabilize <= stats.ticks.search[stable])
|
||||
lim.stabilize = stats.ticks.search[stable] + 1;
|
||||
const bool next_stable = !stable;
|
||||
lim.stabilize = stats.ticks.search[next_stable] + next_delta_ticks;
|
||||
last.stabilize.ticks = stats.ticks.search[next_stable];
|
||||
if (lim.stabilize <= stats.ticks.search[next_stable])
|
||||
lim.stabilize = stats.ticks.search[next_stable] + 1;
|
||||
PHASE ("stabilizing", stats.stabphases,
|
||||
"next %s stabilization limit %" PRId64
|
||||
" at ticks interval %" PRId64,
|
||||
next_mode, lim.stabilize, next_delta_ticks);
|
||||
|
||||
stable = !stable; // Switch!!!!!
|
||||
|
||||
if (stable)
|
||||
stats.stabphases++;
|
||||
|
||||
swap_averages ();
|
||||
PHASE ("stabilizing", stats.stabphases,
|
||||
"next %s stabilization limit %" PRId64
|
||||
" at ticks interval %" PRId64,
|
||||
next_mode, lim.stabilize, next_delta_ticks);
|
||||
report (stable ? '[' : '{');
|
||||
if (stable)
|
||||
START (stable);
|
||||
|
|
@ -91,14 +100,24 @@ bool Internal::restarting () {
|
|||
return false;
|
||||
if ((size_t) level < assumptions.size () + 2)
|
||||
return false;
|
||||
if (stabilizing ())
|
||||
if (stabilizing () && opts.reluctant)
|
||||
return reluctant;
|
||||
if (stats.conflicts <= lim.restart)
|
||||
return false;
|
||||
double f = averages.current.glue.fast;
|
||||
double margin = (100.0 + opts.restartmargin) / 100.0;
|
||||
double s = averages.current.glue.slow, l = margin * s;
|
||||
LOG ("EMA glue slow %.2f fast %.2f limit %.2f", s, f, l);
|
||||
int p = stable ? opts.restartmarginstable : opts.restartmarginfocused;
|
||||
double m = (100.0 + p) / 100.0;
|
||||
double s = averages.current.glue.slow;
|
||||
double l = m * s;
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
char c = l > f ? '>' : l < f ? '<' : '=';
|
||||
VERBOSE (3,
|
||||
"restart glue limit "
|
||||
"%g = %.2f * %g (slow glue) %c %g (fast glue)",
|
||||
l, m, s, c, f);
|
||||
#endif
|
||||
|
||||
return l <= f;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "cadical.hpp"
|
||||
#include "internal.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
|
@ -60,7 +61,7 @@ void Solver::transition_to_steady_state () {
|
|||
external->reset_assumptions ();
|
||||
external->reset_concluded ();
|
||||
external->reset_constraint ();
|
||||
} else if (state() == INCONCLUSIVE) {
|
||||
} else if (state () == INCONCLUSIVE) {
|
||||
external->reset_assumptions ();
|
||||
external->reset_concluded ();
|
||||
external->reset_constraint ();
|
||||
|
|
@ -92,6 +93,18 @@ static void log_api_call (Internal *internal, const char *name, int arg,
|
|||
name, arg, tout.log_code (), suffix);
|
||||
}
|
||||
|
||||
static void log_api_call (Internal *internal, const char *name, int arg,
|
||||
int b, const char *suffix) {
|
||||
Logger::log (internal, "API call %s'%s (%d, %d)'%s %s", tout.api_code (),
|
||||
name, arg, b, tout.log_code (), suffix);
|
||||
}
|
||||
|
||||
static void log_api_call (Internal *internal, const char *name, int arg,
|
||||
int b, int c) {
|
||||
Logger::log (internal, "API call %s'%s (%d, %d)'%s %d", tout.api_code (),
|
||||
name, arg, b, tout.log_code (), c);
|
||||
}
|
||||
|
||||
static void log_api_call (Internal *internal, const char *name,
|
||||
const char *arg, const char *suffix) {
|
||||
Logger::log (internal, "API call %s'%s (\"%s\")'%s %s", tout.api_code (),
|
||||
|
|
@ -119,6 +132,12 @@ static void log_api_call_begin (Internal *internal, const char *name,
|
|||
log_api_call (internal, name, arg, "started");
|
||||
}
|
||||
|
||||
static void log_api_call_begin (Internal *internal, const char *name,
|
||||
int arg, int b) {
|
||||
Logger::log_empty_line (internal);
|
||||
log_api_call (internal, name, arg, b, "started");
|
||||
}
|
||||
|
||||
static void log_api_call_begin (Internal *internal, const char *name,
|
||||
const char *arg) {
|
||||
Logger::log_empty_line (internal);
|
||||
|
|
@ -196,6 +215,11 @@ static void log_api_call_returns (Internal *internal, const char *name,
|
|||
res ? "returns 'true'" : "returns 'false'");
|
||||
}
|
||||
|
||||
static void log_api_call_returns (Internal *internal, const char *name,
|
||||
int lit, int b, int res) {
|
||||
log_api_call (internal, name, lit, b, res);
|
||||
}
|
||||
|
||||
static void log_api_call_returns (Internal *internal, const char *name,
|
||||
const char *arg, const char *res) {
|
||||
Logger::log (internal, "API call %s'%s (\"%s\")'%s returns '%s'",
|
||||
|
|
@ -281,6 +305,13 @@ void Solver::trace_api_call (const char *s0, int i1) const {
|
|||
fflush (trace_api_file);
|
||||
}
|
||||
|
||||
void Solver::trace_api_call (const char *s0, int i1, int b) const {
|
||||
CADICAL_assert (trace_api_file);
|
||||
LOG ("TRACE %s %d %d", s0, i1, b);
|
||||
fprintf (trace_api_file, "%s %d %d\n", s0, i1, b);
|
||||
fflush (trace_api_file);
|
||||
}
|
||||
|
||||
void Solver::trace_api_call (const char *s0, const char *s1) const {
|
||||
CADICAL_assert (trace_api_file);
|
||||
LOG ("TRACE %s %s", s0, s1);
|
||||
|
|
@ -437,23 +468,34 @@ int Solver::vars () {
|
|||
return res;
|
||||
}
|
||||
|
||||
void Solver::reserve (int min_max_var) {
|
||||
TRACE ("reserve", min_max_var);
|
||||
void Solver::resize (int min_max_var) {
|
||||
TRACE ("resize", min_max_var);
|
||||
REQUIRE_VALID_STATE ();
|
||||
transition_to_steady_state ();
|
||||
external->reset_extended ();
|
||||
external->init (min_max_var);
|
||||
LOG_API_CALL_END ("reserve", min_max_var);
|
||||
LOG_API_CALL_END ("resize", min_max_var);
|
||||
}
|
||||
|
||||
int Solver::reserve_difference (int number_of_vars) {
|
||||
TRACE ("reserve_difference", number_of_vars);
|
||||
int Solver::declare_more_variables (int number_of_vars) {
|
||||
TRACE ("declare_more_variables", number_of_vars);
|
||||
REQUIRE_VALID_STATE ();
|
||||
transition_to_steady_state ();
|
||||
external->reset_extended ();
|
||||
int new_max_var = external->max_var + number_of_vars;
|
||||
external->init (new_max_var);
|
||||
LOG_API_CALL_END ("reserve_difference", number_of_vars);
|
||||
LOG_API_CALL_END ("declare_more_variables", number_of_vars);
|
||||
return new_max_var;
|
||||
}
|
||||
|
||||
int Solver::declare_one_more_variable () {
|
||||
TRACE ("declare_one_more_variable");
|
||||
REQUIRE_VALID_STATE ();
|
||||
transition_to_steady_state ();
|
||||
external->reset_extended ();
|
||||
int new_max_var = external->max_var + 1;
|
||||
external->init (new_max_var);
|
||||
LOG_API_CALL_END ("declare_one_more_variable");
|
||||
return new_max_var;
|
||||
}
|
||||
|
||||
|
|
@ -673,8 +715,9 @@ void Solver::assume (int lit) {
|
|||
int Solver::lookahead () {
|
||||
TRACE ("lookahead");
|
||||
REQUIRE_VALID_OR_SOLVING_STATE ();
|
||||
transition_to_steady_state ();
|
||||
int lit = external->lookahead ();
|
||||
TRACE ("lookahead");
|
||||
LOG_API_CALL_END ("lookahead", lit);
|
||||
return lit;
|
||||
}
|
||||
|
||||
|
|
@ -730,8 +773,9 @@ int Solver::propagate () {
|
|||
void Solver::implied (std::vector<int> &entrailed) {
|
||||
TRACE ("implied");
|
||||
REQUIRE_VALID_STATE ();
|
||||
REQUIRE (state () == INCONCLUSIVE,
|
||||
"can only get implied literals only in unknown state");
|
||||
REQUIRE (
|
||||
state () == INCONCLUSIVE || state () == SATISFIED,
|
||||
"can only get implied literals only in unknown or satisfied state");
|
||||
external->conclude_unknown ();
|
||||
external->implied (entrailed);
|
||||
if (tracing_nb_lidrup_env_var_method)
|
||||
|
|
@ -775,11 +819,13 @@ int Solver::call_external_solve_and_check_results (bool preprocess_only) {
|
|||
FATAL ("copying assumption checker failed");
|
||||
}
|
||||
#endif
|
||||
#if 0 // was necessary when INCONCLUSIVE state did not exist
|
||||
if (!res) {
|
||||
external->reset_assumptions ();
|
||||
external->reset_constraint ();
|
||||
external->reset_concluded ();
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -799,23 +845,33 @@ int Solver::simplify (int rounds) {
|
|||
REQUIRE (rounds >= 0, "negative number of simplification rounds '%d'",
|
||||
rounds);
|
||||
internal->limit ("preprocessing", rounds);
|
||||
const int lucky = internal->opts.lucky;
|
||||
internal->opts.lucky = 0;
|
||||
const int res = call_external_solve_and_check_results (true);
|
||||
internal->opts.lucky = lucky;
|
||||
LOG_API_CALL_RETURNS ("simplify", rounds, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
int Solver::val (int lit) {
|
||||
TRACE ("val", lit);
|
||||
int Solver::val (
|
||||
int lit, bool use_default_value_for_declared_but_not_used_variable) {
|
||||
LOG_API_CALL_BEGIN (
|
||||
"val", lit,
|
||||
(int) use_default_value_for_declared_but_not_used_variable);
|
||||
REQUIRE_VALID_STATE ();
|
||||
REQUIRE_VALID_LIT (lit);
|
||||
REQUIRE (state () == SATISFIED, "can only get value in satisfied state");
|
||||
if (!use_default_value_for_declared_but_not_used_variable)
|
||||
REQUIRE (lit < external->max_var, "lit of undeclare variable");
|
||||
if (!external->extended)
|
||||
external->extend ();
|
||||
external->conclude_sat ();
|
||||
int res = external->ival (lit);
|
||||
LOG_API_CALL_RETURNS ("val", lit, res);
|
||||
LOG_API_CALL_RETURNS (
|
||||
"val", lit, use_default_value_for_declared_but_not_used_variable,
|
||||
res);
|
||||
CADICAL_assert (state () == SATISFIED);
|
||||
CADICAL_assert (res == lit || res == -lit);
|
||||
return res;
|
||||
|
|
@ -1247,9 +1303,10 @@ bool Solver::disconnect_proof_tracer (FileTracer *tracer) {
|
|||
void Solver::conclude () {
|
||||
TRACE ("conclude");
|
||||
REQUIRE_VALID_STATE ();
|
||||
REQUIRE (state () == UNSATISFIED || state () == SATISFIED ||
|
||||
state () == INCONCLUSIVE,
|
||||
"can only conclude in satisfied, unsatisfied or inconclusive state");
|
||||
REQUIRE (
|
||||
state () == UNSATISFIED || state () == SATISFIED ||
|
||||
state () == INCONCLUSIVE,
|
||||
"can only conclude in satisfied, unsatisfied or inconclusive state");
|
||||
if (state () == UNSATISFIED)
|
||||
internal->conclude_unsat ();
|
||||
else if (state () == SATISFIED)
|
||||
|
|
@ -1759,6 +1816,33 @@ void Solver::error (const char *fmt, ...) {
|
|||
va_end (ap);
|
||||
}
|
||||
|
||||
int64_t Solver::get_statistic_value (const char *opt) const {
|
||||
REQUIRE_INITIALIZED ();
|
||||
if (!strcmp (opt, "conflicts"))
|
||||
return internal->stats.conflicts;
|
||||
if (!strcmp (opt, "decisions"))
|
||||
return internal->stats.decisions;
|
||||
if (!strcmp (opt, "ticks"))
|
||||
return internal->stats.ticks.search[0] +
|
||||
internal->stats.ticks.search[1];
|
||||
if (!strcmp (opt, "propagations"))
|
||||
return internal->stats.propagations.search;
|
||||
if (!strcmp (opt, "clauses"))
|
||||
return internal->stats.current.total;
|
||||
if (!strcmp (opt, "redundant"))
|
||||
return internal->stats.current.redundant;
|
||||
if (!strcmp (opt, "irredundant"))
|
||||
return internal->stats.current.irredundant;
|
||||
if (!strcmp (opt, "fixed"))
|
||||
return internal->stats.all.fixed;
|
||||
if (!strcmp (opt, "eliminated"))
|
||||
return internal->stats.all.eliminated +
|
||||
internal->stats.all.fasteliminated;
|
||||
if (!strcmp (opt, "subsitutued"))
|
||||
return internal->stats.all.substituted;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
int Solver::clauses () {
|
||||
|
|
|
|||
|
|
@ -55,13 +55,12 @@ void Stats::print (Internal *internal) {
|
|||
propagations += stats.propagations.search;
|
||||
propagations += stats.propagations.transred;
|
||||
propagations += stats.propagations.vivify;
|
||||
propagations += stats.propagations.walk;
|
||||
|
||||
int64_t vivified = stats.vivifysubs + stats.vivifystrs;
|
||||
int64_t searchticks = stats.ticks.search[0] + stats.ticks.search[1];
|
||||
int64_t inprobeticks = stats.ticks.vivify + stats.ticks.probe +
|
||||
stats.ticks.factor + stats.ticks.ternary +
|
||||
stats.ticks.sweep;
|
||||
stats.ticks.sweep + stats.ticks.backbone;
|
||||
int64_t totalticks = searchticks + inprobeticks;
|
||||
|
||||
size_t extendbytes = internal->external->extension.size ();
|
||||
|
|
@ -96,6 +95,25 @@ void Stats::print (Internal *internal) {
|
|||
PRT (" backtracked: %15" PRId64 " %10.2f %% of conflicts",
|
||||
stats.backtracks, percent (stats.backtracks, stats.conflicts));
|
||||
}
|
||||
if (all || stats.incremental_decay) {
|
||||
PRT ("inc-decay: %15" PRId64 " %10.2f %% per search",
|
||||
stats.incremental_decay,
|
||||
percent (stats.incremental_decay, stats.searches));
|
||||
}
|
||||
if (all || stats.backbone.rounds) {
|
||||
PRT ("backbone: %15" PRId64 " %10.2f %% of vars",
|
||||
stats.backbone.probes,
|
||||
percent (stats.backbone.probes, stats.vars));
|
||||
PRT (" rounds: %15" PRId64 " %10.2f per phase",
|
||||
stats.backbone.rounds,
|
||||
relative (stats.backbone.rounds, stats.backbone.phases));
|
||||
PRT (" phases: %15" PRId64 " %10.2f interval",
|
||||
stats.backbone.phases,
|
||||
relative (stats.conflicts, stats.backbone.phases));
|
||||
PRT (" units: %15" PRId64 " %10.2f per phase",
|
||||
stats.backbone.units,
|
||||
relative (stats.backbone.units, stats.backbone.phases));
|
||||
}
|
||||
if (all || stats.conditioned) {
|
||||
PRT ("conditioned: %15" PRId64
|
||||
" %10.2f %% of irredundant clauses",
|
||||
|
|
@ -147,6 +165,15 @@ void Stats::print (Internal *internal) {
|
|||
PRT (" searched: %15" PRId64 " %10.2f per decision",
|
||||
stats.searched, relative (stats.searched, stats.decisions));
|
||||
}
|
||||
if (all || stats.randec.random_decisions) {
|
||||
PRT ("rand. dec phase: %15" PRId64 " %10.2f per interval",
|
||||
stats.randec.random_decision_phases,
|
||||
relative (stats.randec.random_decision_phases, stats.decisions));
|
||||
PRT ("random decs: %15" PRId64 " %10.2f per phase",
|
||||
stats.randec.random_decisions,
|
||||
relative (stats.randec.random_decisions,
|
||||
stats.randec.random_decision_phases));
|
||||
}
|
||||
if (all || stats.all.eliminated) {
|
||||
PRT ("eliminated: %15" PRId64 " %10.2f %% of all variables",
|
||||
stats.all.eliminated, percent (stats.all.eliminated, stats.vars));
|
||||
|
|
@ -301,7 +328,7 @@ void Stats::print (Internal *internal) {
|
|||
PRT ("learned: %15" PRId64 " %10.2f %% per conflict",
|
||||
stats.learned.clauses,
|
||||
percent (stats.learned.clauses, stats.conflicts));
|
||||
PRT ("@ bumped: %15" PRId64 " %10.2f per learned",
|
||||
PRT (" bumped: %15" PRId64 " %10.2f per learned",
|
||||
stats.bumped, relative (stats.bumped, stats.learned.clauses));
|
||||
PRT (" recomputed: %15" PRId64 " %10.2f %% per learned",
|
||||
stats.recomputed,
|
||||
|
|
@ -387,9 +414,6 @@ void Stats::print (Internal *internal) {
|
|||
PRT (" vivifyprops: %15" PRId64 " %10.2f %% of propagations",
|
||||
stats.propagations.vivify,
|
||||
percent (stats.propagations.vivify, propagations));
|
||||
PRT (" walkprops: %15" PRId64 " %10.2f %% of propagations",
|
||||
stats.propagations.walk,
|
||||
percent (stats.propagations.walk, propagations));
|
||||
if (all || stats.reactivated) {
|
||||
PRT ("reactivated: %15" PRId64 " %10.2f %% of all variables",
|
||||
stats.reactivated, percent (stats.reactivated, stats.vars));
|
||||
|
|
@ -610,6 +634,8 @@ void Stats::print (Internal *internal) {
|
|||
stats.ticks.search[0], percent (stats.ticks.search[0], searchticks));
|
||||
PRT (" inprobeticks: %15" PRId64 " %10.2f %% totalticks",
|
||||
inprobeticks, percent (inprobeticks, totalticks));
|
||||
PRT (" backboneticks:%15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.backbone, percent (stats.ticks.backbone, searchticks));
|
||||
PRT (" factorticks: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.factor, percent (stats.ticks.factor, searchticks));
|
||||
PRT (" probeticks: %15" PRId64 " %10.2f %% searchticks",
|
||||
|
|
@ -620,6 +646,20 @@ void Stats::print (Internal *internal) {
|
|||
stats.ticks.ternary, percent (stats.ticks.ternary, searchticks));
|
||||
PRT (" vivifyticks: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.vivify, percent (stats.ticks.vivify, searchticks));
|
||||
PRT (" walkticks: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walk, percent (stats.ticks.walk, searchticks));
|
||||
PRT (" walkflipticks:%15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walkflip, percent (stats.ticks.walkflip, searchticks));
|
||||
PRT (" walkflipbrk: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walkflipbroken,
|
||||
percent (stats.ticks.walkflipbroken, searchticks));
|
||||
PRT (" walkflipWL: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walkflipWL,
|
||||
percent (stats.ticks.walkflipWL, searchticks));
|
||||
PRT (" walkpickticks:%15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walkpick, percent (stats.ticks.walkpick, searchticks));
|
||||
PRT (" walkbreak: %15" PRId64 " %10.2f %% searchticks",
|
||||
stats.ticks.walkbreak, percent (stats.ticks.walkbreak, searchticks));
|
||||
if (all) {
|
||||
PRT ("tier recomputed: %15" PRId64 " %10.2f interval",
|
||||
stats.tierecomputed,
|
||||
|
|
@ -646,6 +686,18 @@ void Stats::print (Internal *internal) {
|
|||
relative (stats.conflicts, stats.vivifications));
|
||||
PRT (" vivifychecks: %15" PRId64 " %10.2f %% per conflict",
|
||||
stats.vivifychecks, percent (stats.vivifychecks, stats.conflicts));
|
||||
const int64_t vivified = stats.vivifiedtier1 + stats.vivifiedtier2 +
|
||||
stats.vivifiedtier3 + stats.vivifiedirred;
|
||||
PRT (" vivified: %15" PRId64 " %10.2f %% per check", vivified,
|
||||
percent (vivified, stats.vivifychecks));
|
||||
PRT (" vified-irred: %15" PRId64 " %10.2f %% per vivified",
|
||||
stats.vivifiedirred, percent (stats.vivifiedirred, vivified));
|
||||
PRT (" vified-tier1: %15" PRId64 " %10.2f %% per vivified",
|
||||
stats.vivifiedtier1, percent (stats.vivifiedtier1, vivified));
|
||||
PRT (" vified-tier2: %15" PRId64 " %10.2f %% per vivified",
|
||||
stats.vivifiedtier2, percent (stats.vivifiedtier2, vivified));
|
||||
PRT (" vified-tier3: %15" PRId64 " %10.2f %% per vivified",
|
||||
stats.vivifiedtier3, percent (stats.vivifiedtier3, vivified));
|
||||
PRT (" vivifysched: %15" PRId64 " %10.2f %% checks per scheduled",
|
||||
stats.vivifysched,
|
||||
percent (stats.vivifychecks, stats.vivifysched));
|
||||
|
|
@ -656,6 +708,9 @@ void Stats::print (Internal *internal) {
|
|||
stats.vivifyinst, percent (stats.vivifyinst, stats.vivifychecks));
|
||||
PRT (" vivifysubs: %15" PRId64 " %10.2f %% per subsumed",
|
||||
stats.vivifysubs, percent (stats.vivifysubs, stats.subsumed));
|
||||
PRT (" vivifyflushed: %15" PRId64 " %10.2f %% per subsumed",
|
||||
stats.vivifyflushed,
|
||||
percent (stats.vivifyflushed, stats.subsumed));
|
||||
PRT (" vivifysubred: %15" PRId64 " %10.2f %% per subs",
|
||||
stats.vivifysubred,
|
||||
percent (stats.vivifysubred, stats.vivifysubs));
|
||||
|
|
@ -681,13 +736,31 @@ void Stats::print (Internal *internal) {
|
|||
percent (stats.vivifydemote, stats.vivifystrs));
|
||||
PRT (" vivifydecs: %15" PRId64 " %10.2f per checks",
|
||||
stats.vivifydecs, relative (stats.vivifydecs, stats.vivifychecks));
|
||||
PRT (" vivifyreused: %15" PRId64 " %10.2f %% per decision",
|
||||
PRT (" vivifyreused: %15" PRId64
|
||||
" %10.2f %% per non-reused decision",
|
||||
stats.vivifyreused,
|
||||
percent (stats.vivifyreused, stats.vivifydecs));
|
||||
}
|
||||
if (all || stats.walk.count) {
|
||||
PRT ("walked: %15" PRId64 " %10.2f interval",
|
||||
stats.walk.count, relative (stats.conflicts, stats.walk.count));
|
||||
if (all || stats.warmup.count) {
|
||||
PRT (" prop-warmup: %15" PRId64 " %10.2f per warmup",
|
||||
stats.warmup.propagated,
|
||||
relative (stats.warmup.propagated, stats.warmup.count));
|
||||
PRT (" dec-warmup: %15" PRId64 " %10.2f per warmup",
|
||||
stats.warmup.decision,
|
||||
relative (stats.warmup.decision, stats.warmup.count));
|
||||
PRT (" dummydec-w: %15" PRId64 " %10.2f per warmup",
|
||||
stats.warmup.dummydecision,
|
||||
relative (stats.warmup.dummydecision, stats.warmup.count));
|
||||
PRT (" conflicts: %15" PRId64 " %10.2f per warmup",
|
||||
stats.warmup.conflicts,
|
||||
relative (stats.warmup.conflicts, stats.warmup.count));
|
||||
PRT (" warmup: %15" PRId64 " %10.2f per walk",
|
||||
stats.warmup.count,
|
||||
relative (stats.warmup.count, stats.walk.count));
|
||||
}
|
||||
#ifndef CADICAL_QUIET
|
||||
if (internal->profiles.walk.value > 0)
|
||||
PRT (" flips: %15" PRId64 " %10.2f M per second",
|
||||
|
|
@ -704,6 +777,9 @@ void Stats::print (Internal *internal) {
|
|||
percent (stats.walk.minimum, stats.added.irredundant));
|
||||
PRT (" broken: %15" PRId64 " %10.2f per flip",
|
||||
stats.walk.broken, relative (stats.walk.broken, stats.walk.flips));
|
||||
PRT (" improved: %15" PRId64 " %10.2f per walk",
|
||||
stats.walk.improved,
|
||||
relative (stats.walk.improved, stats.walk.count));
|
||||
}
|
||||
if (all || stats.weakened) {
|
||||
PRT ("weakened: %15" PRId64 " %10.2f average size",
|
||||
|
|
@ -736,13 +812,23 @@ void Stats::print (Internal *internal) {
|
|||
PRT (" unaries: %15" PRId64 " %10.2f per round",
|
||||
stats.congruence.unaries,
|
||||
relative (stats.congruence.rounds, stats.congruence.unaries));
|
||||
PRT (" rewri.-ands: %15" PRId64 " %10.2f per round",
|
||||
int64_t rewritten = stats.congruence.rewritten_ands +
|
||||
stats.congruence.rewritten_xors +
|
||||
stats.congruence.rewritten_ites;
|
||||
PRT (" rewritten: %15" PRId64 " %10.2f per round", rewritten,
|
||||
percent (rewritten, stats.congruence.rounds));
|
||||
PRT (" rewri.-ands: %15" PRId64 " %10.2f per rewritten",
|
||||
stats.congruence.rewritten_ands,
|
||||
relative (stats.congruence.rounds,
|
||||
stats.congruence.rewritten_ands));
|
||||
PRT (" subsumed: %15" PRId64 " %10.2f per round",
|
||||
percent (stats.congruence.rewritten_ands, rewritten));
|
||||
PRT (" rewri.-xors: %15" PRId64 " %10.2f%% per rewritten",
|
||||
stats.congruence.rewritten_xors,
|
||||
percent (stats.congruence.rewritten_xors, rewritten));
|
||||
PRT (" rewri.-ites: %15" PRId64 " %10.2f%% per rewritten",
|
||||
stats.congruence.rewritten_ites,
|
||||
percent (stats.congruence.rewritten_ites, rewritten));
|
||||
PRT (" subsumed: %15" PRId64 " %10.2f%% per round",
|
||||
stats.congruence.subsumed,
|
||||
relative (stats.congruence.rounds, stats.congruence.subsumed));
|
||||
relative (stats.congruence.subsumed, stats.congruence.rounds));
|
||||
}
|
||||
|
||||
LINE ();
|
||||
|
|
@ -750,6 +836,10 @@ void Stats::print (Internal *internal) {
|
|||
tout.magenta_code (), internal->opts.realtime ? "real" : "process",
|
||||
tout.normal_code ());
|
||||
|
||||
SECTION ("glue usage");
|
||||
|
||||
internal->print_tier_usage_statistics ();
|
||||
|
||||
#endif // ifndef CADICAL_QUIET
|
||||
}
|
||||
|
||||
|
|
@ -810,6 +900,8 @@ void LratChecker::print_stats () {
|
|||
stats.original, percent (stats.original, stats.added));
|
||||
MSG ("derived: %15" PRId64 " %10.2f %% of all clauses",
|
||||
stats.derived, percent (stats.derived, stats.added));
|
||||
MSG ("rat: %15" PRId64 " %10.2f %% of derived clauses",
|
||||
stats.rat, percent (stats.rat, stats.derived));
|
||||
MSG ("deleted: %15" PRId64 " %10.2f %% of all clauses",
|
||||
stats.deleted, percent (stats.deleted, stats.added));
|
||||
MSG ("finalized: %15" PRId64 " %10.2f %% of all clauses",
|
||||
|
|
|
|||
|
|
@ -308,7 +308,6 @@ inline int Internal::try_to_subsume_clause (Clause *c,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct subsume_less_noccs {
|
||||
Internal *internal;
|
||||
subsume_less_noccs (Internal *i) : internal (i) {}
|
||||
|
|
|
|||
|
|
@ -923,6 +923,13 @@ int64_t Internal::add_sweep_binary (sweep_proof_clause pc, int lit,
|
|||
proof->weaken_minus (id, clause);
|
||||
}
|
||||
external->push_binary_clause_on_extension_stack (id, lit, other);
|
||||
for (auto &tracer : tracers) {
|
||||
if (externalize (lit) < 0)
|
||||
break;
|
||||
const int elit = externalize (lit);
|
||||
const int eother = externalize (other);
|
||||
tracer->notify_equivalence (elit, -eother);
|
||||
}
|
||||
clause.clear ();
|
||||
lrat_chain.clear ();
|
||||
return id;
|
||||
|
|
@ -1639,7 +1646,7 @@ const char *Internal::sweep_variable (Sweeper &sweeper, int idx) {
|
|||
units = stats.sweep_units - units;
|
||||
solved = stats.sweep_solved - solved;
|
||||
#endif
|
||||
VERBOSE (3,
|
||||
VERBOSE (4,
|
||||
"complete swept variable %d backbone with %" PRIu64
|
||||
" units in %" PRIu64 " solver calls",
|
||||
externalize (idx), units, solved);
|
||||
|
|
@ -1915,7 +1922,7 @@ bool Internal::sweep () {
|
|||
const char *res =
|
||||
#endif
|
||||
sweep_variable (sweeper, idx);
|
||||
VERBOSE (2, "swept[%" PRIu64 "] external variable %d %s", swept,
|
||||
VERBOSE (3, "swept[%" PRIu64 "] external variable %d %s", swept,
|
||||
externalize (idx), res);
|
||||
if (++swept == limit) {
|
||||
VERBOSE (2,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "internal.hpp"
|
||||
#include "util.hpp"
|
||||
#include <string>
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
|
|
@ -14,8 +16,9 @@ void Internal::recompute_tier () {
|
|||
const int64_t delta =
|
||||
stats.tierecomputed >= 16 ? 1u << 16 : (1u << stats.tierecomputed);
|
||||
lim.recompute_tier = stats.conflicts + delta;
|
||||
LOG ("rescheduling in %zd at %zd (conflicts at %zd)", delta,
|
||||
lim.recompute_tier, stats.conflicts);
|
||||
LOG ("rescheduling in %" PRId64 " at %" PRId64 " (conflicts at %" PRId64
|
||||
")",
|
||||
delta, lim.recompute_tier, stats.conflicts);
|
||||
#ifndef CADICAL_NDEBUG
|
||||
uint64_t total_used = 0;
|
||||
for (auto u : stats.used[stable])
|
||||
|
|
@ -34,13 +37,21 @@ void Internal::recompute_tier () {
|
|||
stats.bump_used[stable] * opts.tier1limit / 100;
|
||||
uint64_t accumulated_tier2_limit =
|
||||
stats.bump_used[stable] * opts.tier2limit / 100;
|
||||
uint64_t accumulated_used = 0;
|
||||
for (size_t glue = 0; glue < stats.used[stable].size (); ++glue) {
|
||||
tier1[stable] = 1;
|
||||
tier2[stable] = 1;
|
||||
uint64_t accumulated_used = stats.used[stable][0];
|
||||
size_t glue = 1;
|
||||
for (; glue < stats.used[stable].size (); ++glue) {
|
||||
const uint64_t u = stats.used[stable][glue];
|
||||
accumulated_used += u;
|
||||
if (accumulated_used <= accumulated_tier1_limit) {
|
||||
if (accumulated_used >= accumulated_tier1_limit) {
|
||||
tier1[stable] = glue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; glue < stats.used[stable].size (); ++glue) {
|
||||
const uint64_t u = stats.used[stable][glue];
|
||||
accumulated_used += u;
|
||||
if (accumulated_used >= accumulated_tier2_limit) {
|
||||
tier2[stable] = glue;
|
||||
break;
|
||||
|
|
@ -48,12 +59,137 @@ void Internal::recompute_tier () {
|
|||
}
|
||||
}
|
||||
|
||||
LOG ("tier1 limit = %d in %s mode", tier1[stable],
|
||||
stable ? "stable" : "focused");
|
||||
LOG ("tier2 limit = %d in %s mode", tier2[stable],
|
||||
stable ? "stable" : "focused");
|
||||
CADICAL_assert (tier1[stable] > 0);
|
||||
|
||||
CADICAL_assert (tier1[stable]);
|
||||
CADICAL_assert (tier2[stable]);
|
||||
|
||||
if (tier1[stable] < opts.tier1minglue) {
|
||||
LOG ("tier1 limit of %d is too low, setting %d instead", tier1[stable],
|
||||
opts.tier1minglue);
|
||||
tier1[stable] = opts.tier1minglue;
|
||||
}
|
||||
if (tier2[stable] < opts.tier2minglue) {
|
||||
LOG ("tier2 limit of %d is too low, setting %d instead", tier2[stable],
|
||||
opts.tier2minglue);
|
||||
tier2[stable] = opts.tier2minglue;
|
||||
}
|
||||
if (tier1[stable] >= tier2[stable])
|
||||
tier2[stable] = tier1[stable] + 1;
|
||||
CADICAL_assert (tier2[stable] > tier1[stable]);
|
||||
|
||||
PHASE ("retiered", stats.tierecomputed,
|
||||
"tier1 limit = %d in %s mode, tier2 limit = %d in %s mode",
|
||||
tier1[stable], stable ? "stable" : "focused", tier2[stable],
|
||||
stable ? "stable" : "focused");
|
||||
}
|
||||
|
||||
void Internal::print_tier_usage_statistics () {
|
||||
recompute_tier ();
|
||||
|
||||
for (auto stable : {false, true}) {
|
||||
unsigned total_used = 0;
|
||||
for (size_t glue = 0; glue < stats.used[stable].size (); ++glue)
|
||||
total_used += stats.used[stable][glue];
|
||||
|
||||
const std::string mode = stable ? "stable" : "focused";
|
||||
const size_t tier1 = internal->tier1[stable];
|
||||
const size_t tier2 = internal->tier2[stable];
|
||||
if (tier1 > tier2 && opts.reducetier1glue > opts.reducetier2glue) {
|
||||
MSG ("tier1 > tier 2 due to the options, giving up");
|
||||
break;
|
||||
}
|
||||
CADICAL_assert (tier1 <= tier2);
|
||||
unsigned prefix, suffix;
|
||||
unsigned span = tier2 - tier1 + 1;
|
||||
const unsigned max_printed = 5;
|
||||
CADICAL_assert (max_printed & 1), CADICAL_assert (max_printed / 2 > 0);
|
||||
if (span > max_printed) {
|
||||
prefix = tier1 + max_printed / 2 - 1;
|
||||
suffix = tier2 - max_printed / 2 + 1;
|
||||
} else
|
||||
prefix = UINT_MAX, suffix = 0;
|
||||
|
||||
uint64_t accumulated_middle = 0;
|
||||
int glue_digits = 1, clauses_digits = 1;
|
||||
for (unsigned glue = 0; glue <= stats.used[stable].size (); glue++) {
|
||||
if (glue < tier1)
|
||||
continue;
|
||||
uint64_t used = stats.used[stable][glue];
|
||||
int tmp_glue = 0, tmp_clauses = 0;
|
||||
if (glue <= prefix || suffix <= glue) {
|
||||
tmp_glue = glue;
|
||||
tmp_clauses = used;
|
||||
} else {
|
||||
accumulated_middle += used;
|
||||
if (glue + 1 == suffix) {
|
||||
tmp_glue = (prefix + 1) + (glue) + 1;
|
||||
tmp_clauses = (accumulated_middle);
|
||||
}
|
||||
}
|
||||
if (tmp_glue > glue_digits)
|
||||
glue_digits = tmp_glue;
|
||||
if (tmp_clauses > clauses_digits)
|
||||
clauses_digits = tmp_clauses;
|
||||
if (glue == tier2)
|
||||
break;
|
||||
}
|
||||
|
||||
accumulated_middle = 0;
|
||||
uint64_t accumulated = 0;
|
||||
std::string output;
|
||||
for (unsigned glue = 0; glue <= stats.used[stable].size (); glue++) {
|
||||
uint64_t used = stats.used[stable][glue];
|
||||
accumulated += used;
|
||||
if (glue < tier1)
|
||||
continue;
|
||||
if (glue <= prefix || suffix <= glue + 1) {
|
||||
output += mode + " glue ";
|
||||
}
|
||||
if (glue <= prefix || suffix <= glue) {
|
||||
std::string glue_str = std::to_string (glue);
|
||||
output += glue_str;
|
||||
output += " used " + std::to_string (used);
|
||||
output +=
|
||||
" clauses " +
|
||||
std::to_string (percent (used, total_used)).substr (0, 5) + "%";
|
||||
output += " accumulated " +
|
||||
std::to_string (percent (accumulated, total_used))
|
||||
.substr (0, 5) +
|
||||
"%";
|
||||
if (glue == tier1)
|
||||
output += " tier1";
|
||||
if (glue == tier2)
|
||||
output += " tier2";
|
||||
MSG ("%s", output.c_str ());
|
||||
output.clear ();
|
||||
} else {
|
||||
accumulated_middle += used;
|
||||
if (glue + 1 == suffix) {
|
||||
std::string glue_str = std::to_string (prefix + 1) + "-" +
|
||||
std::to_string (suffix - 1);
|
||||
output +=
|
||||
glue_str + " used " + std::to_string (accumulated_middle);
|
||||
output +=
|
||||
" clauses " +
|
||||
std::to_string (percent (accumulated_middle, total_used))
|
||||
.substr (0, 5) +
|
||||
"%";
|
||||
output += " accumulated " +
|
||||
std::to_string (percent (accumulated, total_used))
|
||||
.substr (0, 5) +
|
||||
"%";
|
||||
MSG ("%s", output.c_str ());
|
||||
output.clear ();
|
||||
}
|
||||
}
|
||||
if (glue == tier2)
|
||||
break;
|
||||
}
|
||||
|
||||
LINE ();
|
||||
}
|
||||
}
|
||||
} // namespace CaDiCaL
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
|
|||
|
|
@ -190,11 +190,41 @@ inline void VeripbTracer::put_binary_id (int64_t id, bool can_be_negative) {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void VeripbTracer::veripb_add_derived_clause (int64_t id, bool redundant,
|
||||
int witness,
|
||||
const vector<int> &clause) {
|
||||
CADICAL_assert (witness == clause[0]);
|
||||
file->put ("red ");
|
||||
for (const auto &external_lit : clause) {
|
||||
file->put ("1 ");
|
||||
if (external_lit < 0)
|
||||
file->put ('~');
|
||||
file->put ('x');
|
||||
file->put (abs (external_lit));
|
||||
file->put (' ');
|
||||
}
|
||||
file->put (">= 1 : ");
|
||||
file->put ('x');
|
||||
file->put (abs (witness));
|
||||
file->put (" -> ");
|
||||
if (witness < 0)
|
||||
file->put ("0");
|
||||
else
|
||||
file->put ("1");
|
||||
file->put (";\n");
|
||||
if (!redundant && checked_deletions) {
|
||||
file->put ("core id ");
|
||||
file->put (id);
|
||||
file->put (";\n");
|
||||
}
|
||||
}
|
||||
|
||||
void VeripbTracer::veripb_add_derived_clause (
|
||||
int64_t id, bool redundant, const vector<int> &clause,
|
||||
const vector<int64_t> &chain) {
|
||||
file->put ("pol ");
|
||||
bool first = true;
|
||||
CADICAL_assert (!chain.empty ());
|
||||
for (auto p = chain.rbegin (); p != chain.rend (); p++) {
|
||||
auto cid = *p;
|
||||
if (first) {
|
||||
|
|
@ -206,7 +236,7 @@ void VeripbTracer::veripb_add_derived_clause (
|
|||
file->put (" + s");
|
||||
}
|
||||
}
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
file->put ("e ");
|
||||
for (const auto &external_lit : clause) {
|
||||
file->put ("1 ");
|
||||
|
|
@ -216,13 +246,13 @@ void VeripbTracer::veripb_add_derived_clause (
|
|||
file->put (abs (external_lit));
|
||||
file->put (' ');
|
||||
}
|
||||
file->put (">= 1 ; ");
|
||||
file->put (">= 1 : ");
|
||||
file->put (id);
|
||||
file->put (" ;\n");
|
||||
file->put (";\n");
|
||||
if (!redundant && checked_deletions) {
|
||||
file->put ("core id ");
|
||||
file->put (id);
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,19 +267,19 @@ void VeripbTracer::veripb_add_derived_clause (int64_t id, bool redundant,
|
|||
file->put (abs (external_lit));
|
||||
file->put (' ');
|
||||
}
|
||||
file->put (">= 1 ;\n");
|
||||
file->put (">= 1;\n");
|
||||
if (!redundant && checked_deletions) {
|
||||
file->put ("core id ");
|
||||
file->put (id);
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
}
|
||||
}
|
||||
|
||||
void VeripbTracer::veripb_begin_proof (int64_t reserved_ids) {
|
||||
file->put ("pseudo-Boolean proof version 2.0\n");
|
||||
file->put ("pseudo-Boolean proof version 3.0\n");
|
||||
file->put ("f ");
|
||||
file->put (reserved_ids);
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
}
|
||||
|
||||
void VeripbTracer::veripb_delete_clause (int64_t id, bool redundant) {
|
||||
|
|
@ -261,18 +291,18 @@ void VeripbTracer::veripb_delete_clause (int64_t id, bool redundant) {
|
|||
file->put ("delc ");
|
||||
}
|
||||
file->put (id);
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
}
|
||||
|
||||
void VeripbTracer::veripb_report_status (bool unsat, int64_t conflict_id) {
|
||||
file->put ("output NONE\n");
|
||||
file->put ("output NONE;\n");
|
||||
if (unsat) {
|
||||
file->put ("conclusion UNSAT : ");
|
||||
file->put (conflict_id);
|
||||
file->put (" \n");
|
||||
file->put (";\n");
|
||||
} else
|
||||
file->put ("conclusion NONE\n");
|
||||
file->put ("end pseudo-Boolean proof\n");
|
||||
file->put ("conclusion NONE;\n");
|
||||
file->put ("end pseudo-Boolean proof;\n");
|
||||
}
|
||||
|
||||
void VeripbTracer::veripb_strengthen (int64_t id) {
|
||||
|
|
@ -280,7 +310,7 @@ void VeripbTracer::veripb_strengthen (int64_t id) {
|
|||
return;
|
||||
file->put ("core id ");
|
||||
file->put (id);
|
||||
file->put ("\n");
|
||||
file->put (";\n");
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
|
@ -295,12 +325,15 @@ void VeripbTracer::begin_proof (int64_t id) {
|
|||
}
|
||||
|
||||
void VeripbTracer::add_derived_clause (int64_t id, bool redundant,
|
||||
int witness,
|
||||
const vector<int> &clause,
|
||||
const vector<int64_t> &chain) {
|
||||
if (file->closed ())
|
||||
return;
|
||||
LOG ("VERIPB TRACER tracing addition of derived clause[%" PRId64 "]", id);
|
||||
if (with_antecedents)
|
||||
if (witness)
|
||||
veripb_add_derived_clause (id, redundant, witness, clause);
|
||||
else if (with_antecedents)
|
||||
veripb_add_derived_clause (id, redundant, clause, chain);
|
||||
else
|
||||
veripb_add_derived_clause (id, redundant, clause);
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@
|
|||
|
||||
#ifdef CADICAL_NBUILD
|
||||
#ifndef VERSION
|
||||
#define VERSION "2.2.0-rc1"
|
||||
#define VERSION "2.2.0"
|
||||
#endif // VERSION
|
||||
#endif // CADICAL_NBUILD
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// The copyright of the code is here.
|
||||
// The copyright of the code is here.
|
||||
|
||||
static const char *COPYRIGHT = "Copyright (c) 2016-2024";
|
||||
static const char *COPYRIGHT = "Copyright (c) 2016-2024";
|
||||
static const char *AUTHORS =
|
||||
"A. Biere, M. Fleury, N. Froleyks, K. Fazekas, F. Pollitt, T. Faller";
|
||||
static const char *AFFILIATIONS =
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ namespace CaDiCaL {
|
|||
|
||||
inline void Internal::vivify_subsume_clause (Clause *subsuming,
|
||||
Clause *subsumed) {
|
||||
CADICAL_assert (subsumed != subsuming);
|
||||
stats.subsumed++;
|
||||
stats.vivifysubs++;
|
||||
#ifndef CADICAL_NDEBUG
|
||||
|
|
@ -75,7 +76,12 @@ inline void Internal::vivify_subsume_clause (Clause *subsuming,
|
|||
}
|
||||
CADICAL_assert (real_size_subsuming <= real_size_subsumed);
|
||||
#endif
|
||||
LOG (subsumed, "subsumed");
|
||||
LOG (subsumed, "subsumed to be deleted");
|
||||
LOG (subsuming, "subsuming to be (un)deleted");
|
||||
if (subsumed->redundant && subsuming->redundant &&
|
||||
subsuming->glue < subsumed->glue) {
|
||||
promote_clause (subsuming, subsumed->glue);
|
||||
}
|
||||
if (subsumed->redundant) {
|
||||
stats.subred++;
|
||||
++stats.vivifysubred;
|
||||
|
|
@ -116,7 +122,9 @@ inline void Internal::vivify_subsume_clause (Clause *subsuming,
|
|||
}
|
||||
|
||||
// demoting a clause (opposite is promote from subsume.cpp)
|
||||
|
||||
//
|
||||
// This turned out to not be useful, but we kept it for the API call in the
|
||||
// proof tracers.
|
||||
inline void Internal::demote_clause (Clause *c) {
|
||||
stats.subsumed++;
|
||||
stats.vivifydemote++;
|
||||
|
|
@ -329,112 +337,22 @@ struct vivify_more_noccs_kissat {
|
|||
vivify_more_noccs_kissat (Internal *i) : internal (i) {}
|
||||
|
||||
bool operator() (int a, int b) {
|
||||
unsigned t = internal->noccs (a);
|
||||
unsigned s = internal->noccs (b);
|
||||
return ((t - s) | ((b - a) & ~(s - t))) >> 31;
|
||||
}
|
||||
};
|
||||
|
||||
// Sort candidate clauses by the number of occurrences (actually by their
|
||||
// score) of their literals, with clauses to be vivified first last. We
|
||||
// assume that clauses are sorted w.r.t. more occurring (higher score)
|
||||
// literals first (with respect to 'vivify_more_noccs').
|
||||
//
|
||||
// For example if there are the following (long irredundant) clauses
|
||||
//
|
||||
// 1 -3 -4 (A)
|
||||
// -1 -2 3 4 (B)
|
||||
// 2 -3 4 (C)
|
||||
//
|
||||
// then we have the following literal scores using Jeroslow Wang scores and
|
||||
// normalizing it with 2^12 (which is the same as 1<<12):
|
||||
//
|
||||
// nocc ( 1) = 2^12 * (2^-3 ) = 512 3.
|
||||
// nocc (-1) = 2^12 * (2^-4 ) = 256 6.
|
||||
// nocc ( 2) = 2^12 * (2^-3 ) = 512 4.
|
||||
// nocc (-2) = 2^12 * (2^-4 ) = 256 7. @1
|
||||
// nocc ( 3) = 2^12 * (2^-4 ) = 256 8.
|
||||
// nocc (-3) = 2^12 * (2^-3 + 2^-3) = 1024 1.
|
||||
// nocc ( 4) = 2^12 * (2^-3 + 2^-4) = 768 2.
|
||||
// nocc (-4) = 2^12 * (2^-3 ) = 512 5.
|
||||
//
|
||||
// which gives the literal order (according to 'vivify_more_noccs')
|
||||
//
|
||||
// -3, 4, 1, 2, -4, -1, -2, 3
|
||||
//
|
||||
// Then sorting the literals in each clause gives
|
||||
//
|
||||
// -3 1 -4 (A')
|
||||
// 4 -1 -2 3 (B') @2
|
||||
// -3 4 2 (C')
|
||||
//
|
||||
// and finally sorting those clauses lexicographically w.r.t. scores is
|
||||
//
|
||||
// -3 4 2 (C')
|
||||
// -3 1 -4 (A') @3
|
||||
// 4 -1 -2 3 (B')
|
||||
//
|
||||
// This order is defined by 'vivify_clause_later' which returns 'true' if
|
||||
// the first clause should be vivified later than the second.
|
||||
|
||||
struct vivify_clause_later {
|
||||
|
||||
Internal *internal;
|
||||
|
||||
vivify_clause_later (Internal *i) : internal (i) {}
|
||||
|
||||
bool operator() (Clause *a, Clause *b) const {
|
||||
|
||||
if (a == b)
|
||||
return false;
|
||||
|
||||
// First focus on clauses scheduled in the last vivify round but not
|
||||
// checked yet since then.
|
||||
//
|
||||
if (!a->vivify && b->vivify)
|
||||
return true;
|
||||
if (a->vivify && !b->vivify)
|
||||
return false;
|
||||
|
||||
// Among redundant clauses (in redundant mode) prefer small glue.
|
||||
//
|
||||
if (a->redundant) {
|
||||
CADICAL_assert (b->redundant);
|
||||
if (a->glue > b->glue)
|
||||
return true;
|
||||
if (a->glue < b->glue)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Then prefer shorter size.
|
||||
//
|
||||
if (a->size > b->size)
|
||||
return true;
|
||||
if (a->size < b->size)
|
||||
return false;
|
||||
|
||||
// Now compare literals in the clauses lexicographically with respect to
|
||||
// the literal order 'vivify_more_noccs' assuming literals are sorted
|
||||
// decreasingly with respect to that order.
|
||||
//
|
||||
const auto eoa = a->end (), eob = b->end ();
|
||||
auto j = b->begin ();
|
||||
for (auto i = a->begin (); i != eoa && j != eob; i++, j++)
|
||||
if (*i != *j)
|
||||
return vivify_more_noccs (internal) (*j, *i);
|
||||
|
||||
return j == eob; // Prefer shorter clauses to be vivified first.
|
||||
unsigned s = internal->noccs (a);
|
||||
unsigned t = internal->noccs (b);
|
||||
return (((t - s) |
|
||||
((internal->vlit (a) - internal->vlit (b)) & ~(s - t))) >>
|
||||
31);
|
||||
}
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Attempting on-the-fly subsumption during sorting when the last line is
|
||||
// reached in 'vivify_clause_later' above turned out to be trouble some for
|
||||
// identical clauses. This is the single point where 'vivify_clause_later'
|
||||
// is not asymmetric and would require 'stable' sorting for determinism. It
|
||||
// can also not be made 'complete' on-the-fly. Instead of on-the-fly
|
||||
// subsumption we thus go over the sorted scheduled in a linear scan
|
||||
// Attempting on-the-fly subsumption during sorting when the last line
|
||||
// is turned out to be trouble some for identical clauses. This is
|
||||
// the single point where sorting is not asymmetric and would require
|
||||
// 'stable' sorting for determinism. It can also not be made
|
||||
// 'complete' on-the-fly. Instead of on-the-fly subsumption, we
|
||||
// (optionnaly) thus go over the sorted scheduled in a linear scan
|
||||
// again and remove certain subsumed clauses (the subsuming clause is
|
||||
// syntactically a prefix of the subsumed clause), which includes
|
||||
// those troublesome syntactically identical clauses.
|
||||
|
|
@ -448,16 +366,16 @@ struct vivify_flush_smaller {
|
|||
for (; i != eoa && j != eob; i++, j++)
|
||||
if (*i != *j)
|
||||
return *i < *j;
|
||||
|
||||
return j == eob && i != eoa;
|
||||
const bool smaller = j == eob && i != eoa;
|
||||
return smaller;
|
||||
}
|
||||
};
|
||||
|
||||
void Internal::flush_vivification_schedule (std::vector<Clause *> &schedule,
|
||||
int64_t &ticks) {
|
||||
ticks += 1 + 3 * cache_lines (schedule.size (), sizeof (Clause *));
|
||||
// we cannot use msort here, as we cannot calculate a score
|
||||
stable_sort (schedule.begin (), schedule.end (), vivify_flush_smaller ());
|
||||
|
||||
const auto end = schedule.end ();
|
||||
auto j = schedule.begin (), i = j;
|
||||
|
||||
|
|
@ -493,6 +411,7 @@ void Internal::flush_vivification_schedule (std::vector<Clause *> &schedule,
|
|||
"flushed %" PRId64 " subsumed scheduled clauses", subsumed);
|
||||
|
||||
stats.vivifysubs += subsumed;
|
||||
stats.vivifyflushed += subsumed;
|
||||
|
||||
if (subsumed) {
|
||||
schedule.resize (j - schedule.begin ());
|
||||
|
|
@ -507,7 +426,6 @@ void Internal::flush_vivification_schedule (std::vector<Clause *> &schedule,
|
|||
// we schedule a clause to be vivified. For redundant clauses we initially
|
||||
// only try to vivify them if they are likely to survive the next 'reduce'
|
||||
// operation, but this left the last schedule empty most of the time.
|
||||
|
||||
bool Internal::consider_to_vivify_clause (Clause *c) {
|
||||
if (c->garbage)
|
||||
return false;
|
||||
|
|
@ -552,7 +470,7 @@ struct vivify_better_watch {
|
|||
// Common code to actually strengthen a candidate clause. The resulting
|
||||
// strengthened clause is communicated through the global 'clause'.
|
||||
|
||||
void Internal::vivify_strengthen (Clause *c) {
|
||||
void Internal::vivify_strengthen (Clause *c, int64_t &ticks) {
|
||||
|
||||
CADICAL_assert (!clause.empty ());
|
||||
|
||||
|
|
@ -566,7 +484,7 @@ void Internal::vivify_strengthen (Clause *c) {
|
|||
// lrat_chain.clear (); done in search_assign
|
||||
stats.vivifyunits++;
|
||||
|
||||
bool ok = propagate ();
|
||||
bool ok = vivify_propagate (ticks);
|
||||
if (!ok)
|
||||
learn_empty_clause ();
|
||||
|
||||
|
|
@ -613,6 +531,8 @@ void Internal::vivify_strengthen (Clause *c) {
|
|||
++stats.vivifystrs;
|
||||
}
|
||||
|
||||
// When shortening clauses, we have to update the watched literals.
|
||||
// Actually we don't do it, and instead simply backtrack back enough.
|
||||
void Internal::vivify_sort_watched (Clause *c) {
|
||||
|
||||
sort (c->begin (), c->end (), vivify_better_watch (this));
|
||||
|
|
@ -637,18 +557,20 @@ void Internal::vivify_sort_watched (Clause *c) {
|
|||
|
||||
CADICAL_assert (new_level >= 0);
|
||||
if (new_level < level)
|
||||
backtrack (new_level);
|
||||
backtrack_without_updating_phases (new_level);
|
||||
|
||||
CADICAL_assert (val (lit0) >= 0);
|
||||
CADICAL_assert (val (lit1) >= 0 || (val (lit0) > 0 && val (lit1) < 0 &&
|
||||
var (lit0).level <= var (lit1).level));
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Conflict analysis from 'start' which learns a decision only clause.
|
||||
//
|
||||
// We cannot use the stack-based implementation of Kissat, because we need
|
||||
// to iterate over the conflict in topological ordering to produce a valid
|
||||
// LRAT proof
|
||||
|
||||
void Internal::vivify_analyze (Clause *start, bool &subsumes,
|
||||
Clause **subsuming,
|
||||
const Clause *const candidate, int implied,
|
||||
|
|
@ -685,7 +607,7 @@ void Internal::vivify_analyze (Clause *start, bool &subsumes,
|
|||
continue;
|
||||
LOG ("unit reason for %d", other);
|
||||
int64_t id = unit_id (-other);
|
||||
LOG ("adding unit reason %zd for %d", id, other);
|
||||
LOG ("adding unit reason %" PRId64 " for %s", id, LOGLIT (other));
|
||||
unit_chain.push_back (id);
|
||||
f.seen = true;
|
||||
analyzed.push_back (other);
|
||||
|
|
@ -703,9 +625,9 @@ void Internal::vivify_analyze (Clause *start, bool &subsumes,
|
|||
analyzed.push_back (other);
|
||||
f.seen = true;
|
||||
}
|
||||
if (start->redundant) {
|
||||
const int new_glue = recompute_glue (start);
|
||||
promote_clause (start, new_glue);
|
||||
if (reason != start && reason->redundant) {
|
||||
const int new_glue = recompute_glue (reason);
|
||||
promote_clause (reason, new_glue);
|
||||
}
|
||||
if (subsumes) {
|
||||
CADICAL_assert (reason);
|
||||
|
|
@ -740,6 +662,9 @@ void Internal::vivify_analyze (Clause *start, bool &subsumes,
|
|||
(void) candidate;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
// First decide which clause (candidate or conflict) to analyze and
|
||||
// how to do it. We also prepare the clause by removing units.
|
||||
void Internal::vivify_deduce (Clause *candidate, Clause *conflict,
|
||||
int implied, Clause **subsuming,
|
||||
bool &redundant) {
|
||||
|
|
@ -761,7 +686,7 @@ void Internal::vivify_deduce (Clause *candidate, Clause *conflict,
|
|||
} else {
|
||||
reason = (conflict ? conflict : candidate);
|
||||
CADICAL_assert (reason);
|
||||
CADICAL_assert (!reason->garbage);
|
||||
CADICAL_assert (!reason->garbage || reason->size == 2);
|
||||
mark2 (candidate);
|
||||
subsumes = (candidate != reason);
|
||||
redundant = reason->redundant;
|
||||
|
|
@ -780,7 +705,7 @@ void Internal::vivify_deduce (Clause *candidate, Clause *conflict,
|
|||
// nevertheless we can use var (l) as if l was still assigned
|
||||
// because var is updated lazily
|
||||
int64_t id = unit_id (-lit);
|
||||
LOG ("adding unit reason %zd for %d", id, lit);
|
||||
LOG ("adding unit reason %" PRId64 " for %s", id, LOGLIT (lit));
|
||||
unit_chain.push_back (id);
|
||||
}
|
||||
f.seen = true;
|
||||
|
|
@ -837,8 +762,10 @@ void Internal::vivify_deduce (Clause *candidate, Clause *conflict,
|
|||
lrat_chain.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// checks whether the clause can be strengthen or not.
|
||||
bool Internal::vivify_shrinkable (const std::vector<int> &sorted,
|
||||
Clause *conflict) {
|
||||
|
||||
|
|
@ -875,6 +802,7 @@ bool Internal::vivify_shrinkable (const std::vector<int> &sorted,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
inline void Internal::vivify_increment_stats (const Vivifier &vivifier) {
|
||||
|
|
@ -894,10 +822,11 @@ inline void Internal::vivify_increment_stats (const Vivifier &vivifier) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
// instantiate last literal (see the description of the hack track 2023),
|
||||
// fix the watches and
|
||||
// backtrack two level back
|
||||
// instantiate last literal (see the description of the hack track
|
||||
// 2023), fix the watches and backtrack two level back to make sure
|
||||
// the watches are correct.
|
||||
bool Internal::vivify_instantiate (
|
||||
const std::vector<int> &sorted, Clause *c,
|
||||
std::vector<std::tuple<int, Clause *, bool>> &lrat_stack,
|
||||
|
|
@ -909,7 +838,7 @@ bool Internal::vivify_instantiate (
|
|||
CADICAL_assert (!var (lit).reason);
|
||||
CADICAL_assert (var (lit).level);
|
||||
CADICAL_assert (val (lit));
|
||||
backtrack (level - 1);
|
||||
backtrack_without_updating_phases (level - 1);
|
||||
CADICAL_assert (val (lit) == 0);
|
||||
stats.vivifydecs++;
|
||||
vivify_assume (lit);
|
||||
|
|
@ -948,6 +877,7 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
|
||||
CADICAL_assert (c->size > 2); // see (NO-BINARY) below
|
||||
CADICAL_assert (analyzed.empty ());
|
||||
CADICAL_assert (!ignore);
|
||||
|
||||
c->vivify = false; // mark as checked / tried
|
||||
c->vivified = true; // and globally remember
|
||||
|
|
@ -984,6 +914,8 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
}
|
||||
|
||||
sort (sorted.begin (), sorted.end (), vivify_more_noccs_kissat (this));
|
||||
CADICAL_assert (std::is_sorted (sorted.begin (), sorted.end (),
|
||||
vivify_more_noccs (this)));
|
||||
|
||||
// The actual vivification checking is performed here, by assuming the
|
||||
// negation of each of the remaining literals of the clause in turn and
|
||||
|
|
@ -1047,7 +979,7 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
const int decision = control[l].decision;
|
||||
if (-lit == decision) {
|
||||
LOG ("reusing decision %d at decision level %d", decision, l);
|
||||
stats.vivifyreused++;
|
||||
++stats.vivifyreused;
|
||||
if (++l > level)
|
||||
break;
|
||||
} else {
|
||||
|
|
@ -1169,15 +1101,13 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
reverse (lrat_chain.begin (), lrat_chain.end ());
|
||||
}
|
||||
|
||||
// For an explanation of the code, see our POS'25 paper ``Revisiting
|
||||
// Clause Vivification'' (although for the experiments we focused on
|
||||
// Kissat instead of CaDiCaL)
|
||||
if (subsuming) {
|
||||
CADICAL_assert (c != subsuming);
|
||||
LOG (c, "deleting subsumed clause");
|
||||
if (c->redundant && subsuming->redundant && c->glue < subsuming->glue) {
|
||||
promote_clause (c, c->glue);
|
||||
}
|
||||
vivify_subsume_clause (subsuming, c);
|
||||
res = false;
|
||||
// stats.vivifysubs++; // already done in vivify_subsume_clause
|
||||
} else if (vivify_shrinkable (sorted, conflict)) {
|
||||
vivify_increment_stats (vivifier);
|
||||
LOG ("vivify succeeded, learning new clause");
|
||||
|
|
@ -1185,7 +1115,7 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
LOG (lrat_chain, "lrat");
|
||||
LOG (clause, "learning clause");
|
||||
conflict = nullptr; // TODO dup from below
|
||||
vivify_strengthen (c);
|
||||
vivify_strengthen (c, ticks);
|
||||
res = true;
|
||||
} else if (subsume && c->redundant) {
|
||||
LOG (c, "vivification implied");
|
||||
|
|
@ -1193,8 +1123,8 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
++stats.vivifyimplied;
|
||||
res = true;
|
||||
} else if ((conflict || subsume) && !c->redundant && !redundant) {
|
||||
LOG ("demote clause from irredundant to redundant");
|
||||
if (opts.vivifydemote) {
|
||||
LOG ("demote clause from irredundant to redundant");
|
||||
demote_clause (c);
|
||||
const int new_glue = recompute_glue (c);
|
||||
promote_clause (c, new_glue);
|
||||
|
|
@ -1235,6 +1165,25 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
clear_analyzed_literals (); // TODO why needed?
|
||||
lrat_chain.clear ();
|
||||
conflict = nullptr;
|
||||
ignore = nullptr;
|
||||
|
||||
if (res) {
|
||||
switch (vivifier.tier) {
|
||||
case Vivify_Mode::IRREDUNDANT:
|
||||
++stats.vivifiedirred;
|
||||
break;
|
||||
case Vivify_Mode::TIER1:
|
||||
++stats.vivifiedtier1;
|
||||
break;
|
||||
case Vivify_Mode::TIER2:
|
||||
++stats.vivifiedtier2;
|
||||
break;
|
||||
default:
|
||||
CADICAL_assert (vivifier.tier == Vivify_Mode::TIER3);
|
||||
++stats.vivifiedtier3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1251,9 +1200,9 @@ bool Internal::vivify_clause (Vivifier &vivifier, Clause *c) {
|
|||
// its own but this is not actually necessary.
|
||||
//
|
||||
|
||||
// Non-recursive version, as some bugs have been found. DFS over the
|
||||
// reasons with preordering (aka we explore the entire reason before
|
||||
// exploring deeper)
|
||||
// Non-recursive version, as some bugs have been found by Dominik Schreiber
|
||||
// during his very large experiments. DFS over the reasons with preordering
|
||||
// (aka we explore the entire reason before exploring deeper)
|
||||
void Internal::vivify_build_lrat (
|
||||
int lit, Clause *reason,
|
||||
std::vector<std::tuple<int, Clause *, bool>> &stack) {
|
||||
|
|
@ -1309,8 +1258,6 @@ void Internal::vivify_build_lrat (
|
|||
inline void Internal::vivify_chain_for_units (int lit, Clause *reason) {
|
||||
if (!lrat)
|
||||
return;
|
||||
// LOG ("building chain for units"); bad line for debugging
|
||||
// equivalence if (opts.chrono && assignment_level (lit, reason)) return;
|
||||
if (level)
|
||||
return; // not decision level 0
|
||||
CADICAL_assert (lrat_chain.empty ());
|
||||
|
|
@ -1349,7 +1296,8 @@ vivify_ref create_ref (Internal *internal, Clause *c) {
|
|||
{
|
||||
const int64_t lit_count = internal->noccs (lit);
|
||||
CADICAL_assert (lit_count);
|
||||
LOG ("checking literal %d with %zd occurrences", lit, lit_count);
|
||||
LOG ("checking literal %s with %" PRId64 " occurrences",
|
||||
LOGLIT (lit), lit_count);
|
||||
if (lit_count <= best_count)
|
||||
continue;
|
||||
best_count = lit_count;
|
||||
|
|
@ -1361,32 +1309,35 @@ vivify_ref create_ref (Internal *internal, Clause *c) {
|
|||
CADICAL_assert (best_count);
|
||||
CADICAL_assert (best_count < UINT32_MAX);
|
||||
ref.count[i] =
|
||||
((uint64_t) best_count << 32) + (uint64_t) internal->vlit (best);
|
||||
LOG ("final count at position %d is %d - %d: %lu", i, best, best_count,
|
||||
ref.count[i]);
|
||||
(((uint64_t) best_count) << 32) + (uint64_t) internal->vlit (best);
|
||||
LOG ("final count at position %d is %s - %u: %" PRIu64, i,
|
||||
LOGLIT (best), best_count, ref.count[i]);
|
||||
lits[i] = best;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
/*------------------------------------------------------------------------*/
|
||||
inline void
|
||||
Internal::vivify_prioritize_leftovers ([[maybe_unused]] char tag,
|
||||
size_t prioritized,
|
||||
Internal::vivify_prioritize_leftovers (char tag, size_t prioritized,
|
||||
std::vector<Clause *> &schedule) {
|
||||
if (prioritized) {
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"[phase %c] leftovers of %" PRId64 " clause", tag, prioritized);
|
||||
"[phase %c] leftovers of %zu clause", tag, prioritized);
|
||||
} else {
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"[phase %c] prioritizing all clause", tag);
|
||||
for (auto c : schedule)
|
||||
c->vivify = true;
|
||||
}
|
||||
#ifdef CADICAL_QUIET
|
||||
(void) tag;
|
||||
#endif
|
||||
const size_t max = opts.vivifyschedmax;
|
||||
if (schedule.size () > max) {
|
||||
if (prioritized) {
|
||||
std::partition (begin (schedule), end (schedule),
|
||||
[] (Clause *c) { return c->vivify; });
|
||||
// put the left-overs first to be kept
|
||||
std::stable_partition (begin (schedule), end (schedule),
|
||||
[] (Clause *c) { return c->vivify; });
|
||||
}
|
||||
schedule.resize (max);
|
||||
}
|
||||
|
|
@ -1463,6 +1414,8 @@ void Internal::vivify_initialize (Vivifier &vivifier, int64_t &ticks) {
|
|||
if (opts.vivifyflush) {
|
||||
clear_watches ();
|
||||
for (auto &sched : vivifier.schedules) {
|
||||
// approximation for schedule
|
||||
ticks += 1 + cache_lines (sched.size (), sizeof (Clause *));
|
||||
for (const auto &c : sched) {
|
||||
// Literals in scheduled clauses are sorted with their highest score
|
||||
// literals first (as explained above in the example at '@2'). This
|
||||
|
|
@ -1471,41 +1424,26 @@ void Internal::vivify_initialize (Vivifier &vivifier, int64_t &ticks) {
|
|||
// below.
|
||||
//
|
||||
sort (c->begin (), c->end (), vivify_more_noccs (this));
|
||||
// ++ticks;
|
||||
}
|
||||
// Flush clauses subsumed by another clause with the same prefix,
|
||||
// which also includes flushing syntactically identical clauses.
|
||||
//
|
||||
flush_vivification_schedule (sched, ticks);
|
||||
}
|
||||
// approximation for schedule
|
||||
// ticks += 1 + cache_lines (clauses.size (), sizeof (Clause *));
|
||||
connect_watches (); // watch all relevant clauses
|
||||
}
|
||||
#if 0
|
||||
connect_watches (); // watch all relevant clauses
|
||||
vivify_propagate (ticks);
|
||||
#endif
|
||||
vivify_propagate (ticks);
|
||||
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"[phase %c] leftovers out of %zu clauses", 'u',
|
||||
vivifier.schedule_tier1.size ());
|
||||
}
|
||||
|
||||
inline std::vector<vivify_ref> ¤t_refs_schedule (Vivifier &vivifier) {
|
||||
switch (vivifier.tier) {
|
||||
case Vivify_Mode::TIER1:
|
||||
return vivifier.refs_schedule_tier1;
|
||||
break;
|
||||
case Vivify_Mode::TIER2:
|
||||
return vivifier.refs_schedule_tier2;
|
||||
break;
|
||||
case Vivify_Mode::TIER3:
|
||||
return vivifier.refs_schedule_tier3;
|
||||
break;
|
||||
default:
|
||||
return vivifier.refs_schedule_irred;
|
||||
break;
|
||||
}
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
__assume(false);
|
||||
#else
|
||||
__builtin_unreachable ();
|
||||
#endif
|
||||
return vivifier.refs_schedule;
|
||||
}
|
||||
|
||||
inline std::vector<Clause *> ¤t_schedule (Vivifier &vivifier) {
|
||||
|
|
@ -1580,19 +1518,16 @@ void Internal::vivify_round (Vivifier &vivifier, int64_t ticks_limit) {
|
|||
if (terminated_asynchronously ())
|
||||
return;
|
||||
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"starting %c vivification round ticks limit %" PRId64 "",
|
||||
vivifier.tag, ticks_limit);
|
||||
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"starting %c vivification round ticks limit %" PRId64 "",
|
||||
vivifier.tag, ticks_limit);
|
||||
|
||||
CADICAL_assert (watching ());
|
||||
|
||||
auto &refs_schedule = current_refs_schedule (vivifier);
|
||||
auto &schedule = current_schedule (vivifier);
|
||||
|
||||
PHASE ("vivify", stats.vivifications,
|
||||
"starting %c vivification round ticks limit %" PRId64
|
||||
" with %zu clauses",
|
||||
vivifier.tag, ticks_limit, schedule.size ());
|
||||
|
||||
CADICAL_assert (watching ());
|
||||
|
||||
int64_t ticks = 1 + schedule.size ();
|
||||
|
||||
// Sort candidates, with first to be tried candidate clause last, i.e.,
|
||||
|
|
@ -1609,7 +1544,7 @@ void Internal::vivify_round (Vivifier &vivifier, int64_t ticks_limit) {
|
|||
//
|
||||
|
||||
// first build the schedule with vivifier_refs
|
||||
auto end_schedule = end (schedule);
|
||||
const auto end_schedule = end (schedule);
|
||||
refs_schedule.resize (schedule.size ());
|
||||
std::transform (begin (schedule), end_schedule, begin (refs_schedule),
|
||||
[&] (Clause *c) { return create_ref (this, c); });
|
||||
|
|
@ -1629,8 +1564,7 @@ void Internal::vivify_round (Vivifier &vivifier, int64_t ticks_limit) {
|
|||
std::transform (begin (refs_schedule), end (refs_schedule),
|
||||
begin (schedule),
|
||||
[] (vivify_ref c) { return c.clause; });
|
||||
erase_vector (refs_schedule);
|
||||
LOG ("clause after sorting final:");
|
||||
refs_schedule.clear ();
|
||||
} else {
|
||||
// skip sorting but still put clauses with the vivify tag at the end to
|
||||
// be done first Kissat does this implicitely by going twice over all
|
||||
|
|
@ -1697,10 +1631,10 @@ void Internal::vivify_round (Vivifier &vivifier, int64_t ticks_limit) {
|
|||
for (auto c : schedule)
|
||||
c->vivify = true;
|
||||
#elif 1
|
||||
// if we have gone through all the leftovers, the current clauses are
|
||||
// leftovers for the next round
|
||||
if (!schedule.empty () && !schedule.front ()->vivify &&
|
||||
schedule.back ()->vivify)
|
||||
// if we have gone through all the leftovers (the next candidate
|
||||
// is not one), all the current clauses are leftovers for the next
|
||||
// round
|
||||
if (!schedule.empty () && !schedule.back ()->vivify)
|
||||
for (auto c : schedule)
|
||||
c->vivify = true;
|
||||
#else
|
||||
|
|
@ -1852,8 +1786,15 @@ bool Internal::vivify () {
|
|||
}
|
||||
int64_t init_ticks = 0;
|
||||
|
||||
// Refill the schedule every time. Unchecked clauses are 'saved' by
|
||||
// Refill the schedule every time. Unchecked clauses are 'saved' by
|
||||
// setting their 'vivify' bit, such that they can be tried next time.
|
||||
// There are two things to denote: the option 'vivifyonce' does what it is
|
||||
// supposed to do, and it works because the ticks are kept for the next
|
||||
// schedule. Also, we limit the size of the schedule to limit the cost of
|
||||
// sorting.
|
||||
//
|
||||
// TODO: After limiting, the cost we fixed some heuristics bug, so maybe
|
||||
// we could increase the limit.
|
||||
//
|
||||
// TODO: count against ticks.vivify directly instead of this unholy
|
||||
// shifting.
|
||||
|
|
@ -1880,9 +1821,9 @@ bool Internal::vivify () {
|
|||
}
|
||||
|
||||
if (!unsat && tier2effort) {
|
||||
erase_vector (
|
||||
vivifier.schedule_tier1); // save memory (well, not really as we
|
||||
// already reached the peak memory)
|
||||
// save memory (well, not really as we
|
||||
// already reached the peak memory)
|
||||
erase_vector (vivifier.schedule_tier1);
|
||||
if (limit < stats.ticks.vivify)
|
||||
limit = stats.ticks.vivify;
|
||||
const double effort = (total * tier2effort) / sumeffort;
|
||||
|
|
@ -1953,6 +1894,7 @@ bool Internal::vivify () {
|
|||
STOP_SIMPLIFIER (vivify, VIVIFY);
|
||||
|
||||
private_steps = false;
|
||||
CADICAL_assert (!ignore);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "walk.hpp"
|
||||
#include "internal.hpp"
|
||||
#include "random.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
|
|
@ -10,21 +12,45 @@ namespace CaDiCaL {
|
|||
|
||||
// Random walk local search based on 'ProbSAT' ideas.
|
||||
|
||||
// We (based on the Master project from Leah Hohl) tried to ticks
|
||||
// local search similarly to the other parts of the solver with
|
||||
// limited success however.
|
||||
//
|
||||
// On the problem `ncc_none_5047_6_3_3_3_0_435991723', the broken part
|
||||
// of walk_flip is very cheap and should not be counted in ticks, but
|
||||
// on various other problems `9pipe_k' it is very important to ticks
|
||||
// this part too.
|
||||
|
||||
// using ClauseOrBinary = std::variant <Clause*, TaggedBinary>;
|
||||
|
||||
struct Walker {
|
||||
|
||||
Internal *internal;
|
||||
|
||||
Random random; // local random number generator
|
||||
int64_t propagations; // number of propagations
|
||||
int64_t limit; // limit on number of propagations
|
||||
vector<Clause *> broken; // currently unsatisfied clauses
|
||||
double epsilon; // smallest considered score
|
||||
vector<double> table; // break value to score table
|
||||
vector<double> scores; // scores of candidate literals
|
||||
|
||||
double score (unsigned); // compute score from break count
|
||||
|
||||
Walker (Internal *, double size, int64_t limit);
|
||||
// for efficiency, storing the model each time an improvement is
|
||||
// found is too costly. Instead we store some of the flips since
|
||||
// last time and the position of the best model found so far.
|
||||
Random random; // local random number generator
|
||||
int64_t ticks; // ticks to approximate run time
|
||||
int64_t limit; // limit on number of propagations
|
||||
vector<ClauseOrBinary> broken; // currently unsatisfied clauses
|
||||
double epsilon; // smallest considered score
|
||||
vector<double> table; // break value to score table
|
||||
vector<double> scores; // scores of candidate literals
|
||||
std::vector<int>
|
||||
flips; // remember the flips compared to the last best saved model
|
||||
int best_trail_pos;
|
||||
int64_t minimum = INT64_MAX;
|
||||
std::vector<signed char> best_values; // best model stored so far
|
||||
double score (unsigned); // compute score from break count
|
||||
#ifndef CADICAL_NDEBUG
|
||||
std::vector<signed char> current_best_model; // best model found so far
|
||||
#endif
|
||||
Walker (Internal *, int64_t limit);
|
||||
void populate_table (double size);
|
||||
void push_flipped (int flipped);
|
||||
void save_walker_trail (bool);
|
||||
void save_final_minimum (int64_t old_minimum);
|
||||
};
|
||||
|
||||
// These are in essence the CB values from Adrian Balint's thesis. They
|
||||
|
|
@ -64,11 +90,18 @@ inline static double fitcbval (double size) {
|
|||
|
||||
// Initialize the data structures for one local search round.
|
||||
|
||||
Walker::Walker (Internal *i, double size, int64_t l)
|
||||
Walker::Walker (Internal *i, int64_t l)
|
||||
: internal (i), random (internal->opts.seed), // global random seed
|
||||
propagations (0), limit (l) {
|
||||
ticks (0), limit (l), best_trail_pos (-1) {
|
||||
random += internal->stats.walk.count; // different seed every time
|
||||
flips.reserve (i->max_var / 4);
|
||||
best_values.resize (i->max_var + 1, 0);
|
||||
#ifndef CADICAL_NDEBUG
|
||||
current_best_model.resize (i->max_var + 1, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Walker::populate_table (double size) {
|
||||
// This is the magic constant in ProbSAT (also called 'CB'), which we pick
|
||||
// according to the average size every second invocation and otherwise
|
||||
// just the default '2.0', which turns into the base '0.5'.
|
||||
|
|
@ -87,6 +120,117 @@ Walker::Walker (Internal *i, double size, int64_t l)
|
|||
table.size ());
|
||||
}
|
||||
|
||||
// Add the literal to flip to the queue
|
||||
|
||||
void Walker::push_flipped (int flipped) {
|
||||
LOG ("push literal %s on the flips", LOGLIT (flipped));
|
||||
CADICAL_assert (flipped);
|
||||
if (best_trail_pos < 0) {
|
||||
LOG ("not pushing flipped %s to already invalid trail",
|
||||
LOGLIT (flipped));
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t size_trail = flips.size ();
|
||||
const size_t limit = internal->max_var / 4 + 1;
|
||||
if (size_trail < limit) {
|
||||
flips.push_back (flipped);
|
||||
LOG ("pushed flipped %s to trail which now has size %zd",
|
||||
LOGLIT (flipped), size_trail + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (best_trail_pos) {
|
||||
LOG ("trail reached limit %zd but has best position %d", limit,
|
||||
best_trail_pos);
|
||||
save_walker_trail (true);
|
||||
flips.push_back (flipped);
|
||||
LOG ("pushed flipped %s to trail which now has size %zu",
|
||||
LOGLIT (flipped), flips.size ());
|
||||
return;
|
||||
} else {
|
||||
LOG ("trail reached limit %zd without best position", limit);
|
||||
flips.clear ();
|
||||
LOG ("not pushing %s to invalidated trail", LOGLIT (flipped));
|
||||
best_trail_pos = -1;
|
||||
LOG ("best trail position becomes invalid");
|
||||
}
|
||||
}
|
||||
|
||||
void Walker::save_walker_trail (bool keep) {
|
||||
CADICAL_assert (best_trail_pos != -1);
|
||||
CADICAL_assert ((size_t) best_trail_pos <= flips.size ());
|
||||
// CADICAL_assert (!keep || best_trail_pos == flips.size());
|
||||
#ifdef LOGGING
|
||||
const size_t size_trail = flips.size ();
|
||||
#endif
|
||||
const int kept = flips.size () - best_trail_pos;
|
||||
LOG ("saving %d values of flipped literals on trail of size %zd",
|
||||
best_trail_pos, flips.size ());
|
||||
|
||||
const auto begin = flips.begin ();
|
||||
const auto best = flips.begin () + best_trail_pos;
|
||||
const auto end = flips.end ();
|
||||
|
||||
auto it = begin;
|
||||
for (; it != best; ++it) {
|
||||
const int lit = *it;
|
||||
CADICAL_assert (lit);
|
||||
const signed char value = sign (lit);
|
||||
const int idx = std::abs (lit);
|
||||
best_values[idx] = value;
|
||||
}
|
||||
if (!keep) {
|
||||
LOG ("no need to shift and keep remaining %u literals", kept);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto v : internal->vars) {
|
||||
if (internal->active (v))
|
||||
CADICAL_assert (best_values[v] == current_best_model[v]);
|
||||
}
|
||||
#endif
|
||||
LOG ("flushed %u literals %.0f%% from trail", best_trail_pos,
|
||||
percent (best_trail_pos, size_trail));
|
||||
CADICAL_assert (it == best);
|
||||
auto jt = begin;
|
||||
for (; it != end; ++it, ++jt) {
|
||||
CADICAL_assert (jt <= it);
|
||||
CADICAL_assert (it < end);
|
||||
*jt = *it;
|
||||
}
|
||||
|
||||
CADICAL_assert ((int) (end - jt) == best_trail_pos);
|
||||
CADICAL_assert ((int) (jt - begin) == kept);
|
||||
flips.resize (kept);
|
||||
LOG ("keeping %u literals %.0f%% on trail", kept,
|
||||
percent (kept, size_trail));
|
||||
LOG ("reset best trail position to 0");
|
||||
best_trail_pos = 0;
|
||||
}
|
||||
|
||||
// finally export_ the final minimum
|
||||
void Walker::save_final_minimum (int64_t old_init_minimum) {
|
||||
CADICAL_assert (minimum <= old_init_minimum);
|
||||
#ifdef CADICAL_NDEBUG
|
||||
(void) old_init_minimum;
|
||||
#endif
|
||||
|
||||
if (!best_trail_pos || best_trail_pos == -1)
|
||||
LOG ("minimum already saved");
|
||||
else
|
||||
save_walker_trail (false);
|
||||
|
||||
++internal->stats.walk.improved;
|
||||
for (auto v : internal->vars) {
|
||||
if (best_values[v])
|
||||
internal->phases.saved[v] = best_values[v];
|
||||
else
|
||||
CADICAL_assert (!internal->active (v));
|
||||
}
|
||||
internal->copy_phases (internal->phases.prev);
|
||||
}
|
||||
// The scores are tabulated for faster computation (to avoid 'pow').
|
||||
|
||||
inline double Walker::score (unsigned i) {
|
||||
|
|
@ -97,15 +241,22 @@ inline double Walker::score (unsigned i) {
|
|||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
Clause *Internal::walk_pick_clause (Walker &walker) {
|
||||
ClauseOrBinary Internal::walk_pick_clause (Walker &walker) {
|
||||
require_mode (WALK);
|
||||
CADICAL_assert (!walker.broken.empty ());
|
||||
int64_t size = walker.broken.size ();
|
||||
if (size > INT_MAX)
|
||||
size = INT_MAX;
|
||||
int pos = walker.random.pick_int (0, size - 1);
|
||||
Clause *res = walker.broken[pos];
|
||||
LOG (res, "picking random position %d", pos);
|
||||
ClauseOrBinary res = walker.broken[pos];
|
||||
#ifdef LOGGING
|
||||
Clause *c;
|
||||
if (!res.is_binary ())
|
||||
c = res.clause ();
|
||||
else
|
||||
c = res.tagged_binary ().d;
|
||||
LOG (c, "picking random position %d", pos);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -114,12 +265,14 @@ Clause *Internal::walk_pick_clause (Walker &walker) {
|
|||
// Compute the number of clauses which would be become unsatisfied if 'lit'
|
||||
// is flipped and set to false. This is called the 'break-count' of 'lit'.
|
||||
|
||||
unsigned Internal::walk_break_value (int lit) {
|
||||
|
||||
unsigned Internal::walk_break_value (int lit, int64_t &ticks) {
|
||||
require_mode (WALK);
|
||||
START (walkbreak);
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
const int64_t oldticks = ticks;
|
||||
|
||||
unsigned res = 0; // The computed break-count of 'lit'.
|
||||
ticks += (1 + cache_lines (watches (lit).size (), sizeof (Clause *)));
|
||||
|
||||
for (auto &w : watches (lit)) {
|
||||
CADICAL_assert (w.blit != lit);
|
||||
|
|
@ -131,6 +284,11 @@ unsigned Internal::walk_break_value (int lit) {
|
|||
}
|
||||
|
||||
Clause *c = w.clause;
|
||||
#ifdef LOGGING
|
||||
CADICAL_assert (c != dummy_binary);
|
||||
#endif
|
||||
++ticks;
|
||||
|
||||
CADICAL_assert (lit == c->literals[0]);
|
||||
|
||||
// Now try to find a second satisfied literal starting at 'literals[1]'
|
||||
|
|
@ -168,9 +326,10 @@ unsigned Internal::walk_break_value (int lit) {
|
|||
*i = prev;
|
||||
prev = other;
|
||||
}
|
||||
|
||||
res++; // Literal 'lit' single satisfies clause 'c'.
|
||||
}
|
||||
stats.ticks.walkbreak += (ticks - oldticks);
|
||||
STOP (walkbreak);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -191,6 +350,8 @@ unsigned Internal::walk_break_value (int lit) {
|
|||
int Internal::walk_pick_lit (Walker &walker, Clause *c) {
|
||||
LOG ("picking literal by break-count");
|
||||
CADICAL_assert (walker.scores.empty ());
|
||||
const int64_t old = walker.ticks;
|
||||
walker.ticks += 1;
|
||||
double sum = 0;
|
||||
int64_t propagations = 0;
|
||||
for (const auto lit : *c) {
|
||||
|
|
@ -201,16 +362,15 @@ int Internal::walk_pick_lit (Walker &walker, Clause *c) {
|
|||
}
|
||||
CADICAL_assert (active (lit));
|
||||
propagations++;
|
||||
unsigned tmp = walk_break_value (-lit);
|
||||
unsigned tmp = walk_break_value (-lit, walker.ticks);
|
||||
double score = walker.score (tmp);
|
||||
LOG ("literal %d break-count %u score %g", lit, tmp, score);
|
||||
walker.scores.push_back (score);
|
||||
sum += score;
|
||||
}
|
||||
(void) propagations; // TODO actually unused?
|
||||
LOG ("scored %zd literals", walker.scores.size ());
|
||||
CADICAL_assert (!walker.scores.empty ());
|
||||
walker.propagations += propagations;
|
||||
stats.propagations.walk += propagations;
|
||||
CADICAL_assert (walker.scores.size () <= (size_t) c->size);
|
||||
const double lim = sum * walker.random.generate_double ();
|
||||
LOG ("score sum %g limit %g", sum, lim);
|
||||
|
|
@ -236,13 +396,78 @@ int Internal::walk_pick_lit (Walker &walker, Clause *c) {
|
|||
}
|
||||
walker.scores.clear ();
|
||||
LOG ("picking literal %d by break-count", res);
|
||||
stats.ticks.walkpick += walker.ticks - old;
|
||||
return res;
|
||||
}
|
||||
|
||||
int Internal::walk_pick_lit (Walker &walker, ClauseOrBinary c) {
|
||||
if (c.is_binary ())
|
||||
return walk_pick_lit (walker, c.tagged_binary ());
|
||||
return walk_pick_lit (walker, c.clause ());
|
||||
}
|
||||
|
||||
int Internal::walk_pick_lit (Walker &walker, const TaggedBinary c) {
|
||||
LOG ("picking literal by break-count on binary clause [%" PRIu64 "]%s %s",
|
||||
c.d->id, LOGLIT (c.lit), LOGLIT (c.other));
|
||||
CADICAL_assert (walker.scores.empty ());
|
||||
const int64_t old = walker.ticks;
|
||||
double sum = 0;
|
||||
int64_t propagations = 0;
|
||||
const std::array<int, 2> clause = {c.lit, c.other};
|
||||
for (const auto lit : clause) {
|
||||
CADICAL_assert (active (lit));
|
||||
if (var (lit).level == 1) {
|
||||
LOG ("skipping assumption %d for scoring", -lit);
|
||||
continue;
|
||||
}
|
||||
CADICAL_assert (active (lit));
|
||||
CADICAL_assert (val (lit) < 0);
|
||||
propagations++;
|
||||
unsigned tmp = walk_break_value (-lit, walker.ticks);
|
||||
double score = walker.score (tmp);
|
||||
LOG ("literal %d break-count %u score %g", lit, tmp, score);
|
||||
walker.scores.push_back (score);
|
||||
sum += score;
|
||||
}
|
||||
(void) propagations; // TODO unused?
|
||||
LOG ("scored %zd literals", walker.scores.size ());
|
||||
CADICAL_assert (!walker.scores.empty ());
|
||||
CADICAL_assert (walker.scores.size () <= (size_t) 2);
|
||||
const double lim = sum * walker.random.generate_double ();
|
||||
LOG ("score sum %g limit %g", sum, lim);
|
||||
const auto end = clause.end ();
|
||||
auto i = clause.begin ();
|
||||
auto j = walker.scores.begin ();
|
||||
int res = 0;
|
||||
for (;;) {
|
||||
CADICAL_assert (i != end);
|
||||
res = *i++;
|
||||
if (var (res).level > 1)
|
||||
break;
|
||||
LOG ("skipping assumption %d without score", -res);
|
||||
}
|
||||
sum = *j++;
|
||||
while (sum <= lim && i != end) {
|
||||
res = *i++;
|
||||
if (var (res).level == 1) {
|
||||
LOG ("skipping assumption %d without score", -res);
|
||||
continue;
|
||||
}
|
||||
sum += *j++;
|
||||
}
|
||||
CADICAL_assert (res);
|
||||
walker.scores.clear ();
|
||||
LOG ("picking literal %d by break-count", res);
|
||||
stats.ticks.walkpick += walker.ticks - old;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void Internal::walk_flip_lit (Walker &walker, int lit) {
|
||||
|
||||
// flips a literal unless we run out of ticks.
|
||||
bool Internal::walk_flip_lit (Walker &walker, int lit) {
|
||||
START (walkflip);
|
||||
const int64_t old = walker.ticks;
|
||||
require_mode (WALK);
|
||||
LOG ("flipping assign %d", lit);
|
||||
CADICAL_assert (val (lit) < 0);
|
||||
|
|
@ -254,39 +479,74 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
set_val (idx, tmp);
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
|
||||
// we are going to need it anyway and it probably still is in memory
|
||||
const Watches &ws = watches (-lit);
|
||||
if (!ws.empty ()) {
|
||||
const Watch &w = ws[0];
|
||||
#ifndef WIN32
|
||||
__builtin_prefetch (&w, 0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Then remove 'c' and all other now satisfied (made) clauses.
|
||||
{
|
||||
// Simply go over all unsatisfied (broken) clauses.
|
||||
|
||||
LOG ("trying to make %zd broken clauses", walker.broken.size ());
|
||||
|
||||
// We need to measure (and bound) the memory accesses during traversing
|
||||
// broken clauses in terms of 'propagations'. This is tricky since we
|
||||
// are not actually propagating literals. Instead we use the clause
|
||||
// variable 'ratio' as an approximation to the number of clauses used
|
||||
// during propagating a literal. Note that we use a one-watch scheme.
|
||||
// Accordingly the number of broken clauses traversed divided by that
|
||||
// ratio is an approximation of the number of propagation this would
|
||||
// correspond to (in terms of memory access). To eagerly update these
|
||||
// statistics we simply increment the propagation counter after every
|
||||
// 'ratio' traversed clause. These propagations are particularly
|
||||
// expensive if the number of broken clauses is large which usually
|
||||
// happens initially.
|
||||
//
|
||||
const double ratio = clause_variable_ratio ();
|
||||
const auto eou = walker.broken.end ();
|
||||
// broken is in cache given how central it is... but not always (see the
|
||||
// ncc problems). Value was heuristically determined to give reasonnable
|
||||
// values.
|
||||
walker.ticks +=
|
||||
1 + cache_lines (walker.broken.size (), sizeof (Clause *));
|
||||
auto j = walker.broken.begin (), i = j;
|
||||
#ifdef LOGGING
|
||||
#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
|
||||
int64_t made = 0;
|
||||
#endif
|
||||
int64_t count = 0;
|
||||
|
||||
while (i != eou) {
|
||||
|
||||
Clause *d = *j++ = *i++;
|
||||
ClauseOrBinary tagged = *j++ = *i++;
|
||||
|
||||
int *literals = d->literals, prev = 0;
|
||||
if (tagged.is_binary ()) {
|
||||
const TaggedBinary &b = tagged.tagged_binary ();
|
||||
const int clit = b.lit;
|
||||
const int other = b.other;
|
||||
CADICAL_assert (val (clit) < 0 || val (other) < 0);
|
||||
#if defined(LOGGING)
|
||||
CADICAL_assert (b.d->literals[0] == clit || b.d->literals[1] == clit);
|
||||
CADICAL_assert (b.d->literals[0] == other || b.d->literals[1] == other);
|
||||
#endif
|
||||
if (clit == lit || other == lit) {
|
||||
LOG (b.d, "made");
|
||||
const int first_lit = lit;
|
||||
const int second_lit = clit ^ lit ^ other;
|
||||
#ifdef LOGGING
|
||||
watch_binary_literal (first_lit, second_lit, b.d);
|
||||
#else
|
||||
// placeholder for the clause, does not matter
|
||||
watch_binary_literal (first_lit, second_lit, dummy_binary);
|
||||
#endif
|
||||
|
||||
++walker.ticks;
|
||||
#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
|
||||
made++;
|
||||
#endif
|
||||
j--;
|
||||
} else {
|
||||
LOG (b.d, "still broken");
|
||||
CADICAL_assert (val (clit) < 0 && val (other) < 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// now the expansive part
|
||||
Clause *d = tagged.clause ();
|
||||
++walker.ticks;
|
||||
int *literals = d->literals;
|
||||
LOG (d, "search for replacement");
|
||||
int prev = 0;
|
||||
// Find 'lit' in 'd'.
|
||||
//
|
||||
const int size = d->size;
|
||||
|
|
@ -299,18 +559,17 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
break;
|
||||
CADICAL_assert (val (other) < 0);
|
||||
}
|
||||
|
||||
// If 'lit' is in 'd' then move it to the front to watch it.
|
||||
//
|
||||
if (prev == lit) {
|
||||
literals[0] = lit;
|
||||
LOG (d, "made");
|
||||
watch_literal (literals[0], literals[1], d);
|
||||
#ifdef LOGGING
|
||||
++walker.ticks;
|
||||
#if defined(LOGGING) || !defined(CADICAL_NDEBUG)
|
||||
made++;
|
||||
#endif
|
||||
j--;
|
||||
|
||||
} else { // Otherwise the clause is not satisfied, undo shift.
|
||||
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
|
|
@ -319,41 +578,81 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
prev = other;
|
||||
}
|
||||
}
|
||||
|
||||
if (count--)
|
||||
continue;
|
||||
|
||||
// Update these counters eagerly. Otherwise if we delay the update
|
||||
// until all clauses are traversed, interrupting the solver has a high
|
||||
// chance of giving bogus statistics on the number of 'propagations'
|
||||
// in 'walk', if it is interrupted in this loop.
|
||||
|
||||
count = ratio; // Starting counting down again.
|
||||
walker.propagations++;
|
||||
stats.propagations.walk++;
|
||||
LOG (d, "clause after undoing shift");
|
||||
}
|
||||
LOG ("made %" PRId64 " clauses by flipping %d", made, lit);
|
||||
CADICAL_assert ((int64_t) (j - walker.broken.begin ()) + made ==
|
||||
(int64_t) walker.broken.size ());
|
||||
walker.broken.resize (j - walker.broken.begin ());
|
||||
LOG ("made %" PRId64 " clauses by flipping %d, still %zu broken", made,
|
||||
lit, walker.broken.size ());
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto d : walker.broken) {
|
||||
if (d.is_binary ()) {
|
||||
const TaggedBinary &b = d.tagged_binary ();
|
||||
CADICAL_assert (val (b.lit) < 0 && val (b.other) < 0);
|
||||
} else {
|
||||
for (auto lit : *d.clause ())
|
||||
CADICAL_assert (val (lit) < 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (walker.ticks > walker.limit) {
|
||||
STOP (walkflip);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stats.ticks.walkflipbroken += walker.ticks - old;
|
||||
|
||||
const int64_t old_after_broken = walker.ticks;
|
||||
|
||||
// Finally add all new unsatisfied (broken) clauses.
|
||||
{
|
||||
walker.propagations++; // This really corresponds now to one
|
||||
stats.propagations.walk++; // propagation (in a one-watch scheme).
|
||||
|
||||
#ifdef LOGGING
|
||||
int64_t broken = 0;
|
||||
#endif
|
||||
Watches &ws = watches (-lit);
|
||||
// probably still in cache
|
||||
walker.ticks += 1 + cache_lines (ws.size (), sizeof (Clause *));
|
||||
|
||||
LOG ("trying to break %zd watched clauses", ws.size ());
|
||||
|
||||
for (const auto &w : ws) {
|
||||
Clause *d = w.clause;
|
||||
LOG (d, "unwatch %d in", -lit);
|
||||
const bool binary = w.binary ();
|
||||
if (binary) {
|
||||
const int other = w.blit;
|
||||
CADICAL_assert (w.blit != -lit);
|
||||
if (val (other) > 0) {
|
||||
LOG (d, "unwatch %d in", -lit);
|
||||
watch_binary_literal (other, -lit, d);
|
||||
++walker.ticks;
|
||||
continue;
|
||||
}
|
||||
LOG (d, "broken");
|
||||
#ifdef LOGGING
|
||||
CADICAL_assert (d != dummy_binary);
|
||||
#endif
|
||||
walker.broken.push_back (TaggedBinary (d, -lit, other));
|
||||
++walker.ticks;
|
||||
#ifdef LOGGING
|
||||
broken++;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (walker.ticks > walker.limit) {
|
||||
STOP (walkflip);
|
||||
return false;
|
||||
}
|
||||
// now the expansive part
|
||||
CADICAL_assert (d->size != 2);
|
||||
++walker.ticks;
|
||||
int *literals = d->literals, replacement = 0, prev = -lit;
|
||||
CADICAL_assert (literals[0] == -lit);
|
||||
CADICAL_assert (d->size == w.size);
|
||||
const int size = d->size;
|
||||
CADICAL_assert (literals[0] == -lit);
|
||||
|
||||
for (int i = 1; i < size; i++) {
|
||||
const int other = literals[i];
|
||||
CADICAL_assert (active (other));
|
||||
|
|
@ -366,19 +665,23 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
break;
|
||||
}
|
||||
if (replacement) {
|
||||
CADICAL_assert (-lit != replacement);
|
||||
literals[1] = -lit;
|
||||
literals[0] = replacement;
|
||||
CADICAL_assert (-lit != replacement);
|
||||
watch_literal (replacement, -lit, d);
|
||||
++walker.ticks;
|
||||
LOG (d, "found replacement");
|
||||
} else {
|
||||
for (int i = size - 1; i > 0; i--) { // undo shift
|
||||
const int other = literals[i];
|
||||
literals[i] = prev;
|
||||
prev = other;
|
||||
}
|
||||
|
||||
CADICAL_assert (literals[0] == -lit);
|
||||
LOG (d, "broken");
|
||||
walker.broken.push_back (d);
|
||||
++walker.ticks;
|
||||
#ifdef LOGGING
|
||||
broken++;
|
||||
#endif
|
||||
|
|
@ -387,6 +690,10 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
LOG ("broken %" PRId64 " clauses by flipping %d", broken, lit);
|
||||
ws.clear ();
|
||||
}
|
||||
STOP (walkflip);
|
||||
stats.ticks.walkflipWL += walker.ticks - old_after_broken;
|
||||
stats.ticks.walkflip += walker.ticks - old;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
|
@ -395,14 +702,58 @@ void Internal::walk_flip_lit (Walker &walker, int lit) {
|
|||
|
||||
inline void Internal::walk_save_minimum (Walker &walker) {
|
||||
int64_t broken = walker.broken.size ();
|
||||
if (broken >= stats.walk.minimum)
|
||||
if (broken >= walker.minimum)
|
||||
return;
|
||||
VERBOSE (3, "new global minimum %" PRId64 "", broken);
|
||||
stats.walk.minimum = broken;
|
||||
if (broken <= stats.walk.minimum) {
|
||||
stats.walk.minimum = broken;
|
||||
VERBOSE (3, "new global minimum %" PRId64 "", broken);
|
||||
} else {
|
||||
VERBOSE (3, "new walk minimum %" PRId64 "", broken);
|
||||
}
|
||||
|
||||
walker.minimum = broken;
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto i : vars) {
|
||||
const signed char tmp = vals[i];
|
||||
if (tmp)
|
||||
phases.min[i] = phases.saved[i] = tmp;
|
||||
walker.current_best_model[i] = tmp;
|
||||
}
|
||||
if (walker.minimum == 0) {
|
||||
for (auto c : clauses) {
|
||||
if (c->garbage)
|
||||
continue;
|
||||
if (c->redundant)
|
||||
continue;
|
||||
int satisfied = 0;
|
||||
for (const auto &lit : *c) {
|
||||
const int tmp = internal->val (lit);
|
||||
if (tmp > 0) {
|
||||
LOG (c, "satisfied literal %d in", lit);
|
||||
satisfied++;
|
||||
}
|
||||
}
|
||||
CADICAL_assert (satisfied);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (walker.best_trail_pos == -1) {
|
||||
VERBOSE (3, "saving the new walk minimum %" PRId64 "", broken);
|
||||
for (auto i : vars) {
|
||||
const signed char tmp = vals[i];
|
||||
if (tmp) {
|
||||
walker.best_values[i] = tmp;
|
||||
#ifndef CADICAL_NDEBUG
|
||||
CADICAL_assert (tmp == walker.current_best_model[i]);
|
||||
#endif
|
||||
} else {
|
||||
CADICAL_assert (!active (i));
|
||||
}
|
||||
}
|
||||
walker.best_trail_pos = 0;
|
||||
} else {
|
||||
walker.best_trail_pos = walker.flips.size ();
|
||||
LOG ("new best trail position %u", walker.best_trail_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -410,13 +761,6 @@ inline void Internal::walk_save_minimum (Walker &walker) {
|
|||
|
||||
int Internal::walk_round (int64_t limit, bool prev) {
|
||||
|
||||
backtrack ();
|
||||
if (propagated < trail.size () && !propagate ()) {
|
||||
LOG ("empty clause after root level propagation");
|
||||
learn_empty_clause ();
|
||||
return 20;
|
||||
}
|
||||
|
||||
stats.walk.count++;
|
||||
|
||||
clear_watches ();
|
||||
|
|
@ -435,34 +779,15 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
}
|
||||
#endif
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"random walk limit of %" PRId64 " propagations", limit);
|
||||
|
||||
// First compute the average clause size for picking the CB constant.
|
||||
//
|
||||
double size = 0;
|
||||
int64_t n = 0;
|
||||
for (const auto c : clauses) {
|
||||
if (c->garbage)
|
||||
continue;
|
||||
if (c->redundant) {
|
||||
if (!opts.walkredundant)
|
||||
continue;
|
||||
if (!likely_to_be_kept_clause (c))
|
||||
continue;
|
||||
}
|
||||
size += c->size;
|
||||
n++;
|
||||
}
|
||||
double average_size = relative (size, n);
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"%" PRId64 " clauses average size %.2f over %d variables", n,
|
||||
average_size, active ());
|
||||
PHASE ("walk", stats.walk.count, "random walk limit of %" PRId64 " ticks",
|
||||
limit);
|
||||
|
||||
// Instantiate data structures for this local search round.
|
||||
//
|
||||
Walker walker (internal, average_size, limit);
|
||||
Walker walker (internal, limit);
|
||||
#ifndef CADICAL_QUIET
|
||||
int old_global_minimum = stats.walk.minimum;
|
||||
#endif
|
||||
|
||||
bool failed = false; // Inconsistent assumptions?
|
||||
|
||||
|
|
@ -498,6 +823,8 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
|
||||
if (!failed) {
|
||||
|
||||
// warmup stores the result in phases, not in target
|
||||
const bool target = opts.warmup ? false : stable || opts.target == 2;
|
||||
for (auto idx : vars) {
|
||||
if (!active (idx)) {
|
||||
LOG ("skipping inactive variable %d", idx);
|
||||
|
|
@ -512,7 +839,7 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
if (prev)
|
||||
tmp = phases.prev[idx];
|
||||
if (!tmp)
|
||||
tmp = sign (decide_phase (idx, true));
|
||||
tmp = sign (decide_phase (idx, target));
|
||||
CADICAL_assert (tmp == 1 || tmp == -1);
|
||||
set_val (idx, tmp);
|
||||
CADICAL_assert (level == 2);
|
||||
|
|
@ -524,6 +851,9 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
#ifdef LOGGING
|
||||
int64_t watched = 0;
|
||||
#endif
|
||||
|
||||
double size = 0;
|
||||
int64_t n = 0;
|
||||
for (const auto c : clauses) {
|
||||
|
||||
if (c->garbage)
|
||||
|
|
@ -539,6 +869,8 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
int satisfied = 0; // clause satisfied?
|
||||
|
||||
int *lits = c->literals;
|
||||
size += c->size;
|
||||
n++;
|
||||
const int size = c->size;
|
||||
|
||||
// Move to front satisfied literals and determine whether there
|
||||
|
|
@ -565,16 +897,31 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
}
|
||||
|
||||
if (satisfied) {
|
||||
watch_literal (lits[0], lits[1], c);
|
||||
LOG (c, "pushing to satisfied");
|
||||
if (c->size == 2)
|
||||
watch_binary_literal (lits[0], lits[1], c);
|
||||
else
|
||||
watch_literal (lits[0], lits[1], c);
|
||||
#ifdef LOGGING
|
||||
watched++;
|
||||
#endif
|
||||
} else {
|
||||
CADICAL_assert (satisfiable); // at least one non-assumed variable ...
|
||||
LOG (c, "broken");
|
||||
walker.broken.push_back (c);
|
||||
CADICAL_assert (c->size == size);
|
||||
if (size == 2)
|
||||
walker.broken.push_back (TaggedBinary (c));
|
||||
else
|
||||
walker.broken.push_back (c);
|
||||
}
|
||||
}
|
||||
|
||||
double average_size = relative (size, n);
|
||||
walker.populate_table (average_size);
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"%" PRId64 " clauses average size %.2f over %d variables", n,
|
||||
average_size, active ());
|
||||
|
||||
#ifdef LOGGING
|
||||
if (!failed) {
|
||||
int64_t broken = walker.broken.size ();
|
||||
|
|
@ -586,13 +933,14 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int64_t old_global_minimum = stats.walk.minimum;
|
||||
CADICAL_assert (failed || walker.table.size ());
|
||||
|
||||
int res; // Tells caller to continue with local search.
|
||||
|
||||
if (!failed) {
|
||||
|
||||
int64_t broken = walker.broken.size ();
|
||||
int64_t initial_minimum = broken;
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"starting with %" PRId64 " unsatisfied clauses "
|
||||
|
|
@ -601,21 +949,25 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
stats.current.irredundant);
|
||||
|
||||
walk_save_minimum (walker);
|
||||
CADICAL_assert (stats.walk.minimum <= walker.minimum);
|
||||
|
||||
int64_t minimum = broken;
|
||||
#ifndef CADICAL_QUIET
|
||||
int64_t flips = 0;
|
||||
#endif
|
||||
while (!terminated_asynchronously () && !walker.broken.empty () &&
|
||||
walker.propagations < walker.limit) {
|
||||
walker.ticks < walker.limit) {
|
||||
#ifndef CADICAL_QUIET
|
||||
flips++;
|
||||
#endif
|
||||
stats.walk.flips++;
|
||||
stats.walk.broken += broken;
|
||||
Clause *c = walk_pick_clause (walker);
|
||||
ClauseOrBinary c = walk_pick_clause (walker);
|
||||
const int lit = walk_pick_lit (walker, c);
|
||||
walk_flip_lit (walker, lit);
|
||||
bool finished = walk_flip_lit (walker, lit);
|
||||
if (!finished)
|
||||
break;
|
||||
walker.push_flipped (lit);
|
||||
broken = walker.broken.size ();
|
||||
LOG ("now have %" PRId64 " broken clauses in total", broken);
|
||||
if (broken >= minimum)
|
||||
|
|
@ -626,33 +978,41 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
walk_save_minimum (walker);
|
||||
}
|
||||
|
||||
if (minimum < old_global_minimum)
|
||||
walker.save_final_minimum (initial_minimum);
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
if (minimum == initial_minimum) {
|
||||
PHASE ("walk", internal->stats.walk.count,
|
||||
"%sno improvement %" PRId64 "%s in %" PRId64 " flips and "
|
||||
"%" PRId64 " ticks",
|
||||
tout.bright_yellow_code (), minimum, tout.normal_code (),
|
||||
flips, walker.ticks);
|
||||
} else if (minimum < old_global_minimum)
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"%snew global minimum %" PRId64 "%s in %" PRId64 " flips and "
|
||||
"%" PRId64 " propagations",
|
||||
"%" PRId64 " ticks",
|
||||
tout.bright_yellow_code (), minimum, tout.normal_code (),
|
||||
flips, walker.propagations);
|
||||
flips, walker.ticks);
|
||||
else
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"best phase minimum %" PRId64 " in %" PRId64 " flips and "
|
||||
"%" PRId64 " propagations",
|
||||
minimum, flips, walker.propagations);
|
||||
"%" PRId64 " ticks",
|
||||
minimum, flips, walker.ticks);
|
||||
|
||||
if (opts.profile >= 2) {
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"%.2f million propagations per second",
|
||||
relative (1e-6 * walker.propagations,
|
||||
time () - profiles.walk.started));
|
||||
PHASE ("walk", stats.walk.count, "%.2f million ticks per second",
|
||||
1e-6 *
|
||||
relative (walker.ticks, time () - profiles.walk.started));
|
||||
|
||||
PHASE ("walk", stats.walk.count, "%.2f thousand flips per second",
|
||||
relative (1e-3 * flips, time () - profiles.walk.started));
|
||||
|
||||
} else {
|
||||
PHASE ("walk", stats.walk.count, "%.2f million propagations",
|
||||
1e-6 * walker.propagations);
|
||||
PHASE ("walk", stats.walk.count, "%.2f ticks", 1e-6 * walker.ticks);
|
||||
|
||||
PHASE ("walk", stats.walk.count, "%.2f thousand flips", 1e-3 * flips);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (minimum > 0) {
|
||||
LOG ("minimum %" PRId64 " non-zero thus potentially continue",
|
||||
|
|
@ -671,8 +1031,6 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
"aborted due to inconsistent assumptions");
|
||||
}
|
||||
|
||||
copy_phases (phases.prev);
|
||||
|
||||
for (auto idx : vars)
|
||||
if (active (idx))
|
||||
set_val (idx, 0);
|
||||
|
|
@ -689,20 +1047,48 @@ int Internal::walk_round (int64_t limit, bool prev) {
|
|||
force_phase_messages = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
stats.ticks.walk += walker.ticks;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Internal::walk () {
|
||||
START_INNER_WALK ();
|
||||
int64_t limit = stats.propagations.search;
|
||||
|
||||
backtrack ();
|
||||
if (propagated < trail.size () && !propagate ()) {
|
||||
LOG ("empty clause after root level propagation");
|
||||
learn_empty_clause ();
|
||||
STOP_INNER_WALK ();
|
||||
return;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
if (opts.warmup)
|
||||
res = warmup ();
|
||||
if (res) {
|
||||
LOG ("stopping walk due to warmup");
|
||||
STOP_INNER_WALK ();
|
||||
return;
|
||||
}
|
||||
const int64_t ticks = stats.ticks.search[0] + stats.ticks.search[1];
|
||||
int64_t limit = ticks - last.walk.ticks;
|
||||
VERBOSE (2,
|
||||
"walk scheduling: last %" PRId64 " current %" PRId64
|
||||
" delta %" PRId64,
|
||||
last.walk.ticks, ticks, limit);
|
||||
last.walk.ticks = ticks;
|
||||
limit *= 1e-3 * opts.walkeffort;
|
||||
if (limit < opts.walkmineff)
|
||||
limit = opts.walkmineff;
|
||||
if (limit > opts.walkmaxeff)
|
||||
limit = opts.walkmaxeff;
|
||||
// local search is very cache friendly, so we actually really go over a
|
||||
// lot of ticks
|
||||
if (limit > 1e3 * opts.walkmaxeff) {
|
||||
MSG ("reached maximum efficiency %" PRId64, limit);
|
||||
limit = 1e3 * opts.walkmaxeff;
|
||||
}
|
||||
(void) walk_round (limit, false);
|
||||
STOP_INNER_WALK ();
|
||||
CADICAL_assert (!unsat);
|
||||
}
|
||||
|
||||
} // namespace CaDiCaL
|
||||
|
|
|
|||
|
|
@ -0,0 +1,972 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "internal.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
namespace CaDiCaL {
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Random walk local search based on 'ProbSAT' ideas.
|
||||
struct Tagged {
|
||||
bool binary : 1;
|
||||
unsigned counter_pos : 31;
|
||||
#ifndef CADICAL_NDEBUG
|
||||
Clause *c;
|
||||
#endif
|
||||
explicit Tagged () { CADICAL_assert (false); }
|
||||
explicit Tagged (Clause *d, unsigned pos)
|
||||
: binary (d->size == 2), counter_pos (pos) {
|
||||
CADICAL_assert ((pos & (1 << 31)) == 0);
|
||||
#ifndef CADICAL_NDEBUG
|
||||
c = d;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
struct Counter {
|
||||
unsigned count; // number of false literals
|
||||
unsigned pos; // pos in the broken clauses
|
||||
Clause *clause; // pointer to the clause itself
|
||||
explicit Counter (unsigned c, unsigned p, Clause *d)
|
||||
: count (c), pos (p), clause (d) {}
|
||||
explicit Counter (unsigned c, Clause *d)
|
||||
: count (c), pos (UINT32_MAX), clause (d) {}
|
||||
};
|
||||
|
||||
struct WalkerFO {
|
||||
|
||||
Internal *internal;
|
||||
|
||||
// for efficiency, storing the model each time an improvement is
|
||||
// found is too costly. Instead we store some of the flips since
|
||||
// last time and the position of the best model found so far.
|
||||
Random random; // local random number generator
|
||||
int64_t ticks; // ticks to approximate run time
|
||||
int64_t limit; // limit on number of propagations
|
||||
vector<Tagged> broken; // currently unsatisfied clauses
|
||||
double epsilon; // smallest considered score
|
||||
vector<double> table; // break value to score table
|
||||
vector<double> scores; // scores of candidate literals
|
||||
std::vector<int>
|
||||
flips; // remember the flips compared to the last best saved model
|
||||
int best_trail_pos;
|
||||
int64_t minimum = INT64_MAX;
|
||||
std::vector<signed char> best_values; // best model found so far
|
||||
double score (unsigned); // compute score from break count
|
||||
|
||||
std::vector<Counter> tclauses;
|
||||
std::vector<std::vector<Tagged>> tcounters;
|
||||
|
||||
using TOccs = std::vector<Tagged>;
|
||||
TOccs &occs (int lit) {
|
||||
const int idx = internal->vlit (lit);
|
||||
CADICAL_assert ((size_t) idx < tcounters.size ());
|
||||
return tcounters[idx];
|
||||
}
|
||||
const TOccs &occs (int lit) const {
|
||||
const int idx = internal->vlit (lit);
|
||||
CADICAL_assert ((size_t) idx < tcounters.size ());
|
||||
return tcounters[idx];
|
||||
}
|
||||
void connect_clause (int lit, Clause *clause, unsigned pos) {
|
||||
CADICAL_assert (pos < tclauses.size ());
|
||||
CADICAL_assert (tclauses[pos].clause == clause);
|
||||
LOG (clause, "connecting clause on %d with already in occurrences %zu",
|
||||
lit, occs (lit).size ());
|
||||
occs (lit).push_back (Tagged (clause, pos));
|
||||
}
|
||||
void connect_clause (Clause *clause, unsigned pos) {
|
||||
CADICAL_assert (pos < tclauses.size ());
|
||||
CADICAL_assert (tclauses[pos].clause == clause);
|
||||
for (auto lit : *clause)
|
||||
connect_clause (lit, clause, pos);
|
||||
}
|
||||
|
||||
void check_occs () const {
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto lit : internal->lits) {
|
||||
for (auto w : occs (lit)) {
|
||||
CADICAL_assert (w.counter_pos < tclauses.size ());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned unsatisfied = 0;
|
||||
for (auto c : tclauses) {
|
||||
unsigned count = 0;
|
||||
LOG (c.clause, "checking clause with counter %d:", c.count);
|
||||
for (auto lit : *c.clause) {
|
||||
if (internal->val (lit) > 0)
|
||||
++count;
|
||||
}
|
||||
CADICAL_assert (count == c.count);
|
||||
if (!count)
|
||||
++unsatisfied;
|
||||
}
|
||||
CADICAL_assert (broken.size () == unsatisfied);
|
||||
#endif
|
||||
}
|
||||
void check_broken () const {
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (size_t i = 0; i < broken.size (); ++i) {
|
||||
const Tagged t = broken[i];
|
||||
CADICAL_assert (t.c);
|
||||
CADICAL_assert (t.counter_pos < tclauses.size ());
|
||||
CADICAL_assert (tclauses[t.counter_pos].clause == t.c);
|
||||
for (auto lit : *t.c) {
|
||||
CADICAL_assert (internal->val (lit) < 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_all () const {
|
||||
check_broken ();
|
||||
check_occs ();
|
||||
}
|
||||
|
||||
static const uint32_t invalid_position = UINT32_MAX;
|
||||
void make_clause (Tagged t);
|
||||
|
||||
WalkerFO (Internal *, double size, int64_t limit);
|
||||
void push_flipped (int flipped);
|
||||
void save_walker_trail (bool);
|
||||
void save_final_minimum (int64_t old_minimum);
|
||||
void make_clauses_along_occurrences (int lit);
|
||||
void make_clauses_along_unsatisfied (int lit);
|
||||
void make_clauses (int lit);
|
||||
void break_clauses (int lit);
|
||||
unsigned walk_full_occs_pick_clause ();
|
||||
void walk_full_occs_flip_lit (int lit);
|
||||
int walk_full_occs_pick_lit (Clause *);
|
||||
unsigned walk_full_occs_break_value (int lit);
|
||||
};
|
||||
|
||||
// These are in essence the CB values from Adrian Balint's thesis. They
|
||||
// denote the inverse 'cb' of the base 'b' of the (probability) weight
|
||||
// 'b^-i' for picking a literal with the break value 'i' (first column is
|
||||
// the 'size', second the 'CB' value).
|
||||
|
||||
static double cbvals[][2] = {
|
||||
{0.0, 2.00}, {3.0, 2.50}, {4.0, 2.85}, {5.0, 3.70},
|
||||
{6.0, 5.10}, {7.0, 7.40}, // Adrian has '5.4', but '7.4' looks better.
|
||||
};
|
||||
|
||||
static const int ncbvals = sizeof cbvals / sizeof cbvals[0];
|
||||
|
||||
// We interpolate the CB values for uniform random SAT formula to the non
|
||||
// integer situation of average clause size by piecewise linear functions.
|
||||
//
|
||||
// y2 - y1
|
||||
// ------- * (x - x1) + y1
|
||||
// x2 - x1
|
||||
//
|
||||
// where 'x' is the average size of clauses and 'y' the CB value.
|
||||
|
||||
inline static double fitcbval (double size) {
|
||||
int i = 0;
|
||||
while (i + 2 < ncbvals &&
|
||||
(cbvals[i][0] > size || cbvals[i + 1][0] < size))
|
||||
i++;
|
||||
const double x2 = cbvals[i + 1][0], x1 = cbvals[i][0];
|
||||
const double y2 = cbvals[i + 1][1], y1 = cbvals[i][1];
|
||||
const double dx = x2 - x1, dy = y2 - y1;
|
||||
CADICAL_assert (dx);
|
||||
const double res = dy * (size - x1) / dx + y1;
|
||||
CADICAL_assert (res > 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Initialize the data structures for one local search round.
|
||||
|
||||
WalkerFO::WalkerFO (Internal *i, double size, int64_t l)
|
||||
: internal (i), random (internal->opts.seed), // global random seed
|
||||
ticks (0), limit (l), best_trail_pos (-1) {
|
||||
random += internal->stats.walk.count; // different seed every time
|
||||
flips.reserve (i->max_var / 4);
|
||||
best_values.resize (i->max_var + 1, 0);
|
||||
tcounters.resize (i->max_var * 2 + 2);
|
||||
|
||||
// This is the magic constant in ProbSAT (also called 'CB'), which we pick
|
||||
// according to the average size every second invocation and otherwise
|
||||
// just the default '2.0', which turns into the base '0.5'.
|
||||
//
|
||||
const bool use_size_based_cb = (internal->stats.walk.count & 1);
|
||||
const double cb = use_size_based_cb ? fitcbval (size) : 2.0;
|
||||
CADICAL_assert (cb);
|
||||
const double base = 1 / cb; // scores are 'base^0,base^1,base^2,...
|
||||
|
||||
double next = 1;
|
||||
for (epsilon = next; next; next = epsilon * base)
|
||||
table.push_back (epsilon = next);
|
||||
|
||||
PHASE ("walk", internal->stats.walk.count,
|
||||
"CB %.2f with inverse %.2f as base and table size %zd", cb, base,
|
||||
table.size ());
|
||||
}
|
||||
|
||||
// Add the literal to flip to the queue
|
||||
|
||||
void WalkerFO::push_flipped (int flipped) {
|
||||
LOG ("push literal %s on the flips", LOGLIT (flipped));
|
||||
CADICAL_assert (flipped);
|
||||
if (best_trail_pos < 0) {
|
||||
LOG ("not pushing flipped %s to already invalid trail",
|
||||
LOGLIT (flipped));
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t size_trail = flips.size ();
|
||||
const size_t limit = internal->max_var / 4 + 1;
|
||||
if (size_trail < limit) {
|
||||
flips.push_back (flipped);
|
||||
LOG ("pushed flipped %s to trail which now has size %zd",
|
||||
LOGLIT (flipped), size_trail + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (best_trail_pos) {
|
||||
LOG ("trail reached limit %zd but has best position %d", limit,
|
||||
best_trail_pos);
|
||||
save_walker_trail (true);
|
||||
flips.push_back (flipped);
|
||||
LOG ("pushed flipped %s to trail which now has size %zu",
|
||||
LOGLIT (flipped), flips.size ());
|
||||
return;
|
||||
} else {
|
||||
LOG ("trail reached limit %zd without best position", limit);
|
||||
flips.clear ();
|
||||
LOG ("not pushing %s to invalidated trail", LOGLIT (flipped));
|
||||
best_trail_pos = -1;
|
||||
LOG ("best trail position becomes invalid");
|
||||
}
|
||||
}
|
||||
|
||||
void WalkerFO::save_walker_trail (bool keep) {
|
||||
CADICAL_assert (best_trail_pos != -1);
|
||||
CADICAL_assert ((size_t) best_trail_pos <= flips.size ());
|
||||
#ifdef LOGGING
|
||||
const size_t size_trail = flips.size ();
|
||||
#endif
|
||||
const int kept = flips.size () - best_trail_pos;
|
||||
LOG ("saving %d values of flipped literals on trail of size %zd",
|
||||
best_trail_pos, size_trail);
|
||||
|
||||
const auto begin = flips.begin ();
|
||||
const auto best = flips.begin () + best_trail_pos;
|
||||
const auto end = flips.end ();
|
||||
|
||||
auto it = begin;
|
||||
for (; it != best; ++it) {
|
||||
const int lit = *it;
|
||||
CADICAL_assert (lit);
|
||||
const signed char value = sign (lit);
|
||||
const int idx = std::abs (lit);
|
||||
best_values[idx] = value;
|
||||
}
|
||||
if (!keep) {
|
||||
LOG ("no need to shift and keep remaining %u literals", kept);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto v : internal->vars) {
|
||||
if (internal->active (v))
|
||||
CADICAL_assert (best_values[v] == internal->phases.saved[v]);
|
||||
}
|
||||
#endif
|
||||
LOG ("flushed %u literals %.0f%% from trail", best_trail_pos,
|
||||
percent (best_trail_pos, size_trail));
|
||||
CADICAL_assert (it == best);
|
||||
auto jt = begin;
|
||||
for (; it != end; ++it, ++jt) {
|
||||
CADICAL_assert (jt <= it);
|
||||
CADICAL_assert (it < end);
|
||||
*jt = *it;
|
||||
}
|
||||
|
||||
CADICAL_assert ((int) (end - jt) == best_trail_pos);
|
||||
CADICAL_assert ((int) (jt - begin) == kept);
|
||||
flips.resize (kept);
|
||||
LOG ("keeping %u literals %.0f%% on trail", kept,
|
||||
percent (kept, size_trail));
|
||||
LOG ("reset best trail position to 0");
|
||||
best_trail_pos = 0;
|
||||
}
|
||||
|
||||
// finally export_ the final minimum
|
||||
void WalkerFO::save_final_minimum (int64_t old_init_minimum) {
|
||||
CADICAL_assert (minimum <= old_init_minimum);
|
||||
#ifdef CADICAL_NDEBUG
|
||||
(void) old_init_minimum;
|
||||
#endif
|
||||
|
||||
if (!best_trail_pos || best_trail_pos == -1)
|
||||
LOG ("minimum already saved");
|
||||
else
|
||||
save_walker_trail (false);
|
||||
|
||||
++internal->stats.walk.improved;
|
||||
for (auto v : internal->vars) {
|
||||
if (best_values[v])
|
||||
internal->phases.saved[v] = best_values[v];
|
||||
else
|
||||
CADICAL_assert (!internal->active (v));
|
||||
}
|
||||
internal->copy_phases (internal->phases.prev);
|
||||
}
|
||||
// The scores are tabulated for faster computation (to avoid 'pow').
|
||||
|
||||
inline double WalkerFO::score (unsigned i) {
|
||||
const double res = (i < table.size () ? table[i] : epsilon);
|
||||
LOG ("break %u mapped to score %g", i, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
unsigned WalkerFO::walk_full_occs_pick_clause () {
|
||||
internal->require_mode (internal->WALK);
|
||||
CADICAL_assert (!broken.empty ());
|
||||
int64_t size = broken.size ();
|
||||
if (size > INT_MAX)
|
||||
size = INT_MAX;
|
||||
int pos = random.pick_int (0, size - 1);
|
||||
unsigned res = broken[pos].counter_pos;
|
||||
LOG (tclauses[res].clause, "picking random position %d", pos);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Compute the number of clauses which would be become unsatisfied if 'lit'
|
||||
// is flipped and set to false. This is called the 'break-count' of 'lit'.
|
||||
|
||||
unsigned WalkerFO::walk_full_occs_break_value (int lit) {
|
||||
|
||||
internal->require_mode (internal->WALK);
|
||||
CADICAL_assert (internal->val (lit) > 0);
|
||||
START (walkbreak);
|
||||
|
||||
const uint64_t old = ticks;
|
||||
unsigned res = 0; // The computed break-count of 'lit'.
|
||||
ticks +=
|
||||
(1 + internal->cache_lines (occs (lit).size (), sizeof (Clause *)));
|
||||
|
||||
for (const auto &w : occs (lit)) {
|
||||
const unsigned ref = w.counter_pos;
|
||||
CADICAL_assert (ref < tclauses.size ());
|
||||
res += (tclauses[ref].count == 1);
|
||||
}
|
||||
|
||||
internal->stats.ticks.walkbreak += ticks - old;
|
||||
STOP (walkbreak);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Given an unsatisfied clause 'c', in which we want to flip a literal, we
|
||||
// first determine the exponential score based on the break-count of its
|
||||
// literals and then sample the literals based on these scores. The CB
|
||||
// value is smaller than one and thus the score is exponentially decreasing
|
||||
// with the break-count increasing. The sampling works as in 'ProbSAT' and
|
||||
// 'YalSAT' by summing up the scores and then picking a random limit in the
|
||||
// range of zero to the sum, then summing up the scores again and picking
|
||||
// the first literal which reaches the limit. Note, that during incremental
|
||||
// SAT solving we can not flip assumed variables. Those are assigned at
|
||||
// decision level one, while the other variables are assigned at two.
|
||||
|
||||
int WalkerFO::walk_full_occs_pick_lit (Clause *c) {
|
||||
START (walkpick);
|
||||
LOG ("picking literal by break-count");
|
||||
CADICAL_assert (scores.empty ());
|
||||
const int64_t old = ++ticks;
|
||||
double sum = 0;
|
||||
int64_t propagations = 0;
|
||||
for (const auto lit : *c) {
|
||||
CADICAL_assert (internal->active (lit));
|
||||
if (internal->var (lit).level == 1) {
|
||||
LOG ("skipping assumption %d for scoring", -lit);
|
||||
continue;
|
||||
}
|
||||
propagations++;
|
||||
unsigned tmp = walk_full_occs_break_value (-lit);
|
||||
double score = this->score (tmp);
|
||||
LOG ("literal %d break-count %u score %g", lit, tmp, score);
|
||||
scores.push_back (score);
|
||||
sum += score;
|
||||
}
|
||||
(void) propagations; // TODO unused?
|
||||
LOG ("scored %zd literals", scores.size ());
|
||||
CADICAL_assert (!scores.empty ());
|
||||
CADICAL_assert (this->scores.size () <= (size_t) c->size);
|
||||
const double lim = sum * random.generate_double ();
|
||||
LOG ("score sum %g limit %g", sum, lim);
|
||||
|
||||
const auto end = c->end ();
|
||||
auto i = c->begin ();
|
||||
auto j = scores.begin ();
|
||||
int res;
|
||||
for (;;) {
|
||||
CADICAL_assert (i != end);
|
||||
res = *i++;
|
||||
if (internal->var (res).level > 1)
|
||||
break;
|
||||
LOG ("skipping assumption %d without score", -res);
|
||||
}
|
||||
sum = *j++;
|
||||
while (sum <= lim && i != end) {
|
||||
res = *i++;
|
||||
if (internal->var (res).level == 1) {
|
||||
LOG ("skipping assumption %d without score", -res);
|
||||
continue;
|
||||
}
|
||||
sum += *j++;
|
||||
}
|
||||
scores.clear ();
|
||||
LOG ("picking literal %d by break-count", res);
|
||||
internal->stats.ticks.walkpick += ticks - old;
|
||||
STOP (walkpick);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
void WalkerFO::make_clause (Tagged t) {
|
||||
CADICAL_assert (t.counter_pos < tclauses.size ());
|
||||
// TODO invalidate position in 'unsatisfied'
|
||||
auto count = tclauses[t.counter_pos].count++;
|
||||
if (count) {
|
||||
LOG (tclauses[t.counter_pos].clause,
|
||||
"already made with counter %d at position %d",
|
||||
tclauses[t.counter_pos].count, tclauses[t.counter_pos].pos);
|
||||
CADICAL_assert (tclauses[t.counter_pos].clause == t.c);
|
||||
CADICAL_assert (tclauses[t.counter_pos].pos == WalkerFO::invalid_position);
|
||||
return;
|
||||
}
|
||||
LOG (tclauses[t.counter_pos].clause,
|
||||
"make with counter %d at position %d", tclauses[t.counter_pos].count,
|
||||
tclauses[t.counter_pos].pos);
|
||||
CADICAL_assert (tclauses[t.counter_pos].pos != WalkerFO::invalid_position);
|
||||
CADICAL_assert (tclauses[t.counter_pos].pos < broken.size ());
|
||||
++ticks;
|
||||
auto last = broken.back ();
|
||||
#ifndef CADICAL_NDEBUG
|
||||
CADICAL_assert (tclauses[t.counter_pos].clause == t.c);
|
||||
CADICAL_assert (last.counter_pos < tclauses.size ());
|
||||
CADICAL_assert (tclauses[last.counter_pos].clause == last.c);
|
||||
#endif
|
||||
unsigned pos = tclauses[t.counter_pos].pos;
|
||||
CADICAL_assert (pos < broken.size ());
|
||||
broken[pos] = last;
|
||||
// the order is important
|
||||
tclauses[last.counter_pos].pos = pos;
|
||||
tclauses[t.counter_pos].pos = WalkerFO::invalid_position;
|
||||
broken.pop_back ();
|
||||
}
|
||||
|
||||
void WalkerFO::make_clauses_along_occurrences (int lit) {
|
||||
const auto &occs = this->occs (lit);
|
||||
LOG ("making clauses with %s along %zu occurrences", LOGLIT (lit),
|
||||
occs.size ());
|
||||
CADICAL_assert (internal->val (lit) > 0);
|
||||
size_t made = 0;
|
||||
ticks += (1 + internal->cache_lines (occs.size (), sizeof (Clause *)));
|
||||
|
||||
for (auto c : occs) {
|
||||
#if 0
|
||||
// only works if make is after break... but we don't want that
|
||||
if (broken.empty()) {
|
||||
LOG ("early abort: satisfiable!");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
this->make_clause (c);
|
||||
made++;
|
||||
}
|
||||
LOG ("made %zu clauses by flipping %d, still %zu broken", made, lit,
|
||||
broken.size ());
|
||||
LOG ("made %zu clauses with flipped %s", made, LOGLIT (lit));
|
||||
(void) made;
|
||||
}
|
||||
|
||||
void WalkerFO::make_clauses_along_unsatisfied (int lit) {
|
||||
LOG ("making clauses with %s along %zu unsatisfied", LOGLIT (lit),
|
||||
this->broken.size ());
|
||||
CADICAL_assert (internal->val (lit) > 0);
|
||||
size_t made = 0;
|
||||
// TODO flush made clauses from 'unsatisfied' directly.
|
||||
// TODO 'stats.make_visited++', 'made++' appropriately.
|
||||
size_t j = 0;
|
||||
const size_t size = this->broken.size ();
|
||||
ticks +=
|
||||
(1 + internal->cache_lines (this->broken.size (), sizeof (Clause *)));
|
||||
for (size_t i = 0, j = 0; i < size; ++i) {
|
||||
CADICAL_assert (i >= j);
|
||||
const auto &c = this->broken[i];
|
||||
Counter &d = this->tclauses[c.counter_pos];
|
||||
this->broken[j++] = this->broken[i];
|
||||
CADICAL_assert (d.pos != WalkerFO::invalid_position);
|
||||
for (auto other : *d.clause) {
|
||||
if (lit == other) {
|
||||
++made;
|
||||
--j;
|
||||
++d.count;
|
||||
LOG (d.clause, "made with count %d", d.count);
|
||||
d.pos = WalkerFO::invalid_position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (d.pos != WalkerFO::invalid_position)
|
||||
LOG (d.clause, "still broken");
|
||||
CADICAL_assert (made + j == i + 1); // assertions holds after incrementing 'i'
|
||||
}
|
||||
CADICAL_assert (j <= size);
|
||||
this->broken.resize (j);
|
||||
LOG ("made %zu clauses with flipped %s", made, LOGLIT (lit));
|
||||
(void) made;
|
||||
}
|
||||
|
||||
void WalkerFO::make_clauses (int lit) {
|
||||
START (walkflipWL);
|
||||
const int64_t old = ticks;
|
||||
// In babywalk this work because there are not counter
|
||||
// if (this->occs(lit).size() > broken.size())
|
||||
// make_clauses_along_unsatisfied(lit);
|
||||
// else
|
||||
make_clauses_along_occurrences (lit);
|
||||
internal->stats.ticks.walkflipWL += ticks - old;
|
||||
STOP (walkflipWL);
|
||||
}
|
||||
|
||||
void WalkerFO::break_clauses (int lit) {
|
||||
START (walkflipbroken);
|
||||
const int64_t old = ticks;
|
||||
LOG ("breaking clauses on %s", LOGLIT (lit));
|
||||
// Finally add all new unsatisfied (broken) clauses.
|
||||
|
||||
#ifdef LOGGING
|
||||
int64_t broken = 0;
|
||||
#endif
|
||||
const WalkerFO::TOccs &ws = occs (lit);
|
||||
ticks += (1 + internal->cache_lines (ws.size (), sizeof (Clause *)));
|
||||
|
||||
LOG ("trying to break %zd clauses", ws.size ());
|
||||
|
||||
for (const auto &w : ws) {
|
||||
unsigned pos = w.counter_pos;
|
||||
Counter &d = tclauses[pos];
|
||||
#ifndef CADICAL_NDEBUG
|
||||
LOG (d.clause, "trying to break");
|
||||
#endif
|
||||
if (--d.count)
|
||||
continue;
|
||||
d.pos = this->broken.size ();
|
||||
++ticks;
|
||||
this->broken.push_back (w);
|
||||
#ifdef LOGGING
|
||||
broken++;
|
||||
#endif
|
||||
}
|
||||
LOG ("broken %" PRId64 " clauses by flipping %d", broken, lit);
|
||||
internal->stats.ticks.walkflipbroken += ticks - old;
|
||||
STOP (walkflipbroken);
|
||||
}
|
||||
|
||||
void WalkerFO::walk_full_occs_flip_lit (int lit) {
|
||||
|
||||
internal->require_mode (internal->WALK);
|
||||
LOG ("flipping assign %d", lit);
|
||||
CADICAL_assert (internal->val (lit) < 0);
|
||||
const int64_t old = ticks;
|
||||
|
||||
// First flip the literal value.
|
||||
//
|
||||
const int tmp = sign (lit);
|
||||
const int idx = abs (lit);
|
||||
internal->set_val (idx, tmp);
|
||||
CADICAL_assert (internal->val (lit) > 0);
|
||||
|
||||
make_clauses (lit);
|
||||
break_clauses (-lit);
|
||||
|
||||
if (!broken.empty ())
|
||||
check_all ();
|
||||
internal->stats.ticks.walkflip += ticks - old;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
// Check whether to save the current phases as new global minimum.
|
||||
|
||||
inline void Internal::walk_full_occs_save_minimum (WalkerFO &walker) {
|
||||
int64_t broken = walker.broken.size ();
|
||||
if (broken >= walker.minimum)
|
||||
return;
|
||||
if (broken <= stats.walk.minimum) {
|
||||
stats.walk.minimum = broken;
|
||||
VERBOSE (3, "new global minimum %" PRId64 "", broken);
|
||||
} else {
|
||||
VERBOSE (3, "new walk minimum %" PRId64 "", broken);
|
||||
}
|
||||
|
||||
walker.minimum = broken;
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto i : vars) {
|
||||
const signed char tmp = vals[i];
|
||||
if (tmp)
|
||||
phases.saved[i] = tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (walker.best_trail_pos == -1) {
|
||||
for (auto i : vars) {
|
||||
const signed char tmp = vals[i];
|
||||
if (tmp) {
|
||||
walker.best_values[i] = tmp;
|
||||
#ifndef CADICAL_NDEBUG
|
||||
CADICAL_assert (tmp == phases.saved[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
walker.best_trail_pos = 0;
|
||||
} else {
|
||||
walker.best_trail_pos = walker.flips.size ();
|
||||
LOG ("new best trail position %u", walker.best_trail_pos);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
int Internal::walk_full_occs_round (int64_t limit, bool prev) {
|
||||
|
||||
stats.walk.count++;
|
||||
|
||||
reset_watches ();
|
||||
|
||||
// Remove all fixed variables first (assigned at decision level zero).
|
||||
//
|
||||
if (last.collect.fixed < stats.all.fixed)
|
||||
garbage_collection ();
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
// We want to see more messages during initial local search.
|
||||
//
|
||||
if (localsearching) {
|
||||
CADICAL_assert (!force_phase_messages);
|
||||
force_phase_messages = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"random walk limit of %" PRId64 " propagations", limit);
|
||||
|
||||
// First compute the average clause size for picking the CB constant.
|
||||
//
|
||||
double size = 0;
|
||||
int64_t n = 0;
|
||||
for (const auto c : clauses) {
|
||||
if (c->garbage)
|
||||
continue;
|
||||
if (c->redundant) {
|
||||
if (!opts.walkredundant)
|
||||
continue;
|
||||
if (!likely_to_be_kept_clause (c))
|
||||
continue;
|
||||
}
|
||||
size += c->size;
|
||||
n++;
|
||||
}
|
||||
double average_size = relative (size, n);
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"%" PRId64 " clauses average size %.2f over %d variables", n,
|
||||
average_size, active ());
|
||||
|
||||
// Instantiate data structures for this local search round.
|
||||
//
|
||||
WalkerFO walker (internal, average_size, limit);
|
||||
|
||||
bool failed = false; // Inconsistent assumptions?
|
||||
|
||||
level = 1; // Assumed variables assigned at level 1.
|
||||
|
||||
if (assumptions.empty ()) {
|
||||
LOG ("no assumptions so assigning all variables to decision phase");
|
||||
} else {
|
||||
LOG ("assigning assumptions to their forced phase first");
|
||||
for (const auto lit : assumptions) {
|
||||
signed char tmp = val (lit);
|
||||
if (tmp > 0)
|
||||
continue;
|
||||
if (tmp < 0) {
|
||||
LOG ("inconsistent assumption %d", lit);
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
if (!active (lit))
|
||||
continue;
|
||||
tmp = sign (lit);
|
||||
const int idx = abs (lit);
|
||||
LOG ("initial assign %d to assumption phase", tmp < 0 ? -idx : idx);
|
||||
set_val (idx, tmp);
|
||||
CADICAL_assert (level == 1);
|
||||
var (idx).level = 1;
|
||||
}
|
||||
if (!failed)
|
||||
LOG ("now assigning remaining variables to their decision phase");
|
||||
}
|
||||
|
||||
level = 2; // All other non assumed variables assigned at level 2.
|
||||
|
||||
if (!failed) {
|
||||
|
||||
const bool target = opts.warmup ? false : stable || opts.target == 2;
|
||||
for (auto idx : vars) {
|
||||
if (!active (idx)) {
|
||||
LOG ("skipping inactive variable %d", idx);
|
||||
continue;
|
||||
}
|
||||
if (vals[idx]) {
|
||||
CADICAL_assert (var (idx).level == 1);
|
||||
LOG ("skipping assumed variable %d", idx);
|
||||
continue;
|
||||
}
|
||||
int tmp = 0;
|
||||
if (prev)
|
||||
tmp = phases.prev[idx];
|
||||
if (!tmp)
|
||||
tmp = sign (decide_phase (idx, target));
|
||||
CADICAL_assert (tmp == 1 || tmp == -1);
|
||||
set_val (idx, tmp);
|
||||
CADICAL_assert (level == 2);
|
||||
var (idx).level = 2;
|
||||
walker.best_values[idx] = tmp;
|
||||
LOG ("initial assign %d to decision phase", tmp < 0 ? -idx : idx);
|
||||
}
|
||||
|
||||
LOG ("watching satisfied and registering broken clauses");
|
||||
#ifdef LOGGING
|
||||
int64_t watched = 0;
|
||||
#endif
|
||||
for (const auto c : clauses) {
|
||||
|
||||
if (c->garbage)
|
||||
continue;
|
||||
if (c->redundant) {
|
||||
if (!opts.walkredundant)
|
||||
continue;
|
||||
if (!likely_to_be_kept_clause (c))
|
||||
continue;
|
||||
}
|
||||
|
||||
bool satisfiable = false; // contains not only assumptions
|
||||
int satisfied = 0; // clause satisfied?
|
||||
|
||||
int *lits = c->literals;
|
||||
const int size = c->size;
|
||||
|
||||
// Move to front satisfied literals and determine whether there
|
||||
// is at least one (non-assumed) literal that can be flipped.
|
||||
//
|
||||
for (int i = 0; i < size; i++) {
|
||||
const int lit = lits[i];
|
||||
CADICAL_assert (active (lit)); // Due to garbage collection.
|
||||
if (val (lit) > 0) {
|
||||
swap (lits[satisfied], lits[i]);
|
||||
if (!satisfied++)
|
||||
LOG ("first satisfying literal %d", lit);
|
||||
} else if (!satisfiable && var (lit).level > 1) {
|
||||
LOG ("non-assumption potentially satisfying literal %d", lit);
|
||||
satisfiable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!satisfied && !satisfiable) {
|
||||
LOG (c, "due to assumptions unsatisfiable");
|
||||
LOG ("stopping local search since assumptions falsify a clause");
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned pos = walker.tclauses.size ();
|
||||
walker.tclauses.push_back (Counter (satisfied, c));
|
||||
walker.connect_clause (c, pos);
|
||||
|
||||
if (!satisfied) {
|
||||
CADICAL_assert (satisfiable); // at least one non-assumed variable ...
|
||||
LOG (c, "broken");
|
||||
walker.tclauses[pos].pos = walker.broken.size ();
|
||||
walker.broken.push_back (Tagged (c, pos));
|
||||
} else {
|
||||
#ifdef LOGGING
|
||||
watched++; // to be able to compare the number with walk
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef LOGGING
|
||||
if (!failed) {
|
||||
int64_t broken = walker.broken.size ();
|
||||
int64_t total = watched + broken;
|
||||
MSG ("watching %" PRId64 " clauses %.0f%% "
|
||||
"out of %" PRId64 " (watched and broken)",
|
||||
watched, percent (watched, total), total);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
walker.check_all ();
|
||||
int res; // Tells caller to continue with local search.
|
||||
|
||||
if (!failed) {
|
||||
|
||||
int64_t broken = walker.broken.size ();
|
||||
int64_t initial_minimum = broken;
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"starting with %" PRId64 " unsatisfied clauses "
|
||||
"(%.0f%% out of %" PRId64 ")",
|
||||
broken, percent (broken, stats.current.irredundant),
|
||||
stats.current.irredundant);
|
||||
|
||||
walk_full_occs_save_minimum (walker);
|
||||
CADICAL_assert (stats.walk.minimum <= walker.minimum);
|
||||
|
||||
int64_t minimum = broken;
|
||||
#ifndef CADICAL_QUIET
|
||||
int64_t flips = 0;
|
||||
#endif
|
||||
while (!terminated_asynchronously () && !walker.broken.empty () &&
|
||||
walker.ticks < walker.limit) {
|
||||
#ifndef CADICAL_QUIET
|
||||
flips++;
|
||||
#endif
|
||||
stats.walk.flips++;
|
||||
stats.walk.broken += broken;
|
||||
unsigned pos = walker.walk_full_occs_pick_clause ();
|
||||
Clause *c = walker.tclauses[pos].clause;
|
||||
const int lit = walker.walk_full_occs_pick_lit (c);
|
||||
walker.walk_full_occs_flip_lit (lit);
|
||||
walker.push_flipped (lit);
|
||||
broken = walker.broken.size ();
|
||||
LOG ("now have %" PRId64 " broken clauses in total", broken);
|
||||
if (broken >= minimum)
|
||||
continue;
|
||||
minimum = broken;
|
||||
VERBOSE (3, "new phase minimum %" PRId64 " after %" PRId64 " flips",
|
||||
minimum, flips);
|
||||
walk_full_occs_save_minimum (walker);
|
||||
}
|
||||
|
||||
walker.save_final_minimum (initial_minimum);
|
||||
#ifndef CADICAL_QUIET
|
||||
if (minimum == initial_minimum) {
|
||||
PHASE ("walk", internal->stats.walk.count,
|
||||
"%sno improvement %" PRId64 "%s in %" PRId64 " flips and "
|
||||
"%" PRId64 " ticks",
|
||||
tout.bright_yellow_code (), minimum, tout.normal_code (),
|
||||
flips, walker.ticks);
|
||||
} else {
|
||||
PHASE ("walk", internal->stats.walk.count,
|
||||
"best phase minimum %" PRId64 " in %" PRId64 " flips and "
|
||||
"%" PRId64 " ticks",
|
||||
minimum, flips, walker.ticks);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts.profile >= 2) {
|
||||
PHASE ("walk", stats.walk.count, "%.2f million ticks per second",
|
||||
1e-6 *
|
||||
relative (walker.ticks, time () - profiles.walk.started));
|
||||
|
||||
PHASE ("walk", stats.walk.count, "%.2f thousand flips per second",
|
||||
relative (1e-3 * flips, time () - profiles.walk.started));
|
||||
|
||||
} else {
|
||||
PHASE ("walk", stats.walk.count, "%.2f ticks", 1e-6 * walker.ticks);
|
||||
|
||||
PHASE ("walk", stats.walk.count, "%.2f thousand flips", 1e-3 * flips);
|
||||
}
|
||||
|
||||
if (minimum > 0) {
|
||||
LOG ("minimum %" PRId64 " non-zero thus potentially continue",
|
||||
minimum);
|
||||
res = 0;
|
||||
} else {
|
||||
LOG ("minimum is zero thus stop local search");
|
||||
res = 10;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
res = 20;
|
||||
|
||||
PHASE ("walk", stats.walk.count,
|
||||
"aborted due to inconsistent assumptions");
|
||||
}
|
||||
|
||||
for (auto idx : vars)
|
||||
if (active (idx))
|
||||
set_val (idx, 0);
|
||||
|
||||
CADICAL_assert (level == 2);
|
||||
level = 0;
|
||||
|
||||
init_watches ();
|
||||
connect_watches ();
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
if (localsearching) {
|
||||
CADICAL_assert (force_phase_messages);
|
||||
force_phase_messages = false;
|
||||
}
|
||||
#endif
|
||||
stats.ticks.walk += walker.ticks;
|
||||
return res;
|
||||
}
|
||||
|
||||
void Internal::walk_full_occs () {
|
||||
START_INNER_WALK ();
|
||||
|
||||
backtrack ();
|
||||
if (propagated < trail.size () && !propagate ()) {
|
||||
LOG ("empty clause after root level propagation");
|
||||
learn_empty_clause ();
|
||||
STOP_INNER_WALK ();
|
||||
return;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
if (opts.warmup)
|
||||
res = warmup ();
|
||||
if (res) {
|
||||
LOG ("stopping walk due to warmup");
|
||||
STOP_INNER_WALK ();
|
||||
return;
|
||||
}
|
||||
const int64_t ticks = stats.ticks.search[0] + stats.ticks.search[1];
|
||||
int64_t limit = ticks - last.walk.ticks;
|
||||
VERBOSE (2,
|
||||
"walk scheduling: last %" PRId64 " current %" PRId64
|
||||
" delta %" PRId64,
|
||||
last.walk.ticks, ticks, limit);
|
||||
last.walk.ticks = ticks;
|
||||
limit *= 1e-3 * opts.walkeffort;
|
||||
if (limit < opts.walkmineff)
|
||||
limit = opts.walkmineff;
|
||||
// local search is very cache friendly, so we actually really go over a
|
||||
// lot of ticks
|
||||
if (limit > 1e3 * opts.walkmaxeff) {
|
||||
MSG ("reached maximum efficiency %" PRId64, limit);
|
||||
limit = 1e3 * opts.walkmaxeff;
|
||||
}
|
||||
(void) walk_full_occs_round (limit, false);
|
||||
STOP_INNER_WALK ();
|
||||
CADICAL_assert (!unsat);
|
||||
}
|
||||
|
||||
} // namespace CaDiCaL
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -0,0 +1,404 @@
|
|||
#include "global.h"
|
||||
|
||||
#include "internal.hpp"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
namespace CaDiCaL {
|
||||
|
||||
// The idea of warmup is to reuse the strength of CDCL, namely
|
||||
// propagating, before calling random walk that is not good at
|
||||
// propagating long chains. Therefore, we propagate (ignoring all conflicts)
|
||||
// discovered along the way.
|
||||
// The asignmend is the same as the normal assignment however, it updates
|
||||
// the target phases so that local search can pick them up later
|
||||
|
||||
// specific warmup version with saving of the target.
|
||||
inline void Internal::warmup_assign (int lit, Clause *reason) {
|
||||
|
||||
CADICAL_assert (level); // no need to learn unit clauses here
|
||||
require_mode (SEARCH);
|
||||
|
||||
const int idx = vidx (lit);
|
||||
CADICAL_assert (reason != external_reason);
|
||||
CADICAL_assert (!vals[idx]);
|
||||
CADICAL_assert (!flags (idx).eliminated () || reason == decision_reason);
|
||||
CADICAL_assert (!searching_lucky_phases);
|
||||
CADICAL_assert (lrat_chain.empty ());
|
||||
Var &v = var (idx);
|
||||
int lit_level;
|
||||
CADICAL_assert (
|
||||
!(reason == external_reason &&
|
||||
((size_t) level <= assumptions.size () + (!!constraint.size ()))));
|
||||
CADICAL_assert (reason);
|
||||
CADICAL_assert (level || reason == decision_reason);
|
||||
// we purely assign in order here
|
||||
lit_level = level;
|
||||
|
||||
v.level = lit_level;
|
||||
v.trail = trail.size ();
|
||||
v.reason = reason;
|
||||
CADICAL_assert ((int) num_assigned < max_var);
|
||||
CADICAL_assert (num_assigned == trail.size ());
|
||||
num_assigned++;
|
||||
const signed char tmp = sign (lit);
|
||||
phases.saved[idx] = tmp;
|
||||
set_val (idx, tmp);
|
||||
CADICAL_assert (val (lit) > 0);
|
||||
CADICAL_assert (val (-lit) < 0);
|
||||
|
||||
trail.push_back (lit);
|
||||
#ifdef LOGGING
|
||||
if (!lit_level)
|
||||
LOG ("root-level unit assign %d @ 0", lit);
|
||||
else
|
||||
LOG (reason, "search assign %d @ %d", lit, lit_level);
|
||||
#endif
|
||||
|
||||
CADICAL_assert (watching ());
|
||||
const Watches &ws = watches (-lit);
|
||||
if (!ws.empty ()) {
|
||||
const Watch &w = ws[0];
|
||||
#ifndef WIN32
|
||||
__builtin_prefetch (&w, 0, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Internal::warmup_propagate_beyond_conflict () {
|
||||
|
||||
CADICAL_assert (!unsat);
|
||||
|
||||
START (propagate);
|
||||
CADICAL_assert (!ignore);
|
||||
|
||||
int64_t before = propagated;
|
||||
|
||||
while (propagated != trail.size ()) {
|
||||
|
||||
const int lit = -trail[propagated++];
|
||||
LOG ("propagating %d", -lit);
|
||||
Watches &ws = watches (lit);
|
||||
|
||||
const const_watch_iterator eow = ws.end ();
|
||||
watch_iterator j = ws.begin ();
|
||||
const_watch_iterator i = j;
|
||||
|
||||
while (i != eow) {
|
||||
|
||||
const Watch w = *j++ = *i++;
|
||||
const signed char b = val (w.blit);
|
||||
|
||||
if (b > 0)
|
||||
continue; // blocking literal satisfied
|
||||
|
||||
if (w.binary ()) {
|
||||
|
||||
// In principle we can ignore garbage binary clauses too, but that
|
||||
// would require to dereference the clause pointer all the time with
|
||||
//
|
||||
// if (w.clause->garbage) { j--; continue; } // (*)
|
||||
//
|
||||
// This is too costly. It is however necessary to produce correct
|
||||
// proof traces if binary clauses are traced to be deleted ('d ...'
|
||||
// line) immediately as soon they are marked as garbage. Actually
|
||||
// finding instances where this happens is pretty difficult (six
|
||||
// parallel fuzzing jobs in parallel took an hour), but it does
|
||||
// occur. Our strategy to avoid generating incorrect proofs now is
|
||||
// to delay tracing the deletion of binary clauses marked as garbage
|
||||
// until they are really deleted from memory. For large clauses
|
||||
// this is not necessary since we have to access the clause anyhow.
|
||||
//
|
||||
// Thanks go to Mathias Fleury, who wanted me to explain why the
|
||||
// line '(*)' above was in the code. Removing it actually really
|
||||
// improved running times and thus I tried to find concrete
|
||||
// instances where this happens (which I found), and then
|
||||
// implemented the described fix.
|
||||
|
||||
// Binary clauses are treated separately since they do not require
|
||||
// to access the clause at all (only during conflict analysis, and
|
||||
// there also only to simplify the code).
|
||||
|
||||
if (b < 0)
|
||||
// ignoring conflict
|
||||
++stats.warmup.conflicts;
|
||||
else {
|
||||
warmup_assign (w.blit, w.clause);
|
||||
}
|
||||
|
||||
} else {
|
||||
CADICAL_assert (w.clause->size > 2);
|
||||
|
||||
// The cache line with the clause data is forced to be loaded here
|
||||
// and thus this first memory access below is the real hot-spot of
|
||||
// the solver. Note, that this check is positive very rarely and
|
||||
// thus branch prediction should be almost perfect here.
|
||||
|
||||
if (w.clause->garbage) {
|
||||
j--;
|
||||
continue;
|
||||
}
|
||||
literal_iterator lits = w.clause->begin ();
|
||||
const int other = lits[0] ^ lits[1] ^ lit;
|
||||
const signed char u = val (other);
|
||||
if (u > 0)
|
||||
j[-1].blit = other;
|
||||
else {
|
||||
const int size = w.clause->size;
|
||||
const const_literal_iterator end = lits + size;
|
||||
const literal_iterator middle = lits + w.clause->pos;
|
||||
literal_iterator k = middle;
|
||||
signed char v = -1;
|
||||
int r = 0;
|
||||
while (k != end && (v = val (r = *k)) < 0)
|
||||
k++;
|
||||
if (v < 0) {
|
||||
k = lits + 2;
|
||||
CADICAL_assert (w.clause->pos <= size);
|
||||
while (k != middle && (v = val (r = *k)) < 0)
|
||||
k++;
|
||||
}
|
||||
|
||||
w.clause->pos = k - lits; // always save position
|
||||
|
||||
CADICAL_assert (lits + 2 <= k), CADICAL_assert (k <= w.clause->end ());
|
||||
|
||||
if (v > 0) {
|
||||
|
||||
// Replacement satisfied, so just replace 'blit'.
|
||||
|
||||
j[-1].blit = r;
|
||||
|
||||
} else if (!v) {
|
||||
|
||||
// Found new unassigned replacement literal to be watched.
|
||||
|
||||
LOG (w.clause, "unwatch %d in", lit);
|
||||
|
||||
lits[0] = other;
|
||||
lits[1] = r;
|
||||
*k = lit;
|
||||
|
||||
watch_literal (r, lit, w.clause);
|
||||
|
||||
j--; // Drop this watch from the watch list of 'lit'.
|
||||
|
||||
} else if (!u) {
|
||||
|
||||
CADICAL_assert (v < 0);
|
||||
|
||||
// The other watch is unassigned ('!u') and all other literals
|
||||
// assigned to false (still 'v < 0'), thus we found a unit.
|
||||
//
|
||||
build_chain_for_units (other, w.clause, 0);
|
||||
warmup_assign (other, w.clause);
|
||||
} else {
|
||||
CADICAL_assert (u < 0);
|
||||
CADICAL_assert (v < 0);
|
||||
|
||||
// ignoring conflict
|
||||
++stats.warmup.conflicts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (j != i) {
|
||||
ws.resize (j - ws.begin ());
|
||||
}
|
||||
}
|
||||
|
||||
CADICAL_assert (propagated == trail.size ());
|
||||
|
||||
stats.warmup.propagated += (trail.size () - before);
|
||||
STOP (propagate);
|
||||
}
|
||||
|
||||
int Internal::warmup_decide () {
|
||||
CADICAL_assert (!satisfied ());
|
||||
START (decide);
|
||||
int res = 0;
|
||||
if ((size_t) level < assumptions.size ()) {
|
||||
const int lit = assumptions[level];
|
||||
CADICAL_assert (assumed (lit));
|
||||
const signed char tmp = val (lit);
|
||||
if (tmp < 0) {
|
||||
LOG ("assumption %d falsified", lit);
|
||||
res = 20;
|
||||
} else if (tmp > 0) {
|
||||
LOG ("assumption %d already satisfied", lit);
|
||||
new_trail_level (0);
|
||||
LOG ("added pseudo decision level");
|
||||
} else {
|
||||
LOG ("deciding assumption %d", lit);
|
||||
search_assume_decision (lit);
|
||||
}
|
||||
} else if ((size_t) level == assumptions.size () && constraint.size ()) {
|
||||
|
||||
int satisfied_lit = 0; // The literal satisfying the constrain.
|
||||
int unassigned_lit = 0; // Highest score unassigned literal.
|
||||
int previous_lit = 0; // Move satisfied literals to the front.
|
||||
|
||||
const size_t size_constraint = constraint.size ();
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
unsigned sum = 0;
|
||||
for (auto lit : constraint)
|
||||
sum += lit;
|
||||
#endif
|
||||
for (size_t i = 0; i != size_constraint; i++) {
|
||||
|
||||
// Get literal and move 'constraint[i] = constraint[i-1]'.
|
||||
|
||||
int lit = constraint[i];
|
||||
constraint[i] = previous_lit;
|
||||
previous_lit = lit;
|
||||
|
||||
const signed char tmp = val (lit);
|
||||
if (tmp < 0) {
|
||||
LOG ("constraint literal %d falsified", lit);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tmp > 0) {
|
||||
LOG ("constraint literal %d satisfied", lit);
|
||||
satisfied_lit = lit;
|
||||
break;
|
||||
}
|
||||
|
||||
CADICAL_assert (!tmp);
|
||||
LOG ("constraint literal %d unassigned", lit);
|
||||
|
||||
if (!unassigned_lit || better_decision (lit, unassigned_lit))
|
||||
unassigned_lit = lit;
|
||||
}
|
||||
|
||||
if (satisfied_lit) {
|
||||
|
||||
constraint[0] = satisfied_lit; // Move satisfied to the front.
|
||||
|
||||
LOG ("literal %d satisfies constraint and "
|
||||
"is implied by assumptions",
|
||||
satisfied_lit);
|
||||
|
||||
new_trail_level (0);
|
||||
LOG ("added pseudo decision level for constraint");
|
||||
notify_decision ();
|
||||
|
||||
} else {
|
||||
|
||||
// Just move all the literals back. If we found an unsatisfied
|
||||
// literal then it will be satisfied (most likely) at the next
|
||||
// decision and moved then to the first position.
|
||||
|
||||
if (size_constraint) {
|
||||
|
||||
for (size_t i = 0; i + 1 != size_constraint; i++)
|
||||
constraint[i] = constraint[i + 1];
|
||||
|
||||
constraint[size_constraint - 1] = previous_lit;
|
||||
}
|
||||
|
||||
if (unassigned_lit) {
|
||||
|
||||
LOG ("deciding %d to satisfy constraint", unassigned_lit);
|
||||
search_assume_decision (unassigned_lit);
|
||||
|
||||
} else {
|
||||
|
||||
LOG ("failing constraint");
|
||||
unsat_constraint = true;
|
||||
res = 20;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CADICAL_NDEBUG
|
||||
for (auto lit : constraint)
|
||||
sum -= lit;
|
||||
CADICAL_assert (!sum); // Checksum of literal should not change!
|
||||
#endif
|
||||
|
||||
} else {
|
||||
const bool target = (stable || opts.target == 2);
|
||||
stats.warmup.decision++;
|
||||
int idx = next_decision_variable ();
|
||||
if (flags (idx).eliminated ())
|
||||
++stats.warmup.dummydecision;
|
||||
int decision = decide_phase (idx, target);
|
||||
new_trail_level (decision);
|
||||
warmup_assign (decision, decision_reason);
|
||||
}
|
||||
if (res)
|
||||
marked_failed = false;
|
||||
STOP (decide);
|
||||
return res;
|
||||
}
|
||||
|
||||
int Internal::warmup () {
|
||||
CADICAL_assert (!unsat);
|
||||
CADICAL_assert (!level);
|
||||
if (!opts.warmup)
|
||||
return 0;
|
||||
require_mode (WALK);
|
||||
START (warmup);
|
||||
++stats.warmup.count;
|
||||
int res = 0;
|
||||
|
||||
#ifndef CADICAL_QUIET
|
||||
const int64_t warmup_propagated = stats.warmup.propagated;
|
||||
const int64_t decision = stats.warmup.decision;
|
||||
const int64_t dummydecision = stats.warmup.dummydecision;
|
||||
#endif
|
||||
// first propagate assumptions in case we find a conflict. One
|
||||
// subtle thing, if we find a conflict in the assumption, then we
|
||||
// actually do need the notifications. Otherwise, we there should be
|
||||
// no notification at all (not even the `backtrack ()` at the end).
|
||||
const size_t assms_contraint_level =
|
||||
assumptions.size () + !constraint.empty ();
|
||||
while (!res && (size_t) level < assms_contraint_level &&
|
||||
num_assigned < (size_t) max_var) {
|
||||
CADICAL_assert (num_assigned < (size_t) max_var);
|
||||
res = warmup_decide ();
|
||||
warmup_propagate_beyond_conflict ();
|
||||
}
|
||||
const bool no_backtrack_notification = (level == 0);
|
||||
|
||||
// now we do not need any notification and can simply propagate
|
||||
CADICAL_assert (propagated == trail.size ());
|
||||
CADICAL_assert (!private_steps);
|
||||
private_steps = true;
|
||||
|
||||
LOG ("propagating beyond conflicts to warm-up walk");
|
||||
while (!res && num_assigned < (size_t) max_var) {
|
||||
CADICAL_assert (propagated == trail.size ());
|
||||
res = warmup_decide ();
|
||||
warmup_propagate_beyond_conflict ();
|
||||
LOG (lrat_chain, "during warmup with lrat chain:");
|
||||
}
|
||||
CADICAL_assert (res || num_assigned == (size_t) max_var);
|
||||
#ifndef CADICAL_QUIET
|
||||
// constrains with empty levels break this
|
||||
// CADICAL_assert (res || stats.warmup.propagated - warmup_propagated ==
|
||||
// (int64_t)num_assigned);
|
||||
VERBOSE (3,
|
||||
"warming-up needed %" PRIu64 " propagations including %" PRIu64
|
||||
" decisions (with %" PRIu64 " dummy ones)",
|
||||
stats.warmup.propagated - warmup_propagated,
|
||||
stats.warmup.decision - decision,
|
||||
stats.warmup.dummydecision - dummydecision);
|
||||
#endif
|
||||
|
||||
// now we backtrack, notifying only if there was something to
|
||||
// notify.
|
||||
private_steps = no_backtrack_notification;
|
||||
if (!res)
|
||||
backtrack_without_updating_phases ();
|
||||
private_steps = false;
|
||||
STOP (warmup);
|
||||
require_mode (WALK);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace CaDiCaL
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
|
@ -52,11 +52,14 @@ int ccadical_frozen (CCaDiCaL *, int lit);
|
|||
void ccadical_melt (CCaDiCaL *, int lit);
|
||||
int ccadical_simplify (CCaDiCaL *);
|
||||
int ccadical_vars (CCaDiCaL *);
|
||||
int ccadical_reserve_difference (CCaDiCaL *, int number_of_vars);
|
||||
int ccadical_declare_more_variables (CCaDiCaL *, int number_of_vars);
|
||||
int ccadical_declare_one_more_variable (CCaDiCaL *);
|
||||
void ccadical_phase (CCaDiCaL *wrapper, int lit);
|
||||
void ccadical_unphase (CCaDiCaL *wrapper, int lit);
|
||||
|
||||
// Extra
|
||||
|
||||
void ccadical_reserve(CCaDiCaL *, int min_max_var);
|
||||
void ccadical_resize(CCaDiCaL *, int min_max_var);
|
||||
int ccadical_is_inconsistent(CCaDiCaL *);
|
||||
int ccadical_clauses(CCaDiCaL *);
|
||||
int ccadical_conflicts(CCaDiCaL *);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ struct CheckerWatch {
|
|||
: blit (b), size (c->size), clause (c) {}
|
||||
};
|
||||
|
||||
typedef vector<CheckerWatch> CheckerWatcher;
|
||||
typedef std::vector<CheckerWatch> CheckerWatcher;
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -69,8 +69,8 @@ class Checker : public StatTracer {
|
|||
// and thus we access them by first mapping a literal to 'unsigned'.
|
||||
//
|
||||
static unsigned l2u (int lit);
|
||||
vector<CheckerWatcher> watchers; // watchers of literals
|
||||
vector<signed char> marks; // mark bits of literals
|
||||
std::vector<CheckerWatcher> watchers; // watchers of literals
|
||||
std::vector<signed char> marks; // mark bits of literals
|
||||
|
||||
signed char &mark (int lit);
|
||||
CheckerWatcher &watcher (int lit);
|
||||
|
|
@ -83,16 +83,16 @@ class Checker : public StatTracer {
|
|||
CheckerClause **clauses; // hash table of clauses
|
||||
CheckerClause *garbage; // linked list of garbage clauses
|
||||
|
||||
vector<int> unsimplified; // original clause for reporting
|
||||
vector<int> simplified; // clause for sorting
|
||||
std::vector<int> unsimplified; // original clause for reporting
|
||||
std::vector<int> simplified; // clause for sorting
|
||||
|
||||
vector<int> trail; // for propagation
|
||||
std::vector<int> trail; // for propagation
|
||||
|
||||
unsigned next_to_propagate; // next to propagate on trail
|
||||
|
||||
void enlarge_vars (int64_t idx);
|
||||
void import_literal (int lit);
|
||||
void import_clause (const vector<int> &);
|
||||
void import_clause (const std::vector<int> &);
|
||||
bool tautological ();
|
||||
|
||||
static const unsigned num_nonces = 4;
|
||||
|
|
@ -156,17 +156,18 @@ public:
|
|||
|
||||
void connect_internal (Internal *i) override;
|
||||
|
||||
void add_original_clause (int64_t, bool, const vector<int> &,
|
||||
void add_original_clause (int64_t, bool, const std::vector<int> &,
|
||||
bool = false) override;
|
||||
void add_derived_clause (int64_t, bool, const vector<int> &,
|
||||
const vector<int64_t> &) override;
|
||||
void delete_clause (int64_t, bool, const vector<int> &) override;
|
||||
void add_derived_clause (int64_t, bool, int, const std::vector<int> &,
|
||||
const std::vector<int64_t> &) override;
|
||||
void delete_clause (int64_t, bool, const std::vector<int> &) override;
|
||||
|
||||
void finalize_clause (int64_t, const vector<int> &) override {} // skip
|
||||
void report_status (int, int64_t) override {} // skip
|
||||
void begin_proof (int64_t) override {} // skip
|
||||
void add_assumption_clause (int64_t, const vector<int> &,
|
||||
const vector<int64_t> &) override;
|
||||
void finalize_clause (int64_t, const std::vector<int> &) override {
|
||||
} // skip
|
||||
void report_status (int, int64_t) override {} // skip
|
||||
void begin_proof (int64_t) override {} // skip
|
||||
void add_assumption_clause (int64_t, const std::vector<int> &,
|
||||
const std::vector<int64_t> &) override;
|
||||
void print_stats () override;
|
||||
void dump (); // for debugging purposes only
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ typedef const int *const_literal_iterator;
|
|||
// memory but more importantly also requires another memory access and thus
|
||||
// is very costly.
|
||||
|
||||
#define USED_SIZE 5
|
||||
struct Clause {
|
||||
union {
|
||||
int64_t id; // Used to create LRAT-style proofs
|
||||
|
|
@ -41,6 +42,8 @@ struct Clause {
|
|||
// compactly in a contiguous memory arena. Otherwise, so almost all of
|
||||
// the time, 'id' is valid. See 'collect.cpp' for details.
|
||||
};
|
||||
unsigned used
|
||||
: USED_SIZE; // resolved in conflict analysis since last 'reduce'
|
||||
bool conditioned : 1; // Tried for globally blocked clause elimination.
|
||||
bool covered : 1; // Already considered for covered clause elimination.
|
||||
bool enqueued : 1; // Enqueued on backward queue.
|
||||
|
|
@ -56,9 +59,8 @@ struct Clause {
|
|||
bool subsume : 1; // not checked in last subsumption round
|
||||
bool swept : 1; // clause used to sweep equivalences
|
||||
bool flushed : 1; // garbage in proof deleted binaries
|
||||
unsigned used : 8; // resolved in conflict analysis since last 'reduce'
|
||||
bool vivified : 1; // clause already vivified
|
||||
bool vivify : 1; // clause scheduled to be vivified
|
||||
bool vivified : 1; // clause already vivified
|
||||
bool vivify : 1; // clause scheduled to be vivified
|
||||
|
||||
// The glucose level ('LBD' or short 'glue') is a heuristic value for the
|
||||
// expected usefulness of a learned clause, where smaller glue is consider
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue