/**CFile**************************************************************** FileName [satProof.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [SAT solver.] Synopsis [Proof manipulation procedures.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: satProof.c,v 1.4 2005/09/16 22:55:03 casem Exp $] ***********************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include "misc/vec/vec.h" #include "misc/vec/vecSet.h" #include "aig/aig/aig.h" #include "satTruth.h" ABC_NAMESPACE_IMPL_START /* Proof is represented as a vector of records. A resolution record is represented by a handle (an offset in this vector). A resolution record entry is <size><label><ant1><ant2>...<antN> Label is initialized to 0. Root clauses are given by their handles. They are marked by bitshifting by 2 bits up and setting the LSB to 1 */ typedef struct satset_t satset; struct satset_t { unsigned learnt : 1; unsigned mark : 1; unsigned partA : 1; unsigned nEnts : 29; int Id; int pEnts[0]; }; //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// //static inline satset* Proof_ClauseRead ( Vec_Int_t* p, int h ) { assert( h > 0 ); return satset_read( (veci *)p, h ); } //static inline satset* Proof_ClauseRead ( Vec_Int_t* p, int h ) { assert( h > 0 ); return (satset *)Vec_IntEntryP( p, h );} static inline satset* Proof_NodeRead ( Vec_Set_t* p, int h ) { assert( h > 0 ); return (satset*)Vec_SetEntry( p, h ); } static inline int Proof_NodeWordNum ( int nEnts ) { assert( nEnts > 0 ); return 1 + ((nEnts + 1) >> 1); } void Proof_ClauseSetEnts( Vec_Set_t* p, int h, int nEnts ) { Proof_NodeRead(p, h)->nEnts = nEnts; } // iterating through nodes in the proof #define Proof_ForeachClauseVec( pVec, p, pNode, i ) \ for ( i = 0; (i < Vec_IntSize(pVec)) && ((pNode) = Proof_ClauseRead(p, Vec_IntEntry(pVec,i))); i++ ) #define Proof_ForeachNodeVec( pVec, p, pNode, i ) \ for ( i = 0; (i < Vec_IntSize(pVec)) && ((pNode) = Proof_NodeRead(p, Vec_IntEntry(pVec,i))); i++ ) #define Proof_ForeachNodeVec1( pVec, p, pNode, i ) \ for ( i = 1; (i < Vec_IntSize(pVec)) && ((pNode) = Proof_NodeRead(p, Vec_IntEntry(pVec,i))); i++ ) // iterating through fanins of a proof node #define Proof_NodeForeachFanin( pProof, pNode, pFanin, i ) \ for ( i = 0; (i < (int)pNode->nEnts) && (((pFanin) = (pNode->pEnts[i] & 1) ? NULL : Proof_NodeRead(pProof, pNode->pEnts[i] >> 2)), 1); i++ ) /* #define Proof_NodeForeachLeaf( pClauses, pNode, pLeaf, i ) \ for ( i = 0; (i < (int)pNode->nEnts) && (((pLeaf) = (pNode->pEnts[i] & 1) ? Proof_ClauseRead(pClauses, pNode->pEnts[i] >> 2) : NULL), 1); i++ ) #define Proof_NodeForeachFaninLeaf( pProof, pClauses, pNode, pFanin, i ) \ for ( i = 0; (i < (int)pNode->nEnts) && ((pFanin) = (pNode->pEnts[i] & 1) ? Proof_ClauseRead(pClauses, pNode->pEnts[i] >> 2) : Proof_NodeRead(pProof, pNode->pEnts[i] >> 2)); i++ ) */ //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Cleans collected resultion nodes belonging to the proof.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Proof_CleanCollected( Vec_Set_t * vProof, Vec_Int_t * vUsed ) { satset * pNode; int hNode; Proof_ForeachNodeVec( vUsed, vProof, pNode, hNode ) pNode->Id = 0; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Proof_CollectUsed_iter( Vec_Set_t * vProof, int hNode, Vec_Int_t * vUsed, Vec_Int_t * vStack ) { satset * pNext, * pNode = Proof_NodeRead( vProof, hNode ); int i; if ( pNode->Id ) return; // start with node pNode->Id = 1; Vec_IntPush( vStack, hNode << 1 ); // perform DFS search while ( Vec_IntSize(vStack) ) { hNode = Vec_IntPop( vStack ); if ( hNode & 1 ) // extracted second time { Vec_IntPush( vUsed, hNode >> 1 ); continue; } // extracted first time Vec_IntPush( vStack, hNode ^ 1 ); // add second time // add its anticedents ; pNode = Proof_NodeRead( vProof, hNode >> 1 ); Proof_NodeForeachFanin( vProof, pNode, pNext, i ) if ( pNext && !pNext->Id ) { pNext->Id = 1; Vec_IntPush( vStack, (pNode->pEnts[i] >> 2) << 1 ); // add first time } } } Vec_Int_t * Proof_CollectUsedIter( Vec_Set_t * vProof, Vec_Int_t * vRoots, int fSort ) { int fVerify = 0; Vec_Int_t * vUsed, * vStack; abctime clk = Abc_Clock(); int i, Entry, iPrev = 0; vUsed = Vec_IntAlloc( 1000 ); vStack = Vec_IntAlloc( 1000 ); Vec_IntForEachEntry( vRoots, Entry, i ) if ( Entry >= 0 ) Proof_CollectUsed_iter( vProof, Entry, vUsed, vStack ); Vec_IntFree( vStack ); // Abc_PrintTime( 1, "Iterative clause collection time", Abc_Clock() - clk ); clk = Abc_Clock(); Abc_MergeSort( Vec_IntArray(vUsed), Vec_IntSize(vUsed) ); // Abc_PrintTime( 1, "Postprocessing with sorting time", Abc_Clock() - clk ); // verify topological order if ( fVerify ) { iPrev = 0; Vec_IntForEachEntry( vUsed, Entry, i ) { if ( iPrev >= Entry ) printf( "Out of topological order!!!\n" ); assert( iPrev < Entry ); iPrev = Entry; } } return vUsed; } /**Function************************************************************* Synopsis [Recursively collects useful proof nodes.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Proof_CollectUsed_rec( Vec_Set_t * vProof, int hNode, Vec_Int_t * vUsed ) { satset * pNext, * pNode = Proof_NodeRead( vProof, hNode ); int i; if ( pNode->Id ) return; pNode->Id = 1; Proof_NodeForeachFanin( vProof, pNode, pNext, i ) if ( pNext && !pNext->Id ) Proof_CollectUsed_rec( vProof, pNode->pEnts[i] >> 2, vUsed ); Vec_IntPush( vUsed, hNode ); } Vec_Int_t * Proof_CollectUsedRec( Vec_Set_t * vProof, Vec_Int_t * vRoots ) { Vec_Int_t * vUsed; int i, Entry; vUsed = Vec_IntAlloc( 1000 ); Vec_IntForEachEntry( vRoots, Entry, i ) if ( Entry >= 0 ) Proof_CollectUsed_rec( vProof, Entry, vUsed ); return vUsed; } /**Function************************************************************* Synopsis [Recursively visits useful proof nodes.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Proof_MarkUsed_rec( Vec_Set_t * vProof, int hNode ) { satset * pNext, * pNode = Proof_NodeRead( vProof, hNode ); int i, Counter = 1; if ( pNode->Id ) return 0; pNode->Id = 1; Proof_NodeForeachFanin( vProof, pNode, pNext, i ) if ( pNext && !pNext->Id ) Counter += Proof_MarkUsed_rec( vProof, pNode->pEnts[i] >> 2 ); return Counter; } int Proof_MarkUsedRec( Vec_Set_t * vProof, Vec_Int_t * vRoots ) { int i, Entry, Counter = 0; Vec_IntForEachEntry( vRoots, Entry, i ) if ( Entry >= 0 ) Counter += Proof_MarkUsed_rec( vProof, Entry ); return Counter; } /**Function************************************************************* Synopsis [Checks the validity of the check point.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ /* void Sat_ProofReduceCheck_rec( Vec_Set_t * vProof, Vec_Int_t * vClauses, satset * pNode, int hClausePivot, Vec_Ptr_t * vVisited ) { satset * pFanin; int k; if ( pNode->Id ) return; pNode->Id = -1; Proof_NodeForeachFaninLeaf( vProof, vClauses, pNode, pFanin, k ) if ( (pNode->pEnts[k] & 1) == 0 ) // proof node Sat_ProofReduceCheck_rec( vProof, vClauses, pFanin, hClausePivot, vVisited ); else // problem clause assert( (pNode->pEnts[k] >> 2) < hClausePivot ); Vec_PtrPush( vVisited, pNode ); } void Sat_ProofReduceCheckOne( sat_solver2 * s, int iLearnt, Vec_Ptr_t * vVisited ) { Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; Vec_Int_t * vRoots = (Vec_Int_t *)&s->claProofs; int hProofNode = Vec_IntEntry( vRoots, iLearnt ); satset * pNode = Proof_NodeRead( vProof, hProofNode ); Sat_ProofReduceCheck_rec( vProof, vClauses, pNode, s->hClausePivot, vVisited ); } void Sat_ProofReduceCheck( sat_solver2 * s ) { Vec_Ptr_t * vVisited; satset * c; int h, i = 1; vVisited = Vec_PtrAlloc( 1000 ); sat_solver_foreach_learnt( s, c, h ) if ( h < s->hLearntPivot ) Sat_ProofReduceCheckOne( s, i++, vVisited ); Vec_PtrForEachEntry( satset *, vVisited, c, i ) c->Id = 0; Vec_PtrFree( vVisited ); } */ /**Function************************************************************* Synopsis [Reduces the proof to contain only roots and their children.] Description [The result is updated proof and updated roots.] SideEffects [] SeeAlso [] ***********************************************************************/ /* void Sat_ProofReduce2( sat_solver2 * s ) { Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; Vec_Int_t * vRoots = (Vec_Int_t *)&s->claProofs; Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; int fVerbose = 0; Vec_Int_t * vUsed; satset * pNode, * pFanin, * pPivot; int i, k, hTemp; abctime clk = Abc_Clock(); static abctime TimeTotal = 0; // collect visited nodes vUsed = Proof_CollectUsedIter( vProof, vRoots, 1 ); // relabel nodes to use smaller space Vec_SetShrinkS( vProof, 2 ); Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) { pNode->Id = Vec_SetAppendS( vProof, 2+pNode->nEnts ); Proof_NodeForeachFaninLeaf( vProof, vClauses, pNode, pFanin, k ) if ( (pNode->pEnts[k] & 1) == 0 ) // proof node pNode->pEnts[k] = (pFanin->Id << 2) | (pNode->pEnts[k] & 2); else // problem clause assert( (int*)pFanin >= Vec_IntArray(vClauses) && (int*)pFanin < Vec_IntArray(vClauses)+Vec_IntSize(vClauses) ); } // update roots Proof_ForeachNodeVec1( vRoots, vProof, pNode, i ) Vec_IntWriteEntry( vRoots, i, pNode->Id ); // determine new pivot assert( s->hProofPivot >= 1 && s->hProofPivot <= Vec_SetHandCurrent(vProof) ); pPivot = Proof_NodeRead( vProof, s->hProofPivot ); s->hProofPivot = Vec_SetHandCurrentS(vProof); // compact the nodes Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) { hTemp = pNode->Id; pNode->Id = 0; memmove( Vec_SetEntry(vProof, hTemp), pNode, sizeof(word)*Proof_NodeWordNum(pNode->nEnts) ); if ( pPivot && pPivot <= pNode ) { s->hProofPivot = hTemp; pPivot = NULL; } } Vec_SetWriteEntryNum( vProof, Vec_IntSize(vUsed) ); Vec_IntFree( vUsed ); // report the result if ( fVerbose ) { printf( "\n" ); printf( "The proof was reduced from %6.2f MB to %6.2f MB (by %6.2f %%) ", 1.0 * Vec_SetMemory(vProof) / (1<<20), 1.0 * Vec_SetMemoryS(vProof) / (1<<20), 100.0 * (Vec_SetMemory(vProof) - Vec_SetMemoryS(vProof)) / Vec_SetMemory(vProof) ); TimeTotal += Abc_Clock() - clk; Abc_PrintTime( 1, "Time", TimeTotal ); } Vec_SetShrink( vProof, Vec_SetHandCurrentS(vProof) ); // Sat_ProofReduceCheck( s ); } */ void Sat_ProofCheck0( Vec_Set_t * vProof ) { satset * pNode, * pFanin; int i, j, k, nSize; Vec_SetForEachEntry( satset *, vProof, nSize, pNode, i, j ) { nSize = Vec_SetWordNum( 2 + pNode->nEnts ); Proof_NodeForeachFanin( vProof, pNode, pFanin, k ) assert( (pNode->pEnts[k] >> 2) ); } } int Sat_ProofReduce( Vec_Set_t * vProof, void * pRoots, int hProofPivot ) { // Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; // Vec_Int_t * vRoots = (Vec_Int_t *)&s->claProofs; Vec_Int_t * vRoots = (Vec_Int_t *)pRoots; // Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; int fVerbose = 0; Vec_Ptr_t * vUsed; satset * pNode, * pFanin, * pPivot; int i, j, k, hTemp, nSize; abctime clk = Abc_Clock(); static abctime TimeTotal = 0; int RetValue; //Sat_ProofCheck0( vProof ); // collect visited nodes nSize = Proof_MarkUsedRec( vProof, vRoots ); vUsed = Vec_PtrAlloc( nSize ); //Sat_ProofCheck0( vProof ); // relabel nodes to use smaller space Vec_SetShrinkS( vProof, 2 ); Vec_SetForEachEntry( satset *, vProof, nSize, pNode, i, j ) { nSize = Vec_SetWordNum( 2 + pNode->nEnts ); if ( pNode->Id == 0 ) continue; pNode->Id = Vec_SetAppendS( vProof, 2 + pNode->nEnts ); assert( pNode->Id > 0 ); Vec_PtrPush( vUsed, pNode ); // update fanins Proof_NodeForeachFanin( vProof, pNode, pFanin, k ) if ( (pNode->pEnts[k] & 1) == 0 ) // proof node { assert( pFanin->Id > 0 ); pNode->pEnts[k] = (pFanin->Id << 2) | (pNode->pEnts[k] & 2); } // else // problem clause // assert( (int*)pFanin >= Vec_IntArray(vClauses) && (int*)pFanin < Vec_IntArray(vClauses)+Vec_IntSize(vClauses) ); } // update roots Proof_ForeachNodeVec1( vRoots, vProof, pNode, i ) Vec_IntWriteEntry( vRoots, i, pNode->Id ); // determine new pivot assert( hProofPivot >= 1 && hProofPivot <= Vec_SetHandCurrent(vProof) ); pPivot = Proof_NodeRead( vProof, hProofPivot ); RetValue = Vec_SetHandCurrentS(vProof); // compact the nodes Vec_PtrForEachEntry( satset *, vUsed, pNode, i ) { hTemp = pNode->Id; pNode->Id = 0; memmove( Vec_SetEntry(vProof, hTemp), pNode, sizeof(word)*Proof_NodeWordNum(pNode->nEnts) ); if ( pPivot && pPivot <= pNode ) { RetValue = hTemp; pPivot = NULL; } } Vec_SetWriteEntryNum( vProof, Vec_PtrSize(vUsed) ); Vec_PtrFree( vUsed ); // report the result if ( fVerbose ) { printf( "\n" ); printf( "The proof was reduced from %6.2f MB to %6.2f MB (by %6.2f %%) ", 1.0 * Vec_SetMemory(vProof) / (1<<20), 1.0 * Vec_SetMemoryS(vProof) / (1<<20), 100.0 * (Vec_SetMemory(vProof) - Vec_SetMemoryS(vProof)) / Vec_SetMemory(vProof) ); TimeTotal += Abc_Clock() - clk; Abc_PrintTime( 1, "Time", TimeTotal ); } Vec_SetShrink( vProof, Vec_SetHandCurrentS(vProof) ); Vec_SetShrinkLimits( vProof ); // Sat_ProofReduceCheck( s ); //Sat_ProofCheck0( vProof ); return RetValue; } #if 0 /**Function************************************************************* Synopsis [Performs one resultion step.] Description [Returns ID of the resolvent if success, and -1 if failure.] SideEffects [] SeeAlso [] ***********************************************************************/ int Sat_ProofCheckResolveOne( Vec_Set_t * p, satset * c1, satset * c2, Vec_Int_t * vTemp ) { satset * c; int h, i, k, Var = -1, Count = 0; // find resolution variable for ( i = 0; i < (int)c1->nEnts; i++ ) for ( k = 0; k < (int)c2->nEnts; k++ ) if ( (c1->pEnts[i] ^ c2->pEnts[k]) == 1 ) { Var = (c1->pEnts[i] >> 1); Count++; } if ( Count == 0 ) { printf( "Cannot find resolution variable\n" ); return 0; } if ( Count > 1 ) { printf( "Found more than 1 resolution variables\n" ); return 0; } // perform resolution Vec_IntClear( vTemp ); Vec_IntPush( vTemp, 0 ); // placeholder Vec_IntPush( vTemp, 0 ); for ( i = 0; i < (int)c1->nEnts; i++ ) if ( (c1->pEnts[i] >> 1) != Var ) Vec_IntPush( vTemp, c1->pEnts[i] ); for ( i = 0; i < (int)c2->nEnts; i++ ) if ( (c2->pEnts[i] >> 1) != Var ) Vec_IntPushUnique( vTemp, c2->pEnts[i] ); // create new resolution entry h = Vec_SetAppend( p, Vec_IntArray(vTemp), Vec_IntSize(vTemp) ); // return the new entry c = Proof_NodeRead( p, h ); c->nEnts = Vec_IntSize(vTemp)-2; return h; } /**Function************************************************************* Synopsis [Checks the proof for consitency.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ satset * Sat_ProofCheckReadOne( Vec_Int_t * vClauses, Vec_Set_t * vProof, Vec_Set_t * vResolves, int iAnt ) { satset * pAnt; if ( iAnt & 1 ) return Proof_ClauseRead( vClauses, iAnt >> 2 ); assert( iAnt > 0 ); pAnt = Proof_NodeRead( vProof, iAnt >> 2 ); assert( pAnt->Id > 0 ); return Proof_NodeRead( vResolves, pAnt->Id ); } /**Function************************************************************* Synopsis [Checks the proof for consitency.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Sat_ProofCheck( sat_solver2 * s ) { Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; Vec_Int_t Roots = { 1, 1, &s->hProofLast }, * vRoots = &Roots; Vec_Set_t * vResolves; Vec_Int_t * vUsed, * vTemp; satset * pSet, * pSet0 = NULL, * pSet1; int i, k, hRoot, Handle, Counter = 0; abctime clk = Abc_Clock(); hRoot = s->hProofLast; if ( hRoot == -1 ) return; // collect visited clauses vUsed = Proof_CollectUsedIter( vProof, vRoots, 1 ); Proof_CleanCollected( vProof, vUsed ); // perform resolution steps vTemp = Vec_IntAlloc( 1000 ); vResolves = Vec_SetAlloc( 20 ); Proof_ForeachNodeVec( vUsed, vProof, pSet, i ) { Handle = -1; pSet0 = Sat_ProofCheckReadOne( vClauses, vProof, vResolves, pSet->pEnts[0] ); for ( k = 1; k < (int)pSet->nEnts; k++ ) { pSet1 = Sat_ProofCheckReadOne( vClauses, vProof, vResolves, pSet->pEnts[k] ); Handle = Sat_ProofCheckResolveOne( vResolves, pSet0, pSet1, vTemp ); pSet0 = Proof_NodeRead( vResolves, Handle ); } pSet->Id = Handle; Counter++; } Vec_IntFree( vTemp ); // clean the proof Proof_CleanCollected( vProof, vUsed ); // compare the final clause printf( "Used %6.2f MB for resolvents.\n", 1.0 * Vec_SetMemory(vResolves) / (1<<20) ); if ( pSet0->nEnts > 0 ) printf( "Derived clause with %d lits instead of the empty clause. ", pSet0->nEnts ); else printf( "Proof verification successful. " ); Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); // cleanup Vec_SetFree( vResolves ); Vec_IntFree( vUsed ); } #endif /**Function************************************************************* Synopsis [Collects nodes belonging to the UNSAT core.] Description [The resulting array contains 1-based IDs of root clauses.] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Sat_ProofCollectCore( Vec_Set_t * vProof, Vec_Int_t * vUsed ) { Vec_Int_t * vCore; satset * pNode, * pFanin; unsigned * pBitMap; int i, k, MaxCla = 0; // find the largest number Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) Proof_NodeForeachFanin( vProof, pNode, pFanin, k ) if ( pFanin == NULL ) MaxCla = Abc_MaxInt( MaxCla, pNode->pEnts[k] >> 2 ); // allocate bitmap pBitMap = ABC_CALLOC( unsigned, Abc_BitWordNum(MaxCla) + 1 ); // collect leaves vCore = Vec_IntAlloc( 1000 ); Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) Proof_NodeForeachFanin( vProof, pNode, pFanin, k ) if ( pFanin == NULL ) { int Entry = (pNode->pEnts[k] >> 2); if ( Abc_InfoHasBit(pBitMap, Entry) ) continue; Abc_InfoSetBit(pBitMap, Entry); Vec_IntPush( vCore, Entry ); } ABC_FREE( pBitMap ); // Vec_IntUniqify( vCore ); return vCore; } #if 0 /**Function************************************************************* Synopsis [Verifies that variables are labeled correctly.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Sat_ProofInterpolantCheckVars( sat_solver2 * s, Vec_Int_t * vGloVars ) { satset* c; Vec_Int_t * vVarMap; int i, k, Entry, * pMask; int Counts[5] = {0}; // map variables into their type (A, B, or AB) vVarMap = Vec_IntStart( s->size ); sat_solver_foreach_clause( s, c, i ) for ( k = 0; k < (int)c->nEnts; k++ ) *Vec_IntEntryP(vVarMap, lit_var(c->pEnts[k])) |= 2 - c->partA; // analyze variables Vec_IntForEachEntry( vGloVars, Entry, i ) { pMask = Vec_IntEntryP(vVarMap, Entry); assert( *pMask >= 0 && *pMask <= 3 ); Counts[(*pMask & 3)]++; *pMask = 0; } // count the number of global variables not listed Vec_IntForEachEntry( vVarMap, Entry, i ) if ( Entry == 3 ) Counts[4]++; Vec_IntFree( vVarMap ); // report if ( Counts[0] ) printf( "Warning: %6d variables listed as global do not appear in clauses (this is normal)\n", Counts[0] ); if ( Counts[1] ) printf( "Warning: %6d variables listed as global appear only in A-clauses (this is a BUG)\n", Counts[1] ); if ( Counts[2] ) printf( "Warning: %6d variables listed as global appear only in B-clauses (this is a BUG)\n", Counts[2] ); if ( Counts[3] ) printf( "Warning: %6d (out of %d) variables listed as global appear in both A- and B-clauses (this is normal)\n", Counts[3], Vec_IntSize(vGloVars) ); if ( Counts[4] ) printf( "Warning: %6d variables not listed as global appear in both A- and B-clauses (this is a BUG)\n", Counts[4] ); } /**Function************************************************************* Synopsis [Computes interpolant of the proof.] Description [Aassuming that vars/clause of partA are marked.] SideEffects [] SeeAlso [] ***********************************************************************/ void * Sat_ProofInterpolant( sat_solver2 * s, void * pGloVars ) { Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; Vec_Int_t * vGlobVars = (Vec_Int_t *)pGloVars; Vec_Int_t Roots = { 1, 1, &s->hProofLast }, * vRoots = &Roots; Vec_Int_t * vUsed, * vCore, * vCoreNums, * vVarMap; satset * pNode, * pFanin; Aig_Man_t * pAig; Aig_Obj_t * pObj = NULL; int i, k, iVar, Lit, Entry, hRoot; // if ( s->hLearntLast < 0 ) // return NULL; // hRoot = veci_begin(&s->claProofs)[satset_read(&s->learnts, s->hLearntLast>>1)->Id]; hRoot = s->hProofLast; if ( hRoot == -1 ) return NULL; Sat_ProofInterpolantCheckVars( s, vGlobVars ); // collect visited nodes vUsed = Proof_CollectUsedIter( vProof, vRoots, 1 ); // collect core clauses (cleans vUsed and vCore) vCore = Sat_ProofCollectCore( vProof, vUsed ); // vCore arrived in terms of clause handles // map variables into their global numbers vVarMap = Vec_IntStartFull( s->size ); Vec_IntForEachEntry( vGlobVars, Entry, i ) Vec_IntWriteEntry( vVarMap, Entry, i ); // start the AIG pAig = Aig_ManStart( 10000 ); pAig->pName = Abc_UtilStrsav( "interpol" ); for ( i = 0; i < Vec_IntSize(vGlobVars); i++ ) Aig_ObjCreateCi( pAig ); // copy the numbers out and derive interpol for clause vCoreNums = Vec_IntAlloc( Vec_IntSize(vCore) ); Proof_ForeachClauseVec( vCore, vClauses, pNode, i ) { if ( pNode->partA ) { pObj = Aig_ManConst0( pAig ); satset_foreach_lit( pNode, Lit, k, 0 ) if ( (iVar = Vec_IntEntry(vVarMap, lit_var(Lit))) >= 0 ) pObj = Aig_Or( pAig, pObj, Aig_NotCond(Aig_IthVar(pAig, iVar), lit_sign(Lit)) ); } else pObj = Aig_ManConst1( pAig ); // remember the interpolant Vec_IntPush( vCoreNums, pNode->Id ); pNode->Id = Aig_ObjToLit(pObj); } Vec_IntFree( vVarMap ); // copy the numbers out and derive interpol for resolvents Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) { // satset_print( pNode ); assert( pNode->nEnts > 1 ); Proof_NodeForeachFaninLeaf( vProof, vClauses, pNode, pFanin, k ) { assert( pFanin->Id < 2*Aig_ManObjNumMax(pAig) ); if ( k == 0 ) pObj = Aig_ObjFromLit( pAig, pFanin->Id ); else if ( pNode->pEnts[k] & 2 ) // variable of A pObj = Aig_Or( pAig, pObj, Aig_ObjFromLit(pAig, pFanin->Id) ); else pObj = Aig_And( pAig, pObj, Aig_ObjFromLit(pAig, pFanin->Id) ); } // remember the interpolant pNode->Id = Aig_ObjToLit(pObj); } // save the result // assert( Proof_NodeHandle(vProof, pNode) == hRoot ); Aig_ObjCreateCo( pAig, pObj ); Aig_ManCleanup( pAig ); // move the results back Proof_ForeachClauseVec( vCore, vClauses, pNode, i ) pNode->Id = Vec_IntEntry( vCoreNums, i ); Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) pNode->Id = 0; // cleanup Vec_IntFree( vCore ); Vec_IntFree( vUsed ); Vec_IntFree( vCoreNums ); return pAig; } /**Function************************************************************* Synopsis [Computes interpolant of the proof.] Description [Aassuming that vars/clause of partA are marked.] SideEffects [] SeeAlso [] ***********************************************************************/ word * Sat_ProofInterpolantTruth( sat_solver2 * s, void * pGloVars ) { Vec_Int_t * vClauses = (Vec_Int_t *)&s->clauses; Vec_Set_t * vProof = (Vec_Set_t *)&s->Proofs; Vec_Int_t * vGlobVars = (Vec_Int_t *)pGloVars; Vec_Int_t Roots = { 1, 1, &s->hProofLast }, * vRoots = &Roots; Vec_Int_t * vUsed, * vCore, * vCoreNums, * vVarMap; satset * pNode, * pFanin; Tru_Man_t * pTru; int nVars = Vec_IntSize(vGlobVars); int nWords = (nVars < 6) ? 1 : (1 << (nVars-6)); word * pRes = ABC_ALLOC( word, nWords ); int i, k, iVar, Lit, Entry, hRoot; assert( nVars > 0 && nVars <= 16 ); hRoot = s->hProofLast; if ( hRoot == -1 ) return NULL; Sat_ProofInterpolantCheckVars( s, vGlobVars ); // collect visited nodes vUsed = Proof_CollectUsedIter( vProof, vRoots, 1 ); // collect core clauses (cleans vUsed and vCore) vCore = Sat_ProofCollectCore( vProof, vUsed, 0 ); // vCore arrived in terms of clause handles // map variables into their global numbers vVarMap = Vec_IntStartFull( s->size ); Vec_IntForEachEntry( vGlobVars, Entry, i ) Vec_IntWriteEntry( vVarMap, Entry, i ); // start the AIG pTru = Tru_ManAlloc( nVars ); // copy the numbers out and derive interpol for clause vCoreNums = Vec_IntAlloc( Vec_IntSize(vCore) ); Proof_ForeachClauseVec( vCore, vClauses, pNode, i ) { if ( pNode->partA ) { // pObj = Aig_ManConst0( pAig ); Tru_ManClear( pRes, nWords ); satset_foreach_lit( pNode, Lit, k, 0 ) if ( (iVar = Vec_IntEntry(vVarMap, lit_var(Lit))) >= 0 ) // pObj = Aig_Or( pAig, pObj, Aig_NotCond(Aig_IthVar(pAig, iVar), lit_sign(Lit)) ); pRes = Tru_ManOrNotCond( pRes, Tru_ManVar(pTru, iVar), nWords, lit_sign(Lit) ); } else // pObj = Aig_ManConst1( pAig ); Tru_ManFill( pRes, nWords ); // remember the interpolant Vec_IntPush( vCoreNums, pNode->Id ); // pNode->Id = Aig_ObjToLit(pObj); pNode->Id = Tru_ManInsert( pTru, pRes ); } Vec_IntFree( vVarMap ); // copy the numbers out and derive interpol for resolvents Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) { // satset_print( pNode ); assert( pNode->nEnts > 1 ); Proof_NodeForeachFaninLeaf( vProof, vClauses, pNode, pFanin, k ) { // assert( pFanin->Id < 2*Aig_ManObjNumMax(pAig) ); // assert( pFanin->Id <= Tru_ManHandleMax(pTru) ); if ( k == 0 ) // pObj = Aig_ObjFromLit( pAig, pFanin->Id ); pRes = Tru_ManCopyNotCond( pRes, Tru_ManFunc(pTru, pFanin->Id & ~1), nWords, pFanin->Id & 1 ); else if ( pNode->pEnts[k] & 2 ) // variable of A // pObj = Aig_Or( pAig, pObj, Aig_ObjFromLit(pAig, pFanin->Id) ); pRes = Tru_ManOrNotCond( pRes, Tru_ManFunc(pTru, pFanin->Id & ~1), nWords, pFanin->Id & 1 ); else // pObj = Aig_And( pAig, pObj, Aig_ObjFromLit(pAig, pFanin->Id) ); pRes = Tru_ManAndNotCond( pRes, Tru_ManFunc(pTru, pFanin->Id & ~1), nWords, pFanin->Id & 1 ); } // remember the interpolant // pNode->Id = Aig_ObjToLit(pObj); pNode->Id = Tru_ManInsert( pTru, pRes ); } // save the result // assert( Proof_NodeHandle(vProof, pNode) == hRoot ); // Aig_ObjCreateCo( pAig, pObj ); // Aig_ManCleanup( pAig ); // move the results back Proof_ForeachClauseVec( vCore, vClauses, pNode, i ) pNode->Id = Vec_IntEntry( vCoreNums, i ); Proof_ForeachNodeVec( vUsed, vProof, pNode, i ) pNode->Id = 0; // cleanup Vec_IntFree( vCore ); Vec_IntFree( vUsed ); Vec_IntFree( vCoreNums ); Tru_ManFree( pTru ); // ABC_FREE( pRes ); return pRes; } #endif /**Function************************************************************* Synopsis [Computes UNSAT core.] Description [The result is the array of root clause indexes.] SideEffects [] SeeAlso [] ***********************************************************************/ void * Proof_DeriveCore( Vec_Set_t * vProof, int hRoot ) { Vec_Int_t Roots = { 1, 1, &hRoot }, * vRoots = &Roots; Vec_Int_t * vCore, * vUsed; if ( hRoot == -1 ) return NULL; // collect visited clauses vUsed = Proof_CollectUsedIter( vProof, vRoots, 0 ); // collect core clauses vCore = Sat_ProofCollectCore( vProof, vUsed ); Vec_IntFree( vUsed ); Vec_IntSort( vCore, 1 ); return vCore; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END