/**CFile**************************************************************** FileName [giaAbs.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [Scalable AIG package.] Synopsis [Counter-example-guided abstraction refinement.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: giaAbs.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "gia.h" #include "sat/bsat/satSolver.h" #include "sat/cnf/cnf.h" #include "sat/bmc/bmc.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Resimulates the counter-example.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Gia_ManVerifyCex( Gia_Man_t * pAig, Abc_Cex_t * p, int fDualOut ) { Gia_Obj_t * pObj, * pObjRi, * pObjRo; int RetValue, i, k, iBit = 0; Gia_ManCleanMark0(pAig); Gia_ManForEachRo( pAig, pObj, i ) pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); for ( i = 0; i <= p->iFrame; i++ ) { Gia_ManForEachPi( pAig, pObj, k ) pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); Gia_ManForEachAnd( pAig, pObj, k ) pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) & (Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj)); Gia_ManForEachCo( pAig, pObj, k ) pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj); if ( i == p->iFrame ) break; Gia_ManForEachRiRo( pAig, pObjRi, pObjRo, k ) { pObjRo->fMark0 = pObjRi->fMark0; } } assert( iBit == p->nBits ); if ( fDualOut ) RetValue = Gia_ManPo(pAig, 2*p->iPo)->fMark0 ^ Gia_ManPo(pAig, 2*p->iPo+1)->fMark0; else RetValue = Gia_ManPo(pAig, p->iPo)->fMark0; Gia_ManCleanMark0(pAig); return RetValue; } /**Function************************************************************* Synopsis [Resimulates the counter-example.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Gia_ManFindFailedPoCex( Gia_Man_t * pAig, Abc_Cex_t * p, int nOutputs ) { Gia_Obj_t * pObj, * pObjRi, * pObjRo; int RetValue, i, k, iBit = 0; assert( Gia_ManPiNum(pAig) == p->nPis ); Gia_ManCleanMark0(pAig); Gia_ManForEachRo( pAig, pObj, i ) pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); iBit = p->nRegs; for ( i = 0; i <= p->iFrame; i++ ) { Gia_ManForEachPi( pAig, pObj, k ) pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); Gia_ManForEachAnd( pAig, pObj, k ) pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) & (Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj)); Gia_ManForEachCo( pAig, pObj, k ) pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj); Gia_ManForEachRiRo( pAig, pObjRi, pObjRo, k ) pObjRo->fMark0 = pObjRi->fMark0; } assert( iBit == p->nBits ); // figure out the number of failed output RetValue = -1; // for ( i = Gia_ManPoNum(pAig) - 1; i >= nOutputs; i-- ) for ( i = nOutputs; i < Gia_ManPoNum(pAig); i++ ) { if ( Gia_ManPo(pAig, i)->fMark0 ) { RetValue = i; break; } } Gia_ManCleanMark0(pAig); return RetValue; } /**Function************************************************************* Synopsis [Determines the failed PO when its exact frame is not known.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Gia_ManSetFailedPoCex( Gia_Man_t * pAig, Abc_Cex_t * p ) { Gia_Obj_t * pObj, * pObjRi, * pObjRo; int i, k, iBit = 0; assert( Gia_ManPiNum(pAig) == p->nPis ); Gia_ManCleanMark0(pAig); p->iPo = -1; // Gia_ManForEachRo( pAig, pObj, i ) // pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); iBit = p->nRegs; for ( i = 0; i <= p->iFrame; i++ ) { Gia_ManForEachPi( pAig, pObj, k ) pObj->fMark0 = Abc_InfoHasBit(p->pData, iBit++); Gia_ManForEachAnd( pAig, pObj, k ) pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) & (Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj)); Gia_ManForEachCo( pAig, pObj, k ) pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj); Gia_ManForEachRiRo( pAig, pObjRi, pObjRo, k ) pObjRo->fMark0 = pObjRi->fMark0; // check the POs Gia_ManForEachPo( pAig, pObj, k ) { if ( !pObj->fMark0 ) continue; p->iPo = k; p->iFrame = i; p->nBits = iBit; break; } } Gia_ManCleanMark0(pAig); return p->iPo; } /**Function************************************************************* Synopsis [Starts the process of returning values for internal nodes.] Description [Should be called when pCex is available, before probing any object for its value using Gia_ManCounterExampleValueLookup().] SideEffects [] SeeAlso [] ***********************************************************************/ void Gia_ManCounterExampleValueStart( Gia_Man_t * pGia, Abc_Cex_t * pCex ) { Gia_Obj_t * pObj, * pObjRi, * pObjRo; int Val0, Val1, nObjs, i, k, iBit = 0; assert( Gia_ManRegNum(pGia) > 0 ); // makes sense only for sequential AIGs assert( pGia->pData2 == NULL ); // if this fail, there may be a memory leak // allocate memory to store simulation bits for internal nodes pGia->pData2 = ABC_CALLOC( unsigned, Abc_BitWordNum( (pCex->iFrame + 1) * Gia_ManObjNum(pGia) ) ); // the register values in the counter-example should be zero Gia_ManForEachRo( pGia, pObj, k ) assert( Abc_InfoHasBit(pCex->pData, iBit) == 0 ), iBit++; // iterate through the timeframes nObjs = Gia_ManObjNum(pGia); for ( i = 0; i <= pCex->iFrame; i++ ) { // no need to set constant-0 node // set primary inputs according to the counter-example Gia_ManForEachPi( pGia, pObj, k ) if ( Abc_InfoHasBit(pCex->pData, iBit++) ) Abc_InfoSetBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjId(pGia, pObj) ); // compute values for each node Gia_ManForEachAnd( pGia, pObj, k ) { Val0 = Abc_InfoHasBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjFaninId0p(pGia, pObj) ); Val1 = Abc_InfoHasBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjFaninId1p(pGia, pObj) ); if ( (Val0 ^ Gia_ObjFaninC0(pObj)) & (Val1 ^ Gia_ObjFaninC1(pObj)) ) Abc_InfoSetBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjId(pGia, pObj) ); } // derive values for combinational outputs Gia_ManForEachCo( pGia, pObj, k ) { Val0 = Abc_InfoHasBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjFaninId0p(pGia, pObj) ); if ( Val0 ^ Gia_ObjFaninC0(pObj) ) Abc_InfoSetBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjId(pGia, pObj) ); } if ( i == pCex->iFrame ) continue; // transfer values to the register output of the next frame Gia_ManForEachRiRo( pGia, pObjRi, pObjRo, k ) if ( Abc_InfoHasBit( (unsigned *)pGia->pData2, nObjs * i + Gia_ObjId(pGia, pObjRi) ) ) Abc_InfoSetBit( (unsigned *)pGia->pData2, nObjs * (i+1) + Gia_ObjId(pGia, pObjRo) ); } assert( iBit == pCex->nBits ); // check that the counter-example is correct, that is, the corresponding output is asserted assert( Abc_InfoHasBit( (unsigned *)pGia->pData2, nObjs * pCex->iFrame + Gia_ObjId(pGia, Gia_ManCo(pGia, pCex->iPo)) ) ); } /**Function************************************************************* Synopsis [Stops the process of returning values for internal nodes.] Description [Should be called when probing is no longer needed] SideEffects [] SeeAlso [] ***********************************************************************/ void Gia_ManCounterExampleValueStop( Gia_Man_t * pGia ) { assert( pGia->pData2 != NULL ); // if this fail, we try to call this procedure more than once ABC_FREE( pGia->pData2 ); pGia->pData2 = NULL; } /**Function************************************************************* Synopsis [Returns the value of the given object in the given timeframe.] Description [Should be called to probe the value of an object with the given ID (iFrame is a 0-based number of a time frame - should not exceed the number of timeframes in the original counter-example).] SideEffects [] SeeAlso [] ***********************************************************************/ int Gia_ManCounterExampleValueLookup( Gia_Man_t * pGia, int Id, int iFrame ) { assert( Id >= 0 && Id < Gia_ManObjNum(pGia) ); return Abc_InfoHasBit( (unsigned *)pGia->pData2, Gia_ManObjNum(pGia) * iFrame + Id ); } /**Function************************************************************* Synopsis [Procedure to test the above code.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Gia_ManCounterExampleValueTest( Gia_Man_t * pGia, Abc_Cex_t * pCex ) { Gia_Obj_t * pObj = Gia_ManObj( pGia, Gia_ManObjNum(pGia)/2 ); int iFrame = Abc_MaxInt( 0, pCex->iFrame - 1 ); printf( "\nUsing counter-example, which asserts output %d in frame %d.\n", pCex->iPo, pCex->iFrame ); Gia_ManCounterExampleValueStart( pGia, pCex ); printf( "Value of object %d in frame %d is %d.\n", Gia_ObjId(pGia, pObj), iFrame, Gia_ManCounterExampleValueLookup(pGia, Gia_ObjId(pGia, pObj), iFrame) ); Gia_ManCounterExampleValueStop( pGia ); } /**Function************************************************************* Synopsis [Returns CEX containing PI+CS values for each timeframe.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Cex_t * Gia_ManCexExtendToIncludeCurrentStates( Gia_Man_t * p, Abc_Cex_t * pCex ) { Abc_Cex_t * pNew; Gia_Obj_t * pObj, * pObjRo, * pObjRi; int i, k, iBit = 0; assert( pCex->nRegs > 0 ); // start the counter-example pNew = Abc_CexAlloc( 0, Gia_ManCiNum(p), pCex->iFrame + 1 ); pNew->iFrame = pCex->iFrame; pNew->iPo = pCex->iPo; // set const0 Gia_ManConst0(p)->fMark0 = 0; // set init state Gia_ManForEachRi( p, pObjRi, k ) pObjRi->fMark0 = Abc_InfoHasBit(pCex->pData, iBit++); assert( iBit == pCex->nRegs ); for ( i = 0; i <= pCex->iFrame; i++ ) { Gia_ManForEachPi( p, pObj, k ) pObj->fMark0 = Abc_InfoHasBit(pCex->pData, iBit++); Gia_ManForEachRiRo( p, pObjRi, pObjRo, k ) pObjRo->fMark0 = pObjRi->fMark0; Gia_ManForEachCi( p, pObj, k ) if ( pObj->fMark0 ) Abc_InfoSetBit( pNew->pData, pNew->nPis * i + k ); Gia_ManForEachAnd( p, pObj, k ) pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) & (Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj)); Gia_ManForEachCo( p, pObj, k ) pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj); } assert( iBit == pCex->nBits ); assert( Gia_ManPo(p, pCex->iPo)->fMark0 == 1 ); Gia_ManCleanMark0(p); return pNew; } /**Function************************************************************* Synopsis [Returns CEX containing all object valuess for each timeframe.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Abc_Cex_t * Gia_ManCexExtendToIncludeAllObjects( Gia_Man_t * p, Abc_Cex_t * pCex ) { Abc_Cex_t * pNew; Gia_Obj_t * pObj, * pObjRo, * pObjRi; int i, k, iBit = 0; assert( pCex->nRegs > 0 ); // start the counter-example pNew = Abc_CexAlloc( 0, Gia_ManObjNum(p), pCex->iFrame + 1 ); pNew->iFrame = pCex->iFrame; pNew->iPo = pCex->iPo; // set const0 Gia_ManConst0(p)->fMark0 = 0; // set init state Gia_ManForEachRi( p, pObjRi, k ) pObjRi->fMark0 = Abc_InfoHasBit(pCex->pData, iBit++); assert( iBit == pCex->nRegs ); for ( i = 0; i <= pCex->iFrame; i++ ) { Gia_ManForEachPi( p, pObj, k ) pObj->fMark0 = Abc_InfoHasBit(pCex->pData, iBit++); Gia_ManForEachRiRo( p, pObjRi, pObjRo, k ) pObjRo->fMark0 = pObjRi->fMark0; Gia_ManForEachObj( p, pObj, k ) if ( pObj->fMark0 ) Abc_InfoSetBit( pNew->pData, pNew->nPis * i + k ); Gia_ManForEachAnd( p, pObj, k ) pObj->fMark0 = (Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj)) & (Gia_ObjFanin1(pObj)->fMark0 ^ Gia_ObjFaninC1(pObj)); Gia_ManForEachCo( p, pObj, k ) pObj->fMark0 = Gia_ObjFanin0(pObj)->fMark0 ^ Gia_ObjFaninC0(pObj); } assert( iBit == pCex->nBits ); assert( Gia_ManPo(p, pCex->iPo)->fMark0 == 1 ); Gia_ManCleanMark0(p); return pNew; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Gia_Man_t * Gia_ManFramesForCexMin( Gia_Man_t * p, int nFrames ) { Gia_Man_t * pFrames, * pTemp; Gia_Obj_t * pObj; int i, f; assert( Gia_ManPoNum(p) == 1 ); pFrames = Gia_ManStart( Gia_ManObjNum(p) ); pFrames->pName = Abc_UtilStrsav( p->pName ); pFrames->pSpec = Abc_UtilStrsav( p->pSpec ); Gia_ManHashAlloc( pFrames ); Gia_ManConst0(p)->Value = 0; for ( f = 0; f < nFrames; f++ ) { Gia_ManForEachRo( p, pObj, i ) pObj->Value = f ? Gia_ObjRoToRi( p, pObj )->Value : 0; Gia_ManForEachPi( p, pObj, i ) pObj->Value = Gia_ManAppendCi( pFrames ); Gia_ManForEachAnd( p, pObj, i ) pObj->Value = Gia_ManHashAnd( pFrames, Gia_ObjFanin0Copy(pObj), Gia_ObjFanin1Copy(pObj) ); Gia_ManForEachRi( p, pObj, i ) pObj->Value = Gia_ObjFanin0Copy(pObj); } Gia_ManForEachCo( p, pObj, i ) Gia_ManAppendCo( pFrames, Gia_ObjFanin0Copy(pObj) ); pFrames = Gia_ManCleanup( pTemp = pFrames ); //printf( "Before cleanup = %d nodes. After cleanup = %d nodes.\n", // Gia_ManAndNum(pTemp), Gia_ManAndNum(pFrames) ); Gia_ManStop( pTemp ); return pFrames; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Gia_ManMinCex( Gia_Man_t * p, Abc_Cex_t * pCex ) { abctime clk = Abc_Clock(); int n, i, iFirstVar, iLit, status, Counter = 0;//, Id; Vec_Int_t * vLits; sat_solver * pSat; Cnf_Dat_t * pCnf; int nFinal, * pFinal; Abc_Cex_t * pCexCare; Gia_Man_t * pFrames; // CEX minimization clk = Abc_Clock(); pCexCare = Bmc_CexCareMinimizeAig( p, Gia_ManPiNum(p), pCex, 1, 1, 1 ); for ( i = pCexCare->nRegs; i < pCexCare->nBits; i++ ) Counter += Abc_InfoHasBit(pCexCare->pData, i); Abc_CexFree( pCexCare ); printf( "Care bits = %d. ", Counter ); Abc_PrintTime( 1, "CEX minimization", Abc_Clock() - clk ); // SAT instance clk = Abc_Clock(); pFrames = Gia_ManFramesForCexMin( p, pCex->iFrame + 1 ); pCnf = (Cnf_Dat_t*)Mf_ManGenerateCnf( pFrames, 8, 0, 0, 0, 0 ); iFirstVar = pCnf->nVars - (pCex->iFrame+1) * pCex->nPis; pSat = (sat_solver*)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); iLit = Abc_Var2Lit( 1, 1 ); status = sat_solver_addclause( pSat, &iLit, &iLit + 1 ); assert( status ); // create literals vLits = Vec_IntAlloc( 100 ); for ( i = pCex->nRegs; i < pCex->nBits; i++ ) Vec_IntPush( vLits, Abc_Var2Lit(iFirstVar + i - pCex->nRegs, !Abc_InfoHasBit(pCex->pData, i)) ); Abc_PrintTime( 1, "SAT solver", Abc_Clock() - clk ); for ( n = 0; n < 2; n++ ) { if ( n ) Vec_IntReverseOrder( vLits ); // SAT-based minimization clk = Abc_Clock(); status = sat_solver_solve( pSat, Vec_IntArray(vLits), Vec_IntLimit(vLits), 0, 0, 0, 0 ); nFinal = sat_solver_final( pSat, &pFinal ); printf( "Status %d. Selected %d assumptions out of %d. ", status, nFinal, Vec_IntSize(vLits) ); Abc_PrintTime( 1, "Analyze_final", Abc_Clock() - clk ); // SAT-based minimization clk = Abc_Clock(); nFinal = sat_solver_minimize_assumptions( pSat, Vec_IntArray(vLits), Vec_IntSize(vLits), 0 ); printf( "Status %d. Selected %d assumptions out of %d. ", status, nFinal, Vec_IntSize(vLits) ); Abc_PrintTime( 1, "LEXUNSAT", Abc_Clock() - clk ); } // cleanup Vec_IntFree( vLits ); sat_solver_delete( pSat ); Cnf_DataFree( pCnf ); Gia_ManStop( pFrames ); } Abc_Cex_t * Bmc_CexCareDeriveCex( Abc_Cex_t * pCex, int iFirstVar, int * pLits, int nLits ) { Abc_Cex_t * pCexMin; int i; pCexMin = Abc_CexAlloc( pCex->nRegs, pCex->nPis, pCex->iFrame + 1 ); pCexMin->iPo = pCex->iPo; pCexMin->iFrame = pCex->iFrame; for ( i = 0; i < nLits; i++ ) { int PiNum = Abc_Lit2Var(pLits[i]) - iFirstVar; assert( PiNum >= 0 && PiNum < pCex->nBits - pCex->nRegs ); Abc_InfoSetBit( pCexMin->pData, pCexMin->nRegs + PiNum ); } return pCexMin; } Abc_Cex_t * Bmc_CexCareSatBasedMinimizeAig( Gia_Man_t * p, Abc_Cex_t * pCex, int fHighEffort, int fVerbose ) { abctime clk = Abc_Clock(); int n, i, iFirstVar, iLit, status; Vec_Int_t * vLits = NULL, * vTemp; sat_solver * pSat; Cnf_Dat_t * pCnf; int nFinal, * pFinal; Abc_Cex_t * pCexBest = NULL; int CountBest = 0; Gia_Man_t * pFrames; // CEX minimization clk = Abc_Clock(); pCexBest = Bmc_CexCareMinimizeAig( p, Gia_ManPiNum(p), pCex, 1, 1, fVerbose ); for ( i = pCexBest->nRegs; i < pCexBest->nBits; i++ ) CountBest += Abc_InfoHasBit(pCexBest->pData, i); if ( fVerbose ) { printf( "Care bits = %d. ", CountBest ); Abc_PrintTime( 1, "Non-SAT-based CEX minimization", Abc_Clock() - clk ); } // SAT instance clk = Abc_Clock(); pFrames = Gia_ManFramesForCexMin( p, pCex->iFrame + 1 ); pCnf = (Cnf_Dat_t*)Mf_ManGenerateCnf( pFrames, 8, 0, 0, 0, 0 ); iFirstVar = pCnf->nVars - (pCex->iFrame+1) * pCex->nPis; pSat = (sat_solver*)Cnf_DataWriteIntoSolver( pCnf, 1, 0 ); iLit = Abc_Var2Lit( 1, 1 ); status = sat_solver_addclause( pSat, &iLit, &iLit + 1 ); assert( status ); // create literals vTemp = Vec_IntAlloc( 100 ); for ( i = pCex->nRegs; i < pCex->nBits; i++ ) Vec_IntPush( vTemp, Abc_Var2Lit(iFirstVar + i - pCex->nRegs, !Abc_InfoHasBit(pCex->pData, i)) ); if ( fVerbose ) Abc_PrintTime( 1, "Constructing SAT solver", Abc_Clock() - clk ); for ( n = 0; n < 2; n++ ) { Vec_IntFreeP( &vLits ); vLits = Vec_IntDup( vTemp ); if ( n ) Vec_IntReverseOrder( vLits ); // SAT-based minimization clk = Abc_Clock(); status = sat_solver_solve( pSat, Vec_IntArray(vLits), Vec_IntLimit(vLits), 0, 0, 0, 0 ); nFinal = sat_solver_final( pSat, &pFinal ); if ( fVerbose ) { printf( "Status %s Selected %5d assumptions out of %5d. ", status == l_False ? "OK ":"BUG", nFinal, Vec_IntSize(vLits) ); Abc_PrintTime( 1, "Analyze_final", Abc_Clock() - clk ); } if ( CountBest > nFinal ) { CountBest = nFinal; ABC_FREE( pCexBest ); pCexBest = Bmc_CexCareDeriveCex( pCex, iFirstVar, pFinal, nFinal ); } if ( !fHighEffort ) continue; // SAT-based minimization clk = Abc_Clock(); nFinal = sat_solver_minimize_assumptions( pSat, Vec_IntArray(vLits), Vec_IntSize(vLits), 0 ); if ( fVerbose ) { printf( "Status %s Selected %5d assumptions out of %5d. ", status == l_False ? "OK ":"BUG", nFinal, Vec_IntSize(vLits) ); Abc_PrintTime( 1, "LEXUNSAT ", Abc_Clock() - clk ); } if ( CountBest > nFinal ) { CountBest = nFinal; ABC_FREE( pCexBest ); pCexBest = Bmc_CexCareDeriveCex( pCex, iFirstVar, Vec_IntArray(vLits), nFinal ); } } if ( fVerbose ) { printf( "Final : " ); Bmc_CexPrint( pCexBest, pCexBest->nPis, 0 ); } // cleanup Vec_IntFreeP( &vLits ); Vec_IntFreeP( &vTemp ); sat_solver_delete( pSat ); Cnf_DataFree( pCnf ); Gia_ManStop( pFrames ); return pCexBest; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END