blob: 04935f99aadd3191d9b7f8e12e91b8abc391a14b [file] [log] [blame]
/**CFile****************************************************************
FileName [giaSatLE.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Scalable AIG package.]
Synopsis [Mapping with edges.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: giaSatLE.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "gia.h"
#include "misc/extra/extra.h"
#include "misc/tim/tim.h"
#include "sat/bsat/satStore.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static inline int Sle_CutSize( int * pCut ) { return pCut[0] & 0xF; } // 4 bits
static inline int Sle_CutSign( int * pCut ) { return ((unsigned)pCut[0]) >> 4; } // 28 bits
static inline int Sle_CutSetSizeSign( int s, int S ) { return (S << 4) | s; }
static inline int * Sle_CutLeaves( int * pCut ) { return pCut + 1; }
static inline int Sle_CutIsUsed( int * pCut ) { return pCut[1] != 0; }
static inline void Sle_CutSetUnused( int * pCut ) { pCut[1] = 0; }
static inline int Sle_ListCutNum( int * pList ) { return pList[0]; }
#define Sle_ForEachCut( pList, pCut, i ) for ( i = 0, pCut = pList + 1; i < pList[0]; i++, pCut += Sle_CutSize(pCut) + 1 ) // cuts with unit-cut
#define Sle_ForEachCut1( pList, pCut, i ) for ( i = 0, pCut = pList + 1; i <= pList[0]; i++, pCut += Sle_CutSize(pCut) + 1 ) // only non-unit cuts
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Cut computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Sle_CutMergeOrder( int * pCut0, int * pCut1, int * pCut, int nLutSize )
{
int nSize0 = Sle_CutSize(pCut0);
int nSize1 = Sle_CutSize(pCut1);
int i, * pC0 = Sle_CutLeaves(pCut0);
int k, * pC1 = Sle_CutLeaves(pCut1);
int c, * pC = Sle_CutLeaves(pCut);
// the case of the largest cut sizes
if ( nSize0 == nLutSize && nSize1 == nLutSize )
{
for ( i = 0; i < nSize0; i++ )
{
if ( pC0[i] != pC1[i] ) return 0;
pC[i] = pC0[i];
}
pCut[0] = Sle_CutSetSizeSign( nLutSize, Sle_CutSign(pCut0) | Sle_CutSign(pCut1) );
return 1;
}
// compare two cuts with different numbers
i = k = c = 0;
if ( nSize0 == 0 ) goto FlushCut1;
if ( nSize1 == 0 ) goto FlushCut0;
while ( 1 )
{
if ( c == nLutSize ) return 0;
if ( pC0[i] < pC1[k] )
{
pC[c++] = pC0[i++];
if ( i >= nSize0 ) goto FlushCut1;
}
else if ( pC0[i] > pC1[k] )
{
pC[c++] = pC1[k++];
if ( k >= nSize1 ) goto FlushCut0;
}
else
{
pC[c++] = pC0[i++]; k++;
if ( i >= nSize0 ) goto FlushCut1;
if ( k >= nSize1 ) goto FlushCut0;
}
}
FlushCut0:
if ( c + nSize0 > nLutSize + i ) return 0;
while ( i < nSize0 )
pC[c++] = pC0[i++];
pCut[0] = Sle_CutSetSizeSign( c, Sle_CutSign(pCut0) | Sle_CutSign(pCut1) );
return 1;
FlushCut1:
if ( c + nSize1 > nLutSize + k ) return 0;
while ( k < nSize1 )
pC[c++] = pC1[k++];
pCut[0] = Sle_CutSetSizeSign( c, Sle_CutSign(pCut0) | Sle_CutSign(pCut1) );
return 1;
}
static inline int Sle_SetCutIsContainedOrder( int * pBase, int * pCut ) // check if pCut is contained in pBase
{
int i, nSizeB = Sle_CutSize(pBase);
int k, nSizeC = Sle_CutSize(pCut);
int * pLeaveB = Sle_CutLeaves(pBase);
int * pLeaveC = Sle_CutLeaves(pCut);
if ( nSizeB == nSizeC )
{
for ( i = 0; i < nSizeB; i++ )
if ( pLeaveB[i] != pLeaveC[i] )
return 0;
return 1;
}
assert( nSizeB > nSizeC );
if ( nSizeC == 0 )
return 1;
for ( i = k = 0; i < nSizeB; i++ )
{
if ( pLeaveB[i] > pLeaveC[k] )
return 0;
if ( pLeaveB[i] == pLeaveC[k] )
{
if ( ++k == nSizeC )
return 1;
}
}
return 0;
}
static inline int Sle_CutCountBits( unsigned i )
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = ((i + (i >> 4)) & 0x0F0F0F0F);
return (i*(0x01010101))>>24;
}
static inline int Sle_SetLastCutIsContained( Vec_Int_t * vTemp, int * pBase )
{
int i, * pCut, * pList = Vec_IntArray(vTemp);
Sle_ForEachCut( pList, pCut, i )
if ( Sle_CutIsUsed(pCut) && Sle_CutSize(pCut) <= Sle_CutSize(pBase) && (Sle_CutSign(pCut) & Sle_CutSign(pBase)) == Sle_CutSign(pCut) && Sle_SetCutIsContainedOrder(pBase, pCut) )
return 1;
return 0;
}
static inline void Sle_SetAddCut( Vec_Int_t * vTemp, int * pCut )
{
int i, * pBase, * pList = Vec_IntArray(vTemp);
Sle_ForEachCut( pList, pBase, i )
if ( Sle_CutIsUsed(pBase) && Sle_CutSize(pCut) < Sle_CutSize(pBase) && (Sle_CutSign(pCut) & Sle_CutSign(pBase)) == Sle_CutSign(pCut) && Sle_SetCutIsContainedOrder(pBase, pCut) )
Sle_CutSetUnused( pBase );
Vec_IntPushArray( vTemp, pCut, Sle_CutSize(pCut)+1 );
Vec_IntAddToEntry( vTemp, 0, 1 );
}
int Sle_ManCutMerge( Gia_Man_t * p, int iObj, Vec_Int_t * vCuts, Vec_Int_t * vTemp, int nLutSize )
{
Gia_Obj_t * pObj = Gia_ManObj( p, iObj );
int * pList0 = Vec_IntEntryP( vCuts, Vec_IntEntry(vCuts, Gia_ObjFaninId0(pObj, iObj)) );
int * pList1 = Vec_IntEntryP( vCuts, Vec_IntEntry(vCuts, Gia_ObjFaninId1(pObj, iObj)) );
int * pCut0, * pCut1, i, k, Cut[8], nCuts = 0;
Vec_IntFill( vTemp, 1, 0 );
Sle_ForEachCut1( pList0, pCut0, i )
Sle_ForEachCut1( pList1, pCut1, k )
{
if ( Sle_CutSize(pCut0) + Sle_CutSize(pCut1) > nLutSize && Sle_CutCountBits(Sle_CutSign(pCut0) | Sle_CutSign(pCut1)) > nLutSize )
continue;
if ( !Sle_CutMergeOrder(pCut0, pCut1, Cut, nLutSize) )
continue;
if ( Sle_SetLastCutIsContained(vTemp, Cut) )
continue;
Sle_SetAddCut( vTemp, Cut );
}
// reload
Vec_IntWriteEntry( vCuts, iObj, Vec_IntSize(vCuts) );
Vec_IntPush( vCuts, -1 );
pList0 = Vec_IntArray(vTemp);
Sle_ForEachCut( pList0, pCut0, i )
{
if ( !Sle_CutIsUsed(pCut0) )
continue;
Vec_IntPushArray( vCuts, pCut0, Sle_CutSize(pCut0)+1 );
nCuts++;
}
// add unit cut
Vec_IntPush( vCuts, Sle_CutSetSizeSign(1, 1<<(iObj % 28)) );
Vec_IntPush( vCuts, iObj );
Vec_IntWriteEntry( vCuts, Vec_IntEntry(vCuts, iObj), nCuts );
return nCuts;
}
Vec_Int_t * Sle_ManComputeCuts( Gia_Man_t * p, int nLutSize, int fVerbose )
{
int i, iObj, nCuts = 0;
Vec_Int_t * vTemp = Vec_IntAlloc( 1000 );
Vec_Int_t * vCuts = Vec_IntAlloc( 30 * Gia_ManAndNum(p) );
assert( nLutSize <= 6 );
Vec_IntFill( vCuts, Gia_ManObjNum(p), 0 );
Gia_ManForEachCiId( p, iObj, i )
{
Vec_IntWriteEntry( vCuts, iObj, Vec_IntSize(vCuts) );
Vec_IntPush( vCuts, 0 );
Vec_IntPush( vCuts, Sle_CutSetSizeSign(1, 1<<(iObj % 28)) );
Vec_IntPush( vCuts, iObj );
}
Gia_ManForEachAndId( p, iObj )
nCuts += Sle_ManCutMerge( p, iObj, vCuts, vTemp, nLutSize );
if ( fVerbose )
printf( "Nodes = %d. Cuts = %d. Cuts/Node = %.2f. Ints/Node = %.2f. Mem = %.2f MB.\n",
Gia_ManAndNum(p), nCuts, 1.0*nCuts/Gia_ManAndNum(p),
1.0*(Vec_IntSize(vCuts)-Gia_ManObjNum(p))/Gia_ManAndNum(p),
1.0*Vec_IntMemory(vCuts) / (1<<20) );
Vec_IntFree( vTemp );
return vCuts;
}
/**Function*************************************************************
Synopsis [Cut delay computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Sle_ManComputeDelayCut( Gia_Man_t * p, int * pCut, Vec_Int_t * vTime )
{
int nSize = Sle_CutSize(pCut);
int k, * pC = Sle_CutLeaves(pCut);
int DelayMax = 0;
for ( k = 0; k < nSize; k++ )
DelayMax = Abc_MaxInt( DelayMax, Vec_IntEntry(vTime, pC[k]) );
return DelayMax + 1;
}
int Sle_ManComputeDelayOne( Gia_Man_t * p, int iObj, Vec_Int_t * vCuts, Vec_Int_t * vTime )
{
int i, * pCut, Delay, DelayMin = ABC_INFINITY;
int * pList = Vec_IntEntryP( vCuts, Vec_IntEntry(vCuts, iObj) );
Sle_ForEachCut( pList, pCut, i )
{
Delay = Sle_ManComputeDelayCut( p, pCut, vTime );
DelayMin = Abc_MinInt( DelayMin, Delay );
}
Vec_IntWriteEntry( vTime, iObj, DelayMin );
return DelayMin;
}
int Sle_ManComputeDelay( Gia_Man_t * p, Vec_Int_t * vCuts )
{
int iObj, Delay, DelayMax = 0;
Vec_Int_t * vTime = Vec_IntStart( Gia_ManObjNum(p) );
Gia_ManForEachAndId( p, iObj )
{
Delay = Sle_ManComputeDelayOne( p, iObj, vCuts, vTime );
DelayMax = Abc_MaxInt( DelayMax, Delay );
}
Vec_IntFree( vTime );
//printf( "Delay = %d.\n", DelayMax );
return DelayMax;
}
/**Function*************************************************************
Synopsis [Cut printing.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManPrintCut( int * pCut )
{
int nSize = Sle_CutSize(pCut);
int k, * pC = Sle_CutLeaves(pCut);
printf( "{" );
for ( k = 0; k < nSize; k++ )
printf( " %d", pC[k] );
printf( " }\n" );
}
void Sle_ManPrintCuts( Gia_Man_t * p, Vec_Int_t * vCuts, int iObj )
{
int i, * pCut;
int * pList = Vec_IntEntryP( vCuts, Vec_IntEntry(vCuts, iObj) );
printf( "Obj %3d\n", iObj );
Sle_ForEachCut( pList, pCut, i )
Sle_ManPrintCut( pCut );
printf( "\n" );
}
void Sle_ManPrintCutsAll( Gia_Man_t * p, Vec_Int_t * vCuts )
{
int iObj;
Gia_ManForEachAndId( p, iObj )
Sle_ManPrintCuts( p, vCuts, iObj );
}
void Sle_ManComputeCutsTest( Gia_Man_t * p )
{
Vec_Int_t * vCuts = Sle_ManComputeCuts( p, 4, 1 );
//Sle_ManPrintCutsAll( p, vCuts );
Vec_IntFree( vCuts );
}
/**Function*************************************************************
Synopsis [Derive mask representing internal nodes.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Bit_t * Sle_ManInternalNodeMask( Gia_Man_t * pGia )
{
int iObj;
Vec_Bit_t * vMask = Vec_BitStart( Gia_ManObjNum(pGia) );
Gia_ManForEachAndId( pGia, iObj )
Vec_BitWriteEntry( vMask, iObj, 1 );
return vMask;
}
/**Function*************************************************************
Synopsis [Check if the cut contains only primary inputs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Sle_ManCutHasPisOnly( int * pCut, Vec_Bit_t * vMask )
{
int k, * pC = Sle_CutLeaves(pCut);
for ( k = 0; k < Sle_CutSize(pCut); k++ )
if ( Vec_BitEntry(vMask, pC[k]) ) // internal node
return 0;
return 1;
}
/**Function*************************************************************
Synopsis [Derive cut fanins of each node.]
Description [These are nodes that are fanins of some cut of this node.]
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManCollectCutFaninsOne( Gia_Man_t * pGia, int iObj, Vec_Int_t * vCuts, Vec_Bit_t * vMask, Vec_Int_t * vCutFanins, Vec_Bit_t * vMap )
{
int i, iFanin, * pCut, * pList = Vec_IntEntryP( vCuts, Vec_IntEntry(vCuts, iObj) );
Sle_ForEachCut( pList, pCut, i )
{
int nSize = Sle_CutSize(pCut);
int k, * pC = Sle_CutLeaves(pCut);
assert( nSize > 1 );
for ( k = 0; k < nSize; k++ )
if ( Vec_BitEntry(vMask, pC[k]) && !Vec_BitEntry(vMap, pC[k]) )
{
Vec_BitWriteEntry( vMap, pC[k], 1 );
Vec_IntPush( vCutFanins, pC[k] );
}
}
Vec_IntForEachEntry( vCutFanins, iFanin, i )
Vec_BitWriteEntry( vMap, iFanin, 0 );
}
Vec_Wec_t * Sle_ManCollectCutFanins( Gia_Man_t * pGia, Vec_Int_t * vCuts, Vec_Bit_t * vMask )
{
int iObj;
Vec_Bit_t * vMap = Vec_BitStart( Gia_ManObjNum(pGia) );
Vec_Wec_t * vCutFanins = Vec_WecStart( Gia_ManObjNum(pGia) );
Gia_ManForEachAndId( pGia, iObj )
Sle_ManCollectCutFaninsOne( pGia, iObj, vCuts, vMask, Vec_WecEntry(vCutFanins, iObj), vMap );
Vec_BitFree( vMap );
return vCutFanins;
}
typedef struct Sle_Man_t_ Sle_Man_t;
struct Sle_Man_t_
{
// user's data
Gia_Man_t * pGia; // user's manager (with mapping and edges)
int nLevels; // total number of levels
int fVerbose; // verbose flag
int nSatCalls; // the number of SAT calls
// SAT variables
int nNodeVars; // node variables (Gia_ManAndNum(pGia))
int nCutVars; // cut variables (total number of non-trivial cuts)
int nEdgeVars; // edge variables (total number of internal edges)
int nDelayVars; // delay variables (nNodeVars * nLevelsMax)
int nVarsTotal; // total number of variables
// SAT clauses
int nCutClas; // cut clauses
int nEdgeClas; // edge clauses
int nEdgeClas2; // edge clauses exclusivity
int nDelayClas; // delay clauses
// internal data
sat_solver * pSat; // SAT solver
Vec_Bit_t * vMask; // internal node mask
Vec_Int_t * vCuts; // cuts for each node
Vec_Wec_t * vCutFanins; // internal cut fanins of each node
Vec_Wec_t * vFanoutEdges; // internal cut fanins of each node
Vec_Wec_t * vEdgeCuts; // cuts of each edge for one node
Vec_Int_t * vObjMap; // temporary object map
Vec_Int_t * vCutFirst; // first cut of each node
Vec_Int_t * vEdgeFirst; // first edge of each node
Vec_Int_t * vDelayFirst; // first edge of each node
Vec_Int_t * vPolars; // initial
Vec_Int_t * vLits; // literals
// statistics
abctime timeStart;
};
static inline int * Sle_ManList( Sle_Man_t * p, int i ) { return Vec_IntEntryP(p->vCuts, Vec_IntEntry(p->vCuts, i)); }
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Sle_Man_t * Sle_ManAlloc( Gia_Man_t * pGia, int nLevels, int fVerbose )
{
Sle_Man_t * p = ABC_CALLOC( Sle_Man_t, 1 );
p->pGia = pGia;
p->nLevels = nLevels;
p->fVerbose = fVerbose;
p->vMask = Sle_ManInternalNodeMask( pGia );
p->vCuts = Sle_ManComputeCuts( pGia, 4, fVerbose );
p->vCutFanins = Sle_ManCollectCutFanins( pGia, p->vCuts, p->vMask );
p->vFanoutEdges = Vec_WecStart( Gia_ManObjNum(pGia) );
p->vEdgeCuts = Vec_WecAlloc( 100 );
p->vObjMap = Vec_IntStartFull( Gia_ManObjNum(pGia) );
p->vCutFirst = Vec_IntStartFull( Gia_ManObjNum(pGia) );
p->vEdgeFirst = Vec_IntStartFull( Gia_ManObjNum(pGia) );
p->vDelayFirst = Vec_IntStartFull( Gia_ManObjNum(pGia) );
p->vPolars = Vec_IntAlloc( 100 );
p->vLits = Vec_IntAlloc( 100 );
p->nLevels = Sle_ManComputeDelay( pGia, p->vCuts );
return p;
}
void Sle_ManStop( Sle_Man_t * p )
{
sat_solver_delete( p->pSat );
Vec_BitFree( p->vMask );
Vec_IntFree( p->vCuts );
Vec_WecFree( p->vCutFanins );
Vec_WecFree( p->vFanoutEdges );
Vec_WecFree( p->vEdgeCuts );
Vec_IntFree( p->vObjMap );
Vec_IntFree( p->vCutFirst );
Vec_IntFree( p->vEdgeFirst );
Vec_IntFree( p->vDelayFirst );
Vec_IntFree( p->vPolars );
Vec_IntFree( p->vLits );
ABC_FREE( p );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManMarkupVariables( Sle_Man_t * p )
{
int iObj, Counter = Gia_ManObjNum(p->pGia);
// node variables
p->nNodeVars = Counter;
// cut variables
Gia_ManForEachAndId( p->pGia, iObj )
{
Vec_IntWriteEntry( p->vCutFirst, iObj, Counter );
Counter += Sle_ListCutNum( Sle_ManList(p, iObj) );
}
p->nCutVars = Counter - p->nNodeVars;
// edge variables
Gia_ManForEachAndId( p->pGia, iObj )
{
Vec_IntWriteEntry( p->vEdgeFirst, iObj, Counter );
Counter += Vec_IntSize( Vec_WecEntry(p->vCutFanins, iObj) );
}
p->nEdgeVars = Counter - p->nCutVars - p->nNodeVars;
// delay variables
Gia_ManForEachAndId( p->pGia, iObj )
{
Vec_IntWriteEntry( p->vDelayFirst, iObj, Counter );
Counter += p->nLevels;
}
p->nDelayVars = Counter - p->nEdgeVars - p->nCutVars - p->nNodeVars;
p->nVarsTotal = Counter;
}
/**Function*************************************************************
Synopsis [Derive initial variable assignment.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
// returns 1 if Cut can represent LUT (Cut is equal or is contained in LUT)
static inline int Sle_ManCheckContained( int * pCutLeaves, int nCutLeaves, int * pLutFanins, int nLutFanins )
{
int i, k;
if ( nCutLeaves > nLutFanins )
return 0;
for ( i = 0; i < nCutLeaves; i++ )
{
for ( k = 0; k < nLutFanins; k++ )
if ( pCutLeaves[i] == pLutFanins[k] )
break;
if ( k == nLutFanins ) // not found
return 0;
}
return 1;
}
void Sle_ManDeriveInit( Sle_Man_t * p )
{
Vec_Int_t * vEdges;
int i, iObj, iFanin, iEdge;
if ( !Gia_ManHasMapping(p->pGia) )
return;
// derive initial state
Vec_IntClear( p->vPolars );
Gia_ManForEachAndId( p->pGia, iObj )
{
int nFanins, * pFanins, * pCut, * pList, iFound = -1;
if ( !Gia_ObjIsLut(p->pGia, iObj) )
continue;
Vec_IntPush( p->vPolars, iObj ); // node var
nFanins = Gia_ObjLutSize( p->pGia, iObj );
pFanins = Gia_ObjLutFanins( p->pGia, iObj );
// find cut
pList = Sle_ManList( p, iObj );
Sle_ForEachCut( pList, pCut, i )
if ( Sle_ManCheckContained( Sle_CutLeaves(pCut), Sle_CutSize(pCut), pFanins, nFanins ) )
{
iFound = i;
break;
}
if ( iFound == -1 )
{
printf( "Cannot find the following cut at node %d: {", iObj );
for ( i = 0; i < nFanins; i++ )
printf( " %d", pFanins[i] );
printf( " }\n" );
Sle_ManPrintCuts( p->pGia, p->vCuts, iObj );
fflush( stdout );
}
assert( iFound >= 0 );
Vec_IntPush( p->vPolars, Vec_IntEntry(p->vCutFirst, iObj) + iFound ); // cut var
// check if the cut contains only primary inputs - if so, its delay is equal to 1
if ( Sle_ManCutHasPisOnly(pCut, p->vMask) )
Vec_IntPush( p->vPolars, Vec_IntEntry(p->vDelayFirst, iObj) ); // delay var
}
Vec_IntSort( p->vPolars, 0 );
// find zero-delay edges
if ( !p->pGia->vEdge1 )
return;
vEdges = Gia_ManEdgeToArray( p->pGia );
Vec_IntForEachEntryDouble( vEdges, iFanin, iObj, i )
{
assert( iFanin < iObj );
assert( Gia_ObjIsLut(p->pGia, iFanin) );
assert( Gia_ObjIsLut(p->pGia, iObj) );
assert( Gia_ObjIsAnd(Gia_ManObj(p->pGia, iFanin)) );
assert( Gia_ObjIsAnd(Gia_ManObj(p->pGia, iObj)) );
// find edge
iEdge = Vec_IntFind( Vec_WecEntry(p->vCutFanins, iObj), iFanin );
if ( iEdge < 0 )
continue;
assert( iEdge >= 0 );
Vec_IntPush( p->vPolars, Vec_IntEntry(p->vEdgeFirst, iObj) + iEdge ); // edge
}
Vec_IntFree( vEdges );
}
/**Function*************************************************************
Synopsis [Derive CNF.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManDeriveCnf( Sle_Man_t * p, int nBTLimit, int fDynamic )
{
int nTimeOut = 0;
int i, iObj, value;
Vec_Int_t * vArray;
// start the SAT solver
p->pSat = sat_solver_new();
sat_solver_setnvars( p->pSat, p->nVarsTotal );
sat_solver_set_resource_limits( p->pSat, nBTLimit, 0, 0, 0 );
sat_solver_set_runtime_limit( p->pSat, nTimeOut ? nTimeOut * CLOCKS_PER_SEC + Abc_Clock(): 0 );
sat_solver_set_random( p->pSat, 1 );
sat_solver_set_polarity( p->pSat, Vec_IntArray(p->vPolars), Vec_IntSize(p->vPolars) );
//sat_solver_set_var_activity( p->pSat, NULL, p->nVarsTotal );
// set drivers to be mapped
Gia_ManForEachCoDriverId( p->pGia, iObj, i )
if ( Vec_BitEntry(p->vMask, iObj) ) // internal node
{
Vec_IntFill( p->vLits, 1, Abc_Var2Lit(iObj, 0) ); // pos lit
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
// add cover clauses and edge-to-cut clauses
Gia_ManForEachAndId( p->pGia, iObj )
{
int e, iEdge, nEdges = 0, Entry;
int iCutVar0 = Vec_IntEntry( p->vCutFirst, iObj );
int iEdgeVar0 = Vec_IntEntry( p->vEdgeFirst, iObj );
int * pCut, * pList = Sle_ManList( p, iObj );
Vec_Int_t * vCutFans = Vec_WecEntry( p->vCutFanins, iObj );
assert( iCutVar0 > 0 && iEdgeVar0 > 0 );
// node requires one of the cuts
Vec_IntFill( p->vLits, 1, Abc_Var2Lit(iObj, 1) ); // neg lit
for ( i = 0; i < Sle_ListCutNum(pList); i++ )
Vec_IntPush( p->vLits, Abc_Var2Lit(iCutVar0 + i, 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
// cuts are mutually exclusive
for ( i = 0; i < Sle_ListCutNum(pList); i++ )
for ( e = i+1; e < Sle_ListCutNum(pList); e++ )
{
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(iCutVar0 + i, 1), Abc_Var2Lit(iCutVar0 + e, 1) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
// cut requires fanin nodes
Vec_WecInit( p->vEdgeCuts, Vec_IntSize(vCutFans) );
Sle_ForEachCut( pList, pCut, i )
{
int nSize = Sle_CutSize(pCut);
int k, * pC = Sle_CutLeaves(pCut);
assert( nSize > 1 );
for ( k = 0; k < nSize; k++ )
{
if ( !Vec_BitEntry(p->vMask, pC[k]) )
continue;
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(iCutVar0 + i, 1), Abc_Var2Lit(pC[k], 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
// find the edge ID between pC[k] and iObj
iEdge = Vec_IntEntry(p->vObjMap, pC[k]);
if ( iEdge == -1 )
{
Vec_IntWriteEntry( p->vObjMap, pC[k], (iEdge = nEdges++) );
Vec_WecPush( p->vFanoutEdges, pC[k], iEdgeVar0 + iEdge );
}
Vec_WecPush( p->vEdgeCuts, iEdge, iCutVar0 + i );
p->nCutClas++;
}
// cut requires the node
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(iCutVar0 + i, 1), Abc_Var2Lit(iObj, 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
assert( nEdges == Vec_IntSize(vCutFans) );
// edge requires one of the fanout cuts
Vec_WecForEachLevel( p->vEdgeCuts, vArray, e )
{
assert( Vec_IntSize(vArray) > 0 );
Vec_IntFill( p->vLits, 1, Abc_Var2Lit(iEdgeVar0 + e, 1) ); // neg lit (edge)
Vec_IntForEachEntry( vArray, Entry, i )
Vec_IntPush( p->vLits, Abc_Var2Lit(Entry, 0) ); // pos lit (cut)
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
p->nEdgeClas++;
}
// clean object map
Vec_IntForEachEntry( vCutFans, Entry, i )
Vec_IntWriteEntry( p->vObjMap, Entry, -1 );
}
// mutual exclusivity of edges
Vec_WecForEachLevel( p->vFanoutEdges, vArray, iObj )
{
int j, k, EdgeJ, EdgeK;
int iEdgeVar0 = Vec_IntEntry( p->vEdgeFirst, iObj );
Vec_Int_t * vCutFans = Vec_WecEntry( p->vCutFanins, iObj );
// add fanin edges
for ( i = 0; i < Vec_IntSize(vCutFans); i++ )
Vec_IntPush( vArray, iEdgeVar0 + i );
// generate pairs
if ( fDynamic )
continue;
Vec_IntForEachEntry( vArray, EdgeJ, j )
Vec_IntForEachEntryStart( vArray, EdgeK, k, j+1 )
{
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(EdgeJ, 1), Abc_Var2Lit(EdgeK, 1) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
p->nEdgeClas2 += Vec_IntSize(vArray) * (Vec_IntSize(vArray) - 1) / 2;
}
// add delay clauses
Gia_ManForEachAndId( p->pGia, iObj )
{
int e, iFanin;
int iEdgeVar0 = Vec_IntEntry( p->vEdgeFirst, iObj );
int iDelayVar0 = Vec_IntEntry( p->vDelayFirst, iObj );
Vec_Int_t * vCutFans = Vec_WecEntry( p->vCutFanins, iObj );
// check if the node has cuts containing only primary inputs
int * pCut, * pList = Sle_ManList( p, iObj );
Sle_ForEachCut( pList, pCut, i )
if ( Sle_ManCutHasPisOnly(pCut, p->vMask) )
{
Vec_IntFill( p->vLits, 1, Abc_Var2Lit(iDelayVar0, 0) ); // pos lit
// Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(iObj, 1), Abc_Var2Lit(iDelayVar0, 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
break;
}
// if ( i < Sle_ListCutNum(pList) )
// continue;
// create delay requirements for each cut fanin of this node
Vec_IntForEachEntry( vCutFans, iFanin, e )
{
int d, iDelayVarIn = Vec_IntEntry( p->vDelayFirst, iFanin );
for ( d = 0; d < p->nLevels; d++ )
{
Vec_IntClear( p->vLits );
Vec_IntPush( p->vLits, Abc_Var2Lit(iObj, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iFanin, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iDelayVarIn + d, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iEdgeVar0 + e, 0) );
if ( d < p->nLevels-1 )
Vec_IntPush( p->vLits, Abc_Var2Lit(iDelayVar0 + d+1, 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
Vec_IntClear( p->vLits );
Vec_IntPush( p->vLits, Abc_Var2Lit(iObj, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iFanin, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iDelayVarIn + d, 1) );
if ( d < p->nLevels-1 )
Vec_IntPush( p->vLits, Abc_Var2Lit(iEdgeVar0 + e, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(iDelayVar0 + d, 0) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
p->nDelayClas += 2*p->nLevels;
}
}
}
/**Function*************************************************************
Synopsis [Add edge compatibility constraints.]
Description [Returns 1 if constraints have been added.]
SideEffects []
SeeAlso []
***********************************************************************/
int Sle_ManAddEdgeConstraints( Sle_Man_t * p, int nEdges )
{
Vec_Int_t * vArray;
Vec_Int_t * vTemp = Vec_IntAlloc( 100 );
int value, iObj, nAdded = 0;
assert( nEdges == 1 || nEdges == 2 );
Vec_WecForEachLevel( p->vFanoutEdges, vArray, iObj )
{
int j, k, EdgeJ, EdgeK;
// check if they are incompatible
Vec_IntClear( vTemp );
Vec_IntForEachEntry( vArray, EdgeJ, j )
if ( sat_solver_var_value(p->pSat, EdgeJ) )
Vec_IntPush( vTemp, EdgeJ );
if ( Vec_IntSize(vTemp) <= nEdges )
continue;
nAdded++;
if ( nEdges == 1 )
{
// generate pairs
Vec_IntForEachEntry( vTemp, EdgeJ, j )
Vec_IntForEachEntryStart( vTemp, EdgeK, k, j+1 )
{
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(EdgeJ, 1), Abc_Var2Lit(EdgeK, 1) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
p->nEdgeClas2 += Vec_IntSize(vTemp) * (Vec_IntSize(vTemp) - 1) / 2;
}
else if ( nEdges == 2 )
{
int m, EdgeM;
// generate triples
Vec_IntForEachEntry( vTemp, EdgeJ, j )
Vec_IntForEachEntryStart( vTemp, EdgeK, k, j+1 )
Vec_IntForEachEntryStart( vTemp, EdgeM, m, k+1 )
{
Vec_IntFillTwo( p->vLits, 2, Abc_Var2Lit(EdgeJ, 1), Abc_Var2Lit(EdgeK, 1) );
Vec_IntPush( p->vLits, Abc_Var2Lit(EdgeM, 1) );
value = sat_solver_addclause( p->pSat, Vec_IntArray(p->vLits), Vec_IntLimit(p->vLits) );
assert( value );
}
p->nEdgeClas2 += Vec_IntSize(vTemp) * (Vec_IntSize(vTemp) - 1) * (Vec_IntSize(vTemp) - 2) / 6;
}
else assert( 0 );
}
Vec_IntFree( vTemp );
//printf( "Added clauses to %d nodes.\n", nAdded );
return nAdded;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManDeriveResult( Sle_Man_t * p, Vec_Int_t * vEdge2, Vec_Int_t * vMapping )
{
Vec_Int_t * vMapTemp;
int iObj;
// create mapping
Vec_IntFill( vMapping, Gia_ManObjNum(p->pGia), 0 );
Gia_ManForEachAndId( p->pGia, iObj )
{
int i, iCut, iCutVar0 = Vec_IntEntry( p->vCutFirst, iObj );
int * pCut, * pCutThis = NULL, * pList = Sle_ManList( p, iObj );
if ( !sat_solver_var_value(p->pSat, iObj) )
continue;
Sle_ForEachCut( pList, pCut, iCut )
if ( sat_solver_var_value(p->pSat, iCutVar0 + iCut) )
{
assert( pCutThis == NULL );
pCutThis = pCut;
}
assert( pCutThis != NULL );
Vec_IntWriteEntry( vMapping, iObj, Vec_IntSize(vMapping) );
Vec_IntPush( vMapping, Sle_CutSize(pCutThis) );
for ( i = 0; i < Sle_CutSize(pCutThis); i++ )
Vec_IntPush( vMapping, Sle_CutLeaves(pCutThis)[i] );
Vec_IntPush( vMapping, iObj );
}
vMapTemp = p->pGia->vMapping;
p->pGia->vMapping = vMapping;
// collect edges
Vec_IntClear( vEdge2 );
Gia_ManForEachAndId( p->pGia, iObj )
{
int i, iFanin, iEdgeVar0 = Vec_IntEntry( p->vEdgeFirst, iObj );
Vec_Int_t * vCutFans = Vec_WecEntry( p->vCutFanins, iObj );
//int * pCut, * pList = Sle_ManList( p, iObj );
// int iCutVar0 = Vec_IntEntry( p->vCutFirst, iObj );
if ( !sat_solver_var_value(p->pSat, iObj) )
continue;
//for ( i = 0; i < Sle_ListCutNum(pList); i++ )
// printf( "%d", sat_solver_var_value(p->pSat, iCutVar0 + i) );
//printf( "\n" );
Vec_IntForEachEntry( vCutFans, iFanin, i )
if ( sat_solver_var_value(p->pSat, iFanin) && sat_solver_var_value(p->pSat, iEdgeVar0 + i) )
{
// verify edge
int * pFanins = Gia_ObjLutFanins( p->pGia, iObj );
int k, nFanins = Gia_ObjLutSize( p->pGia, iObj );
for ( k = 0; k < nFanins; k++ )
{
//printf( "%d ", pFanins[k] );
if ( pFanins[k] == iFanin )
break;
}
//printf( "\n" );
if ( k == nFanins )
// printf( "Cannot find LUT with input %d at node %d.\n", iFanin, iObj );
continue;
Vec_IntPushTwo( vEdge2, iFanin, iObj );
}
}
p->pGia->vMapping = vMapTemp;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Sle_ManExplore( Gia_Man_t * pGia, int nBTLimit, int DelayInit, int fDynamic, int fTwoEdges, int fVerbose )
{
int fVeryVerbose = 0;
abctime clk = Abc_Clock();
Vec_Int_t * vEdges2 = Vec_IntAlloc(1000);
Vec_Int_t * vMapping = Vec_IntAlloc(1000);
int i, iLut, nConfs, status, Delay, iFirstVar;
int DelayStart = (DelayInit || !Gia_ManHasMapping(pGia)) ? DelayInit : Gia_ManLutLevel(pGia, NULL);
Sle_Man_t * p = Sle_ManAlloc( pGia, DelayStart, fVerbose );
if ( fVerbose )
printf( "Running solver with %d conflicts, %d initial delay, and %d edges. Dynamic constraints = %s.\n", nBTLimit, DelayInit, 1+fTwoEdges, fDynamic?"yes":"no" );
Sle_ManMarkupVariables( p );
if ( fVerbose )
printf( "Vars: Total = %d. Node = %d. Cut = %d. Edge = %d. Delay = %d.\n",
p->nVarsTotal, p->nNodeVars, p->nCutVars, p->nEdgeVars, p->nDelayVars );
Sle_ManDeriveInit( p );
Sle_ManDeriveCnf( p, nBTLimit, fDynamic || fTwoEdges );
if ( fVerbose )
printf( "Clas: Total = %d. Cut = %d. Edge = %d. EdgeEx = %d. Delay = %d.\n",
sat_solver_nclauses(p->pSat), p->nCutClas, p->nEdgeClas, p->nEdgeClas2, p->nDelayClas );
//Sat_SolverWriteDimacs( p->pSat, "temp.cnf", NULL, NULL, 0 );
for ( Delay = p->nLevels; Delay >= 0; Delay-- )
{
// we constrain COs, although it would be fine to constrain only POs
if ( Delay < p->nLevels )
{
Gia_ManForEachCoDriverId( p->pGia, iLut, i )
if ( Vec_BitEntry(p->vMask, iLut) ) // internal node
{
iFirstVar = Vec_IntEntry( p->vDelayFirst, iLut );
if ( !sat_solver_push(p->pSat, Abc_Var2Lit(iFirstVar + Delay, 1)) )
break;
}
if ( i < Gia_ManCoNum(p->pGia) )
{
if ( fVerbose )
{
printf( "Proved UNSAT for delay %d. ", Delay );
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
break;
}
}
// solve with assumptions
//clk = Abc_Clock();
nConfs = sat_solver_nconflicts( p->pSat );
while ( 1 )
{
p->nSatCalls++;
status = sat_solver_solve_internal( p->pSat );
if ( status != l_True )
break;
if ( !Sle_ManAddEdgeConstraints(p, 1+fTwoEdges) )
break;
}
nConfs = sat_solver_nconflicts( p->pSat ) - nConfs;
if ( status == l_True )
{
if ( fVerbose )
{
int nNodes = 0, nEdges = 0;
for ( i = 0; i < p->nNodeVars; i++ )
nNodes += sat_solver_var_value(p->pSat, i);
for ( i = 0; i < p->nEdgeVars; i++ )
nEdges += sat_solver_var_value(p->pSat, p->nNodeVars + p->nCutVars + i);
printf( "Solution with delay %2d, node count %5d, and edge count %5d exists. Conf = %8d. ", Delay, nNodes, nEdges, nConfs );
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
// save the result
Sle_ManDeriveResult( p, vEdges2, vMapping );
if ( fVeryVerbose )
{
printf( "Nodes: " );
for ( i = 0; i < p->nNodeVars; i++ )
if ( sat_solver_var_value(p->pSat, i) )
printf( "%d ", i );
printf( "\n" );
printf( "\n" );
Vec_IntPrint( p->vCutFirst );
printf( "Cuts: " );
for ( i = 0; i < p->nCutVars; i++ )
if ( sat_solver_var_value(p->pSat, p->nNodeVars + i) )
printf( "%d ", p->nNodeVars + i );
printf( "\n" );
printf( "\n" );
Vec_IntPrint( p->vEdgeFirst );
printf( "Edges: " );
for ( i = 0; i < p->nEdgeVars; i++ )
if ( sat_solver_var_value(p->pSat, p->nNodeVars + p->nCutVars + i) )
printf( "%d ", p->nNodeVars + p->nCutVars + i );
printf( "\n" );
printf( "\n" );
Vec_IntPrint( p->vDelayFirst );
printf( "Delays: " );
for ( i = 0; i < p->nDelayVars; i++ )
if ( sat_solver_var_value(p->pSat, p->nNodeVars + p->nCutVars + p->nEdgeVars + i) )
printf( "%d ", p->nNodeVars + p->nCutVars + p->nEdgeVars + i );
printf( "\n" );
printf( "\n" );
}
}
else
{
if ( fVerbose )
{
if ( status == l_False )
printf( "Proved UNSAT for delay %d. Conf = %8d. ", Delay, nConfs );
else
printf( "Resource limit reached for delay %d. Conf = %8d. ", Delay, nConfs );
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
break;
}
}
if ( fVerbose )
printf( "Clas: Total = %d. Cut = %d. Edge = %d. EdgeEx = %d. Delay = %d. Calls = %d.\n",
sat_solver_nclauses(p->pSat), p->nCutClas, p->nEdgeClas, p->nEdgeClas2, p->nDelayClas, p->nSatCalls );
if ( Vec_IntSize(vMapping) > 0 )
{
Gia_ManEdgeFromArray( p->pGia, vEdges2 );
Vec_IntFree( vEdges2 );
Vec_IntFreeP( &p->pGia->vMapping );
p->pGia->vMapping = vMapping;
}
else
{
Vec_IntFree( vEdges2 );
Vec_IntFree( vMapping );
}
Vec_IntFreeP( &p->pGia->vPacking );
Sle_ManStop( p );
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END