blob: 547d58b03e939c1241ce10eec9376fb4fa9db6cb [file] [log] [blame]
/**CFile****************************************************************
FileName [sscSat.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [SAT sweeping under constraints.]
Synopsis [SAT procedures.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 29, 2008.]
Revision [$Id: sscSat.c,v 1.00 2008/07/29 00:00:00 alanmi Exp $]
***********************************************************************/
#include "sscInt.h"
#include "sat/cnf/cnf.h"
#include "aig/gia/giaAig.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static inline int Ssc_ObjSatLit( Ssc_Man_t * p, int Lit ) { return Abc_Var2Lit( Ssc_ObjSatVar(p, Abc_Lit2Var(Lit)), Abc_LitIsCompl(Lit) ); }
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Addes clauses to the solver.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static void Gia_ManAddClausesMux( Ssc_Man_t * p, Gia_Obj_t * pNode )
{
Gia_Obj_t * pNodeI, * pNodeT, * pNodeE;
int pLits[4], LitF, LitI, LitT, LitE, RetValue;
assert( !Gia_IsComplement( pNode ) );
assert( Gia_ObjIsMuxType( pNode ) );
// get nodes (I = if, T = then, E = else)
pNodeI = Gia_ObjRecognizeMux( pNode, &pNodeT, &pNodeE );
// get the Litiable numbers
LitF = Ssc_ObjSatLit( p, Gia_Obj2Lit(p->pFraig,pNode) );
LitI = Ssc_ObjSatLit( p, Gia_Obj2Lit(p->pFraig,pNodeI) );
LitT = Ssc_ObjSatLit( p, Gia_Obj2Lit(p->pFraig,pNodeT) );
LitE = Ssc_ObjSatLit( p, Gia_Obj2Lit(p->pFraig,pNodeE) );
// f = ITE(i, t, e)
// i' + t' + f
// i' + t + f'
// i + e' + f
// i + e + f'
// create four clauses
pLits[0] = Abc_LitNotCond(LitI, 1);
pLits[1] = Abc_LitNotCond(LitT, 1);
pLits[2] = Abc_LitNotCond(LitF, 0);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
pLits[0] = Abc_LitNotCond(LitI, 1);
pLits[1] = Abc_LitNotCond(LitT, 0);
pLits[2] = Abc_LitNotCond(LitF, 1);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
pLits[0] = Abc_LitNotCond(LitI, 0);
pLits[1] = Abc_LitNotCond(LitE, 1);
pLits[2] = Abc_LitNotCond(LitF, 0);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
pLits[0] = Abc_LitNotCond(LitI, 0);
pLits[1] = Abc_LitNotCond(LitE, 0);
pLits[2] = Abc_LitNotCond(LitF, 1);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
// two additional clauses
// t' & e' -> f'
// t & e -> f
// t + e + f'
// t' + e' + f
if ( LitT == LitE )
{
// assert( fCompT == !fCompE );
return;
}
pLits[0] = Abc_LitNotCond(LitT, 0);
pLits[1] = Abc_LitNotCond(LitE, 0);
pLits[2] = Abc_LitNotCond(LitF, 1);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
pLits[0] = Abc_LitNotCond(LitT, 1);
pLits[1] = Abc_LitNotCond(LitE, 1);
pLits[2] = Abc_LitNotCond(LitF, 0);
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 3 );
assert( RetValue );
}
/**Function*************************************************************
Synopsis [Addes clauses to the solver.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static void Gia_ManAddClausesSuper( Ssc_Man_t * p, Gia_Obj_t * pNode, Vec_Int_t * vSuper )
{
int i, RetValue, Lit, LitNode, pLits[2];
assert( !Gia_IsComplement(pNode) );
assert( Gia_ObjIsAnd( pNode ) );
// suppose AND-gate is A & B = C
// add !A => !C or A + !C
// add !B => !C or B + !C
LitNode = Ssc_ObjSatLit( p, Gia_Obj2Lit(p->pFraig,pNode) );
Vec_IntForEachEntry( vSuper, Lit, i )
{
pLits[0] = Ssc_ObjSatLit( p, Lit );
pLits[1] = Abc_LitNot( LitNode );
RetValue = sat_solver_addclause( p->pSat, pLits, pLits + 2 );
assert( RetValue );
// update literals
Vec_IntWriteEntry( vSuper, i, Abc_LitNot(pLits[0]) );
}
// add A & B => C or !A + !B + C
Vec_IntPush( vSuper, LitNode );
RetValue = sat_solver_addclause( p->pSat, Vec_IntArray(vSuper), Vec_IntArray(vSuper) + Vec_IntSize(vSuper) );
assert( RetValue );
(void) RetValue;
}
/**Function*************************************************************
Synopsis [Collects the supergate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static void Ssc_ManCollectSuper_rec( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vSuper )
{
// stop at complements, PIs, and MUXes
if ( Gia_IsComplement(pObj) || Gia_ObjIsCi(pObj) || Gia_ObjIsMuxType(pObj) )
{
Vec_IntPushUnique( vSuper, Gia_Obj2Lit(p, pObj) );
return;
}
Ssc_ManCollectSuper_rec( p, Gia_ObjChild0(pObj), vSuper );
Ssc_ManCollectSuper_rec( p, Gia_ObjChild1(pObj), vSuper );
}
static void Ssc_ManCollectSuper( Gia_Man_t * p, Gia_Obj_t * pObj, Vec_Int_t * vSuper )
{
assert( !Gia_IsComplement(pObj) );
assert( Gia_ObjIsAnd(pObj) );
Vec_IntClear( vSuper );
Ssc_ManCollectSuper_rec( p, Gia_ObjChild0(pObj), vSuper );
Ssc_ManCollectSuper_rec( p, Gia_ObjChild1(pObj), vSuper );
}
/**Function*************************************************************
Synopsis [Updates the solver clause database.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static void Ssc_ManCnfAddToFrontier( Ssc_Man_t * p, int Id, Vec_Int_t * vFront )
{
Gia_Obj_t * pObj;
assert( Id > 0 );
if ( Ssc_ObjSatVar(p, Id) )
return;
pObj = Gia_ManObj( p->pFraig, Id );
Ssc_ObjSetSatVar( p, Id, p->nSatVars++ );
sat_solver_setnvars( p->pSat, p->nSatVars + 100 );
if ( Gia_ObjIsAnd(pObj) )
Vec_IntPush( vFront, Id );
}
static void Ssc_ManCnfNodeAddToSolver( Ssc_Man_t * p, int NodeId )
{
Gia_Obj_t * pNode;
int i, k, Id, Lit;
abctime clk;
assert( NodeId > 0 );
// quit if CNF is ready
if ( Ssc_ObjSatVar(p, NodeId) )
return;
clk = Abc_Clock();
// start the frontier
Vec_IntClear( p->vFront );
Ssc_ManCnfAddToFrontier( p, NodeId, p->vFront );
// explore nodes in the frontier
Gia_ManForEachObjVec( p->vFront, p->pFraig, pNode, i )
{
// create the supergate
assert( Ssc_ObjSatVar(p, Gia_ObjId(p->pFraig, pNode)) );
if ( Gia_ObjIsMuxType(pNode) )
{
Vec_IntClear( p->vFanins );
Vec_IntPushUnique( p->vFanins, Gia_ObjFaninId0p( p->pFraig, Gia_ObjFanin0(pNode) ) );
Vec_IntPushUnique( p->vFanins, Gia_ObjFaninId0p( p->pFraig, Gia_ObjFanin1(pNode) ) );
Vec_IntPushUnique( p->vFanins, Gia_ObjFaninId1p( p->pFraig, Gia_ObjFanin0(pNode) ) );
Vec_IntPushUnique( p->vFanins, Gia_ObjFaninId1p( p->pFraig, Gia_ObjFanin1(pNode) ) );
Vec_IntForEachEntry( p->vFanins, Id, k )
Ssc_ManCnfAddToFrontier( p, Id, p->vFront );
Gia_ManAddClausesMux( p, pNode );
}
else
{
Ssc_ManCollectSuper( p->pFraig, pNode, p->vFanins );
Vec_IntForEachEntry( p->vFanins, Lit, k )
Ssc_ManCnfAddToFrontier( p, Abc_Lit2Var(Lit), p->vFront );
Gia_ManAddClausesSuper( p, pNode, p->vFanins );
}
assert( Vec_IntSize(p->vFanins) > 1 );
}
p->timeCnfGen += Abc_Clock() - clk;
}
/**Function*************************************************************
Synopsis [Starts the SAT solver for constraints.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ssc_ManStartSolver( Ssc_Man_t * p )
{
Aig_Man_t * pMan = Gia_ManToAigSimple( p->pFraig );
Cnf_Dat_t * pDat = Cnf_Derive( pMan, 0 );
Gia_Obj_t * pObj;
sat_solver * pSat;
int i, status;
assert( p->pSat == NULL && p->vId2Var == NULL );
assert( Aig_ManObjNumMax(pMan) == Gia_ManObjNum(p->pFraig) );
Aig_ManStop( pMan );
// save variable mapping
p->nSatVarsPivot = p->nSatVars = pDat->nVars;
p->vId2Var = Vec_IntStart( Gia_ManCandNum(p->pAig) + Gia_ManCandNum(p->pCare) + 10 ); // mapping of each node into its SAT var
p->vVar2Id = Vec_IntStart( Gia_ManCandNum(p->pAig) + Gia_ManCandNum(p->pCare) + 10 ); // mapping of each SAT var into its node
Ssc_ObjSetSatVar( p, 0, pDat->pVarNums[0] );
Gia_ManForEachCi( p->pFraig, pObj, i )
{
int iObj = Gia_ObjId( p->pFraig, pObj );
Ssc_ObjSetSatVar( p, iObj, pDat->pVarNums[iObj] );
}
//Cnf_DataWriteIntoFile( pDat, "dump.cnf", 1, NULL, NULL );
// start the SAT solver
pSat = sat_solver_new();
sat_solver_setnvars( pSat, pDat->nVars + 1000 );
for ( i = 0; i < pDat->nClauses; i++ )
{
if ( !sat_solver_addclause( pSat, pDat->pClauses[i], pDat->pClauses[i+1] ) )
{
Cnf_DataFree( pDat );
sat_solver_delete( pSat );
return;
}
}
Cnf_DataFree( pDat );
status = sat_solver_simplify( pSat );
if ( status == 0 )
{
sat_solver_delete( pSat );
return;
}
p->pSat = pSat;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Ssc_ManCollectSatPattern( Ssc_Man_t * p, Vec_Int_t * vPattern )
{
Gia_Obj_t * pObj;
int i;
Vec_IntClear( vPattern );
Gia_ManForEachCi( p->pFraig, pObj, i )
Vec_IntPush( vPattern, sat_solver_var_value(p->pSat, Ssc_ObjSatVar(p, Gia_ObjId(p->pFraig, pObj))) );
}
Vec_Int_t * Ssc_ManFindPivotSat( Ssc_Man_t * p )
{
Vec_Int_t * vInit;
int status = sat_solver_solve( p->pSat, NULL, NULL, p->pPars->nBTLimit, 0, 0, 0 );
if ( status == l_False )
return (Vec_Int_t *)(ABC_PTRINT_T)1;
if ( status == l_Undef )
return NULL;
assert( status == l_True );
vInit = Vec_IntAlloc( Gia_ManCiNum(p->pFraig) );
Ssc_ManCollectSatPattern( p, vInit );
return vInit;
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Ssc_ManCheckEquivalence( Ssc_Man_t * p, int iRepr, int iNode, int fCompl )
{
int pLitsSat[2], RetValue;
abctime clk;
assert( iRepr != iNode );
if ( iRepr > iNode )
return l_Undef;
assert( iRepr < iNode );
// if ( p->nTimeOut )
// sat_solver_set_runtime_limit( p->pSat, p->nTimeOut * CLOCKS_PER_SEC + Abc_Clock() );
// create CNF
if ( iRepr )
Ssc_ManCnfNodeAddToSolver( p, iRepr );
Ssc_ManCnfNodeAddToSolver( p, iNode );
sat_solver_compress( p->pSat );
// order the literals
pLitsSat[0] = Abc_Var2Lit( Ssc_ObjSatVar(p, iRepr), 0 );
pLitsSat[1] = Abc_Var2Lit( Ssc_ObjSatVar(p, iNode), fCompl ^ (int)(iRepr > 0) );
// solve under assumptions
// A = 1; B = 0
clk = Abc_Clock();
RetValue = sat_solver_solve( p->pSat, pLitsSat, pLitsSat + 2, (ABC_INT64_T)p->pPars->nBTLimit, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( RetValue == l_False )
{
pLitsSat[0] = Abc_LitNot( pLitsSat[0] ); // compl
pLitsSat[1] = Abc_LitNot( pLitsSat[1] ); // compl
RetValue = sat_solver_addclause( p->pSat, pLitsSat, pLitsSat + 2 );
assert( RetValue );
p->timeSatUnsat += Abc_Clock() - clk;
}
else if ( RetValue == l_True )
{
Ssc_ManCollectSatPattern( p, p->vPattern );
p->timeSatSat += Abc_Clock() - clk;
return l_True;
}
else // if ( RetValue1 == l_Undef )
{
p->timeSatUndec += Abc_Clock() - clk;
return l_Undef;
}
// if the old node was constant 0, we already know the answer
if ( iRepr == 0 )
return l_False;
// solve under assumptions
// A = 0; B = 1
clk = Abc_Clock();
RetValue = sat_solver_solve( p->pSat, pLitsSat, pLitsSat + 2, (ABC_INT64_T)p->pPars->nBTLimit, (ABC_INT64_T)0, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( RetValue == l_False )
{
pLitsSat[0] = Abc_LitNot( pLitsSat[0] );
pLitsSat[1] = Abc_LitNot( pLitsSat[1] );
RetValue = sat_solver_addclause( p->pSat, pLitsSat, pLitsSat + 2 );
assert( RetValue );
p->timeSatUnsat += Abc_Clock() - clk;
}
else if ( RetValue == l_True )
{
Ssc_ManCollectSatPattern( p, p->vPattern );
p->timeSatSat += Abc_Clock() - clk;
return l_True;
}
else // if ( RetValue1 == l_Undef )
{
p->timeSatUndec += Abc_Clock() - clk;
return l_Undef;
}
return l_False;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END