blob: 5af54306ac2c60c94bdd22cf8e6345bee1b008a0 [file] [log] [blame]
/**CFile****************************************************************
FileName [bmcChain.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [SAT-based bounded model checking.]
Synopsis [Implementation of chain BMC.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: bmcChain.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "bmc.h"
#include "aig/gia/giaAig.h"
#include "sat/cnf/cnf.h"
#include "sat/bsat/satSolver.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Find the first failure.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Abc_Cex_t * Bmc_ChainFailOneOutput( Gia_Man_t * p, int nFrameMax, int nConfMax, int fVerbose, int fVeryVerbose )
{
int RetValue;
Abc_Cex_t * pCex = NULL;
Aig_Man_t * pAig = Gia_ManToAigSimple( p );
Saig_ParBmc_t Pars, * pPars = &Pars;
Saig_ParBmcSetDefaultParams( pPars );
pPars->nFramesMax = nFrameMax;
pPars->nConfLimit = nConfMax;
pPars->fVerbose = fVeryVerbose;
RetValue = Saig_ManBmcScalable( pAig, pPars );
if ( RetValue == 0 ) // SAT
{
pCex = pAig->pSeqModel, pAig->pSeqModel = NULL;
if ( fVeryVerbose )
Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d.\n", pCex->iPo, p->pName, pCex->iFrame );
}
else if ( fVeryVerbose )
Abc_Print( 1, "No output asserted in %d frames. Resource limit reached.\n", pPars->iFrame+2 );
Aig_ManStop( pAig );
return pCex;
}
/**Function*************************************************************
Synopsis [Move GIA into the failing state.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Gia_Man_t * Gia_ManDupWithInit( Gia_Man_t * p )
{
Gia_Man_t * pNew;
Gia_Obj_t * pObj;
int i;
pNew = Gia_ManStart( Gia_ManObjNum(p) );
pNew->pName = Abc_UtilStrsav( p->pName );
pNew->pSpec = Abc_UtilStrsav( p->pSpec );
Gia_ManConst0(p)->Value = 0;
Gia_ManForEachObj1( p, pObj, i )
{
if ( Gia_ObjIsAnd(pObj) )
pObj->Value = Gia_ManAppendAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
else if ( Gia_ObjIsCi(pObj) )
{
pObj->Value = Gia_ManAppendCi( pNew );
pObj->Value = Abc_LitNotCond( pObj->Value, pObj->fMark0 );
}
else if ( Gia_ObjIsCo(pObj) )
{
pObj->Value = Gia_ObjFanin0Copy(pObj);
pObj->Value = Abc_LitNotCond( pObj->Value, pObj->fMark0 );
pObj->Value = Gia_ManAppendCo( pNew, pObj->Value );
}
}
Gia_ManSetRegNum( pNew, Gia_ManRegNum(p) );
return pNew;
}
Gia_Man_t * Gia_ManVerifyCexAndMove( Gia_Man_t * pGia, Abc_Cex_t * p )
{
Gia_Man_t * pNew;
Gia_Obj_t * pObj, * pObjRi, * pObjRo;
int RetValue, i, k, iBit = 0;
Gia_ManCleanMark0(pGia);
Gia_ManForEachRo( pGia, pObj, i )
pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++);
for ( i = 0; i <= p->iFrame; i++ )
{
Gia_ManForEachPi( pGia, pObj, k )
pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++);
Gia_ManForEachAnd( pGia, pObj, k )
pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) &
(Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj));
Gia_ManForEachCo( pGia, pObj, k )
pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj);
if ( i == p->iFrame )
break;
Gia_ManForEachRiRo( pGia, pObjRi, pObjRo, k )
pObjRo->fMark0 = pObjRi->fMark0;
}
assert( iBit == p->nBits );
RetValue = Gia_ManPo(pGia, p->iPo)->fMark0;
assert( RetValue );
// set PI/PO values to zero and transfer RO values to RI
Gia_ManForEachPi( pGia, pObj, k )
pObj->fMark0 = 0;
Gia_ManForEachPo( pGia, pObj, k )
pObj->fMark0 = 0;
Gia_ManForEachRiRo( pGia, pObjRi, pObjRo, k )
pObjRi->fMark0 = pObjRo->fMark0;
// duplicate assuming CI/CO marks are set correctly
pNew = Gia_ManDupWithInit( pGia );
Gia_ManCleanMark0(pGia);
return pNew;
}
/**Function*************************************************************
Synopsis [Find what outputs fail in this state.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Gia_Man_t * Gia_ManDupPosAndPropagateInit( Gia_Man_t * p )
{
Gia_Man_t * pNew, * pTemp;
Gia_Obj_t * pObj; int i;
pNew = Gia_ManStart( Gia_ManObjNum(p) );
pNew->pName = Abc_UtilStrsav( p->pName );
pNew->pSpec = Abc_UtilStrsav( p->pSpec );
Gia_ManConst0(p)->Value = 0;
Gia_ManHashAlloc( pNew );
Gia_ManForEachObj1( p, pObj, i )
{
if ( Gia_ObjIsAnd(pObj) )
pObj->Value = Gia_ManHashAnd( pNew, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) );
else if ( Gia_ObjIsPi(p, pObj) )
pObj->Value = Gia_ManAppendCi( pNew );
else if ( Gia_ObjIsCi(pObj) )
pObj->Value = 0;
else if ( Gia_ObjIsPo(p, pObj) )
Gia_ManAppendCo( pNew, Gia_ObjFanin0Copy(pObj) );
}
Gia_ManHashStop( pNew );
assert( Gia_ManPiNum(p) == Gia_ManPiNum(pNew) );
assert( Gia_ManPoNum(p) == Gia_ManPoNum(pNew) );
pNew = Gia_ManCleanup( pTemp = pNew );
Gia_ManStop( pTemp );
return pNew;
}
sat_solver * Gia_ManDeriveSatSolver( Gia_Man_t * p, Vec_Int_t * vSatIds )
{
sat_solver * pSat;
Aig_Man_t * pAig = Gia_ManToAigSimple( p );
// Cnf_Dat_t * pCnf = (Cnf_Dat_t *)Mf_ManGenerateCnf( p, 8, 0, 0, 0, 0 );
Cnf_Dat_t * pCnf = Cnf_Derive( pAig, Aig_ManCoNum(pAig) );
// save SAT vars for the primary inputs
if ( vSatIds )
{
Aig_Obj_t * pObj; int i;
Vec_IntClear( vSatIds );
Aig_ManForEachCi( pAig, pObj, i )
Vec_IntPush( vSatIds, pCnf->pVarNums[ Aig_ObjId(pObj) ] );
assert( Vec_IntSize(vSatIds) == Gia_ManPiNum(p) );
}
Aig_ManStop( pAig );
pSat = (sat_solver *)Cnf_DataWriteIntoSolver( pCnf, 1, 0 );
Cnf_DataFree( pCnf );
assert( p->nRegs == 0 );
return pSat;
}
Vec_Int_t * Bmc_ChainFindFailedOutputs( Gia_Man_t * p, Vec_Ptr_t * vCexes )
{
Vec_Int_t * vOutputs;
Vec_Int_t * vSatIds;
Gia_Man_t * pInit;
Gia_Obj_t * pObj;
sat_solver * pSat;
int i, j, Lit, status = 0;
// derive output logic cones
pInit = Gia_ManDupPosAndPropagateInit( p );
// derive SAT solver and test
vSatIds = Vec_IntAlloc( Gia_ManPiNum(p) );
pSat = Gia_ManDeriveSatSolver( pInit, vSatIds );
vOutputs = Vec_IntAlloc( 100 );
Gia_ManForEachPo( pInit, pObj, i )
{
if ( Gia_ObjFaninLit0p(pInit, pObj) == 0 )
continue;
Lit = Abc_Var2Lit( i+1, 0 );
status = sat_solver_solve( pSat, &Lit, &Lit + 1, 0, 0, 0, 0 );
if ( status == l_True )
{
// save the index of solved output
Vec_IntPush( vOutputs, i );
// create CEX for this output
if ( vCexes )
{
Abc_Cex_t * pCex = Abc_CexAlloc( Gia_ManRegNum(p), Gia_ManPiNum(p), 1 );
pCex->iFrame = 0;
pCex->iPo = i;
for ( j = 0; j < Gia_ManPiNum(p); j++ )
if ( sat_solver_var_value( pSat, Vec_IntEntry(vSatIds, j) ) )
Abc_InfoSetBit( pCex->pData, Gia_ManRegNum(p) + j );
Vec_PtrPush( vCexes, pCex );
}
}
}
Gia_ManStop( pInit );
sat_solver_delete( pSat );
Vec_IntFree( vSatIds );
return vOutputs;
}
/**Function*************************************************************
Synopsis [Cleanup AIG by removing COs replacing failed out by const0.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Gia_ObjMakePoConst0( Gia_Man_t * p, Gia_Obj_t * pObj )
{
assert( Gia_ObjIsCo(pObj) );
pObj->iDiff0 = Gia_ObjId( p, pObj );
pObj->fCompl0 = 0;
}
int Gia_ManCountNonConst0( Gia_Man_t * p )
{
Gia_Obj_t * pObj;
int i, Count = 0;
Gia_ManForEachPo( p, pObj, i )
Count += (Gia_ObjFaninLit0p(p, pObj) != 0);
return Count;
}
Gia_Man_t * Bmc_ChainCleanup( Gia_Man_t * p, Vec_Int_t * vOutputs )
{
int i, iOut;
Vec_IntForEachEntry( vOutputs, iOut, i )
{
Gia_Obj_t * pObj = Gia_ManPo( p, iOut );
assert( Gia_ObjFaninLit0p(p, pObj) != 0 );
Gia_ObjMakePoConst0( p, pObj );
assert( Gia_ObjFaninLit0p(p, pObj) == 0 );
}
return Gia_ManCleanup( p );
}
/**Function*************************************************************
Synopsis []
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Bmc_ChainTest( Gia_Man_t * p, int nFrameMax, int nConfMax, int fVerbose, int fVeryVerbose, Vec_Ptr_t ** pvCexes )
{
int Iter, IterMax = 10000;
Gia_Man_t * pTemp, * pNew = Gia_ManDup(p);
Abc_Cex_t * pCex = NULL;
Vec_Int_t * vOutputs;
abctime clk2, clk = Abc_Clock();
abctime clkBmc = 0;
abctime clkMov = 0;
abctime clkSat = 0;
abctime clkCln = 0;
abctime clkSwp = 0;
int DepthTotal = 0;
if ( pvCexes )
*pvCexes = Vec_PtrAlloc( 1000 );
for ( Iter = 0; Iter < IterMax; Iter++ )
{
if ( Gia_ManPoNum(pNew) == 0 )
{
if ( fVerbose )
printf( "Finished all POs.\n" );
break;
}
// run BMC till the first failure
clk2 = Abc_Clock();
pCex = Bmc_ChainFailOneOutput( pNew, nFrameMax, nConfMax, fVerbose, fVeryVerbose );
clkBmc += Abc_Clock() - clk2;
if ( pCex == NULL )
{
if ( fVerbose )
printf( "BMC could not detect a failed output in %d frames with %d conflicts.\n", nFrameMax, nConfMax );
break;
}
assert( !Iter || pCex->iFrame > 0 );
// move the AIG to the failure state
clk2 = Abc_Clock();
pNew = Gia_ManVerifyCexAndMove( pTemp = pNew, pCex );
Gia_ManStop( pTemp );
DepthTotal += pCex->iFrame;
clkMov += Abc_Clock() - clk2;
// find outputs that fail in this state
clk2 = Abc_Clock();
vOutputs = Bmc_ChainFindFailedOutputs( pNew, pvCexes ? *pvCexes : NULL );
assert( Vec_IntFind(vOutputs, pCex->iPo) >= 0 );
// save the counter-example
if ( pvCexes )
Vec_PtrPush( *pvCexes, pCex );
else
Abc_CexFree( pCex );
clkSat += Abc_Clock() - clk2;
// remove them from the AIG
clk2 = Abc_Clock();
pNew = Bmc_ChainCleanup( pTemp = pNew, vOutputs );
Gia_ManStop( pTemp );
clkCln += Abc_Clock() - clk2;
// perform sequential cleanup
clk2 = Abc_Clock();
// pNew = Gia_ManSeqStructSweep( pTemp = pNew, 0, 1, 0 );
// Gia_ManStop( pTemp );
clkSwp += Abc_Clock() - clk2;
// printout
if ( fVerbose )
{
int nNonConst = Gia_ManCountNonConst0(pNew);
printf( "Iter %4d : ", Iter+1 );
printf( "Depth =%5d ", DepthTotal );
printf( "FailPo =%5d ", Vec_IntSize(vOutputs) );
printf( "UndecPo =%5d ", nNonConst );
printf( "(%6.2f %%) ", 100.0 * nNonConst / Gia_ManPoNum(pNew) );
printf( "AIG =%8d ", Gia_ManAndNum(pNew) );
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
}
Vec_IntFree( vOutputs );
}
printf( "Completed a CEX chain with %d segments, %d frames, and %d failed POs (out of %d). ",
Iter, DepthTotal, Gia_ManPoNum(pNew) - Gia_ManCountNonConst0(pNew), Gia_ManPoNum(pNew) );
if ( fVerbose )
{
Abc_PrintTime( 1, "Time", Abc_Clock() - clk );
Abc_PrintTimeP( 1, "BMC ", clkBmc, Abc_Clock() - clk );
Abc_PrintTimeP( 1, "Init ", clkMov, Abc_Clock() - clk );
Abc_PrintTimeP( 1, "SAT ", clkSat, Abc_Clock() - clk );
Abc_PrintTimeP( 1, "Clean", clkCln, Abc_Clock() - clk );
// Abc_PrintTimeP( 1, "Sweep", clkSwp, Abc_Clock() - clk );
}
Gia_ManStop( pNew );
if ( pvCexes )
printf( "Total number of CEXes collected = %d.\n", Vec_PtrSize(*pvCexes) );
return 0;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END