| /**CFile**************************************************************** |
| |
| FileName [pr.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Proof recording.] |
| |
| Synopsis [Core procedures of the package.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: pr.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <assert.h> |
| |
| #include "misc/util/abc_global.h" |
| #include "pr.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| typedef unsigned lit; |
| |
| typedef struct Pr_Cls_t_ Pr_Cls_t; |
| struct Pr_Cls_t_ |
| { |
| unsigned uTruth; // interpolant |
| void * pProof; // the proof node |
| // void * pAntis; // the anticedents |
| Pr_Cls_t * pNext; // the next clause |
| Pr_Cls_t * pNext0; // the next 0-watch |
| Pr_Cls_t * pNext1; // the next 0-watch |
| int Id; // the clause ID |
| unsigned fA : 1; // belongs to A |
| unsigned fRoot : 1; // original clause |
| unsigned fVisit : 1; // visited clause |
| unsigned nLits : 24; // the number of literals |
| lit pLits[0]; // literals of this clause |
| }; |
| |
| struct Pr_Man_t_ |
| { |
| // general data |
| int fProofWrite; // writes the proof file |
| int fProofVerif; // verifies the proof |
| int nVars; // the number of variables |
| int nVarsAB; // the number of global variables |
| int nRoots; // the number of root clauses |
| int nClauses; // the number of all clauses |
| int nClausesA; // the number of clauses of A |
| Pr_Cls_t * pHead; // the head clause |
| Pr_Cls_t * pTail; // the tail clause |
| Pr_Cls_t * pLearnt; // the tail clause |
| Pr_Cls_t * pEmpty; // the empty clause |
| // internal BCP |
| int nRootSize; // the number of root level assignments |
| int nTrailSize; // the number of assignments made |
| lit * pTrail; // chronological order of assignments (size nVars) |
| lit * pAssigns; // assignments by variable (size nVars) |
| char * pSeens; // temporary mark (size nVars) |
| char * pVarTypes; // variable type (size nVars) [1=A, 0=B, <0=AB] |
| Pr_Cls_t ** pReasons; // reasons for each assignment (size nVars) |
| Pr_Cls_t ** pWatches; // watched clauses for each literal (size 2*nVars) |
| int nVarsAlloc; // the allocated size of arrays |
| // proof recording |
| void * pManProof; // proof manager |
| int Counter; // counter of resolved clauses |
| // memory management |
| int nChunkSize; // the number of bytes in a chunk |
| int nChunkUsed; // the number of bytes used in the last chunk |
| char * pChunkLast; // the last memory chunk |
| // internal verification |
| lit * pResLits; // the literals of the resolvent |
| int nResLits; // the number of literals of the resolvent |
| int nResLitsAlloc;// the number of literals of the resolvent |
| // runtime stats |
| abctime timeBcp; |
| abctime timeTrace; |
| abctime timeRead; |
| abctime timeTotal; |
| }; |
| |
| // variable assignments |
| static const lit LIT_UNDEF = 0xffffffff; |
| |
| // variable/literal conversions (taken from MiniSat) |
| static inline lit toLit (int v) { return v + v; } |
| static inline lit toLitCond(int v, int c) { return v + v + (c != 0); } |
| static inline lit lit_neg (lit l) { return l ^ 1; } |
| static inline int lit_var (lit l) { return l >> 1; } |
| static inline int lit_sign (lit l) { return l & 1; } |
| static inline int lit_print(lit l) { return lit_sign(l)? -lit_var(l)-1 : lit_var(l)+1; } |
| static inline lit lit_read (int s) { return s > 0 ? toLit(s-1) : lit_neg(toLit(-s-1)); } |
| static inline int lit_check(lit l, int n) { return l >= 0 && lit_var(l) < n; } |
| |
| // iterators through the clauses |
| #define Pr_ManForEachClause( p, pCls ) for( pCls = p->pHead; pCls; pCls = pCls->pNext ) |
| #define Pr_ManForEachClauseRoot( p, pCls ) for( pCls = p->pHead; pCls != p->pLearnt; pCls = pCls->pNext ) |
| #define Pr_ManForEachClauseLearnt( p, pCls ) for( pCls = p->pLearnt; pCls; pCls = pCls->pNext ) |
| |
| // static procedures |
| static char * Pr_ManMemoryFetch( Pr_Man_t * p, int nBytes ); |
| static void Pr_ManMemoryStop( Pr_Man_t * p ); |
| static void Pr_ManResize( Pr_Man_t * p, int nVarsNew ); |
| |
| // exported procedures |
| extern Pr_Man_t * Pr_ManAlloc( int nVarsAlloc ); |
| extern void Pr_ManFree( Pr_Man_t * p ); |
| extern int Pr_ManAddClause( Pr_Man_t * p, lit * pBeg, lit * pEnd, int fRoot, int fClauseA ); |
| extern int Pr_ManProofWrite( Pr_Man_t * p ); |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Allocate proof manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Pr_Man_t * Pr_ManAlloc( int nVarsAlloc ) |
| { |
| Pr_Man_t * p; |
| // allocate the manager |
| p = (Pr_Man_t *)ABC_ALLOC( char, sizeof(Pr_Man_t) ); |
| memset( p, 0, sizeof(Pr_Man_t) ); |
| // allocate internal arrays |
| Pr_ManResize( p, nVarsAlloc? nVarsAlloc : 256 ); |
| // set the starting number of variables |
| p->nVars = 0; |
| // memory management |
| p->nChunkSize = (1<<16); // use 64K chunks |
| // verification |
| p->nResLitsAlloc = (1<<16); |
| p->pResLits = ABC_ALLOC( lit, p->nResLitsAlloc ); |
| // parameters |
| p->fProofWrite = 0; |
| p->fProofVerif = 0; |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Resize proof manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManResize( Pr_Man_t * p, int nVarsNew ) |
| { |
| // check if resizing is needed |
| if ( p->nVarsAlloc < nVarsNew ) |
| { |
| int nVarsAllocOld = p->nVarsAlloc; |
| // find the new size |
| if ( p->nVarsAlloc == 0 ) |
| p->nVarsAlloc = 1; |
| while ( p->nVarsAlloc < nVarsNew ) |
| p->nVarsAlloc *= 2; |
| // resize the arrays |
| p->pTrail = ABC_REALLOC(lit, p->pTrail, p->nVarsAlloc ); |
| p->pAssigns = ABC_REALLOC(lit, p->pAssigns, p->nVarsAlloc ); |
| p->pSeens = ABC_REALLOC(char, p->pSeens, p->nVarsAlloc ); |
| p->pVarTypes = ABC_REALLOC(char, p->pVarTypes, p->nVarsAlloc ); |
| p->pReasons = ABC_REALLOC(Pr_Cls_t *, p->pReasons, p->nVarsAlloc ); |
| p->pWatches = ABC_REALLOC(Pr_Cls_t *, p->pWatches, p->nVarsAlloc*2 ); |
| // clean the free space |
| memset( p->pAssigns + nVarsAllocOld, 0xff, sizeof(lit) * (p->nVarsAlloc - nVarsAllocOld) ); |
| memset( p->pSeens + nVarsAllocOld, 0, sizeof(char) * (p->nVarsAlloc - nVarsAllocOld) ); |
| memset( p->pVarTypes + nVarsAllocOld, 0, sizeof(char) * (p->nVarsAlloc - nVarsAllocOld) ); |
| memset( p->pReasons + nVarsAllocOld, 0, sizeof(Pr_Cls_t *) * (p->nVarsAlloc - nVarsAllocOld) ); |
| memset( p->pWatches + nVarsAllocOld, 0, sizeof(Pr_Cls_t *) * (p->nVarsAlloc - nVarsAllocOld)*2 ); |
| } |
| // adjust the number of variables |
| if ( p->nVars < nVarsNew ) |
| p->nVars = nVarsNew; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Deallocate proof manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManFree( Pr_Man_t * p ) |
| { |
| printf( "Runtime stats:\n" ); |
| ABC_PRT( "Reading ", p->timeRead ); |
| ABC_PRT( "BCP ", p->timeBcp ); |
| ABC_PRT( "Trace ", p->timeTrace ); |
| ABC_PRT( "TOTAL ", p->timeTotal ); |
| |
| Pr_ManMemoryStop( p ); |
| ABC_FREE( p->pTrail ); |
| ABC_FREE( p->pAssigns ); |
| ABC_FREE( p->pSeens ); |
| ABC_FREE( p->pVarTypes ); |
| ABC_FREE( p->pReasons ); |
| ABC_FREE( p->pWatches ); |
| ABC_FREE( p->pResLits ); |
| ABC_FREE( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Adds one clause to the watcher list.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Pr_ManWatchClause( Pr_Man_t * p, Pr_Cls_t * pClause, lit Lit ) |
| { |
| assert( lit_check(Lit, p->nVars) ); |
| if ( pClause->pLits[0] == Lit ) |
| pClause->pNext0 = p->pWatches[lit_neg(Lit)]; |
| else |
| { |
| assert( pClause->pLits[1] == Lit ); |
| pClause->pNext1 = p->pWatches[lit_neg(Lit)]; |
| } |
| p->pWatches[lit_neg(Lit)] = pClause; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Adds one clause to the manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManAddClause( Pr_Man_t * p, lit * pBeg, lit * pEnd, int fRoot, int fClauseA ) |
| { |
| Pr_Cls_t * pClause; |
| lit Lit, * i, * j; |
| int nSize, VarMax; |
| |
| // process the literals |
| if ( pBeg < pEnd ) |
| { |
| // insertion sort |
| VarMax = lit_var( *pBeg ); |
| for ( i = pBeg + 1; i < pEnd; i++ ) |
| { |
| Lit = *i; |
| VarMax = lit_var(Lit) > VarMax ? lit_var(Lit) : VarMax; |
| for ( j = i; j > pBeg && *(j-1) > Lit; j-- ) |
| *j = *(j-1); |
| *j = Lit; |
| } |
| // make sure there is no duplicated variables |
| for ( i = pBeg + 1; i < pEnd; i++ ) |
| assert( lit_var(*(i-1)) != lit_var(*i) ); |
| // resize the manager |
| Pr_ManResize( p, VarMax+1 ); |
| } |
| |
| // get memory for the clause |
| nSize = sizeof(Pr_Cls_t) + sizeof(lit) * (pEnd - pBeg); |
| pClause = (Pr_Cls_t *)Pr_ManMemoryFetch( p, nSize ); |
| memset( pClause, 0, sizeof(Pr_Cls_t) ); |
| |
| // assign the clause |
| assert( !fClauseA || fRoot ); // clause of A is always a root clause |
| p->nRoots += fRoot; |
| p->nClausesA += fClauseA; |
| pClause->Id = p->nClauses++; |
| pClause->fA = fClauseA; |
| pClause->fRoot = fRoot; |
| pClause->nLits = pEnd - pBeg; |
| memcpy( pClause->pLits, pBeg, sizeof(lit) * (pEnd - pBeg) ); |
| |
| // add the clause to the list |
| if ( p->pHead == NULL ) |
| p->pHead = pClause; |
| if ( p->pTail == NULL ) |
| p->pTail = pClause; |
| else |
| { |
| p->pTail->pNext = pClause; |
| p->pTail = pClause; |
| } |
| |
| // mark the first learnt clause |
| if ( p->pLearnt == NULL && !pClause->fRoot ) |
| p->pLearnt = pClause; |
| |
| // add the empty clause |
| if ( pClause->nLits == 0 ) |
| { |
| if ( p->pEmpty ) |
| printf( "More than one empty clause!\n" ); |
| p->pEmpty = pClause; |
| } |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Fetches memory.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| char * Pr_ManMemoryFetch( Pr_Man_t * p, int nBytes ) |
| { |
| char * pMem; |
| if ( p->pChunkLast == NULL || nBytes > p->nChunkSize - p->nChunkUsed ) |
| { |
| pMem = (char *)ABC_ALLOC( char, p->nChunkSize ); |
| *(char **)pMem = p->pChunkLast; |
| p->pChunkLast = pMem; |
| p->nChunkUsed = sizeof(char *); |
| } |
| pMem = p->pChunkLast + p->nChunkUsed; |
| p->nChunkUsed += nBytes; |
| return pMem; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Frees memory manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManMemoryStop( Pr_Man_t * p ) |
| { |
| char * pMem, * pNext; |
| if ( p->pChunkLast == NULL ) |
| return; |
| for ( pMem = p->pChunkLast; pNext = *(char **)pMem; pMem = pNext ) |
| ABC_FREE( pMem ); |
| ABC_FREE( pMem ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reports memory usage in bytes.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManMemoryReport( Pr_Man_t * p ) |
| { |
| int Total; |
| char * pMem, * pNext; |
| if ( p->pChunkLast == NULL ) |
| return 0; |
| Total = p->nChunkUsed; |
| for ( pMem = p->pChunkLast; pNext = *(char **)pMem; pMem = pNext ) |
| Total += p->nChunkSize; |
| return Total; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Extra_PrintBinary_( FILE * pFile, unsigned Sign[], int nBits ) |
| { |
| int Remainder, nWords; |
| int w, i; |
| |
| Remainder = (nBits%(sizeof(unsigned)*8)); |
| nWords = (nBits/(sizeof(unsigned)*8)) + (Remainder>0); |
| |
| for ( w = nWords-1; w >= 0; w-- ) |
| for ( i = ((w == nWords-1 && Remainder)? Remainder-1: 31); i >= 0; i-- ) |
| fprintf( pFile, "%c", '0' + (int)((Sign[w] & (1<<i)) > 0) ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints the interpolant for one clause.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManPrintInterOne( Pr_Man_t * p, Pr_Cls_t * pClause ) |
| { |
| printf( "Clause %2d : ", pClause->Id ); |
| Extra_PrintBinary_( stdout, &pClause->uTruth, (1 << p->nVarsAB) ); |
| printf( "\n" ); |
| } |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records implication.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline int Pr_ManEnqueue( Pr_Man_t * p, lit Lit, Pr_Cls_t * pReason ) |
| { |
| int Var = lit_var(Lit); |
| if ( p->pAssigns[Var] != LIT_UNDEF ) |
| return p->pAssigns[Var] == Lit; |
| p->pAssigns[Var] = Lit; |
| p->pReasons[Var] = pReason; |
| p->pTrail[p->nTrailSize++] = Lit; |
| //printf( "assigning var %d value %d\n", Var, !lit_sign(Lit) ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records implication.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Pr_ManCancelUntil( Pr_Man_t * p, int Level ) |
| { |
| lit Lit; |
| int i, Var; |
| for ( i = p->nTrailSize - 1; i >= Level; i-- ) |
| { |
| Lit = p->pTrail[i]; |
| Var = lit_var( Lit ); |
| p->pReasons[Var] = NULL; |
| p->pAssigns[Var] = LIT_UNDEF; |
| //printf( "cancelling var %d\n", Var ); |
| } |
| p->nTrailSize = Level; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Propagate one assignment.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline Pr_Cls_t * Pr_ManPropagateOne( Pr_Man_t * p, lit Lit ) |
| { |
| Pr_Cls_t ** ppPrev, * pCur, * pTemp; |
| lit LitF = lit_neg(Lit); |
| int i; |
| // iterate through the literals |
| ppPrev = p->pWatches + Lit; |
| for ( pCur = p->pWatches[Lit]; pCur; pCur = *ppPrev ) |
| { |
| // make sure the false literal is in the second literal of the clause |
| if ( pCur->pLits[0] == LitF ) |
| { |
| pCur->pLits[0] = pCur->pLits[1]; |
| pCur->pLits[1] = LitF; |
| pTemp = pCur->pNext0; |
| pCur->pNext0 = pCur->pNext1; |
| pCur->pNext1 = pTemp; |
| } |
| assert( pCur->pLits[1] == LitF ); |
| |
| // if the first literal is true, the clause is satisfied |
| if ( pCur->pLits[0] == p->pAssigns[lit_var(pCur->pLits[0])] ) |
| { |
| ppPrev = &pCur->pNext1; |
| continue; |
| } |
| |
| // look for a new literal to watch |
| for ( i = 2; i < (int)pCur->nLits; i++ ) |
| { |
| // skip the case when the literal is false |
| if ( lit_neg(pCur->pLits[i]) == p->pAssigns[lit_var(pCur->pLits[i])] ) |
| continue; |
| // the literal is either true or unassigned - watch it |
| pCur->pLits[1] = pCur->pLits[i]; |
| pCur->pLits[i] = LitF; |
| // remove this clause from the watch list of Lit |
| *ppPrev = pCur->pNext1; |
| // add this clause to the watch list of pCur->pLits[i] (now it is pCur->pLits[1]) |
| Pr_ManWatchClause( p, pCur, pCur->pLits[1] ); |
| break; |
| } |
| if ( i < (int)pCur->nLits ) // found new watch |
| continue; |
| |
| // clause is unit - enqueue new implication |
| if ( Pr_ManEnqueue(p, pCur->pLits[0], pCur) ) |
| { |
| ppPrev = &pCur->pNext1; |
| continue; |
| } |
| |
| // conflict detected - return the conflict clause |
| return pCur; |
| } |
| return NULL; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Propagate the current assignments.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Pr_Cls_t * Pr_ManPropagate( Pr_Man_t * p, int Start ) |
| { |
| Pr_Cls_t * pClause; |
| int i; |
| abctime clk = Abc_Clock(); |
| for ( i = Start; i < p->nTrailSize; i++ ) |
| { |
| pClause = Pr_ManPropagateOne( p, p->pTrail[i] ); |
| if ( pClause ) |
| { |
| p->timeBcp += Abc_Clock() - clk; |
| return pClause; |
| } |
| } |
| p->timeBcp += Abc_Clock() - clk; |
| return NULL; |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints the clause.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManPrintClause( Pr_Cls_t * pClause ) |
| { |
| int i; |
| printf( "Clause ID = %d. Proof = %d. {", pClause->Id, (int)pClause->pProof ); |
| for ( i = 0; i < (int)pClause->nLits; i++ ) |
| printf( " %d", pClause->pLits[i] ); |
| printf( " }\n" ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prints the resolvent.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManPrintResolvent( lit * pResLits, int nResLits ) |
| { |
| int i; |
| printf( "Resolvent: {" ); |
| for ( i = 0; i < nResLits; i++ ) |
| printf( " %d", pResLits[i] ); |
| printf( " }\n" ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Writes one root clause into a file.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManProofWriteOne( Pr_Man_t * p, Pr_Cls_t * pClause ) |
| { |
| pClause->pProof = (void *)++p->Counter; |
| |
| if ( p->fProofWrite ) |
| { |
| int v; |
| fprintf( (FILE *)p->pManProof, "%d", (int)pClause->pProof ); |
| for ( v = 0; v < (int)pClause->nLits; v++ ) |
| fprintf( (FILE *)p->pManProof, " %d", lit_print(pClause->pLits[v]) ); |
| fprintf( (FILE *)p->pManProof, " 0 0\n" ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Traces the proof for one clause.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManProofTraceOne( Pr_Man_t * p, Pr_Cls_t * pConflict, Pr_Cls_t * pFinal ) |
| { |
| Pr_Cls_t * pReason; |
| int i, v, Var, PrevId; |
| int fPrint = 0; |
| abctime clk = Abc_Clock(); |
| |
| // collect resolvent literals |
| if ( p->fProofVerif ) |
| { |
| assert( (int)pConflict->nLits <= p->nResLitsAlloc ); |
| memcpy( p->pResLits, pConflict->pLits, sizeof(lit) * pConflict->nLits ); |
| p->nResLits = pConflict->nLits; |
| } |
| |
| // mark all the variables in the conflict as seen |
| for ( v = 0; v < (int)pConflict->nLits; v++ ) |
| p->pSeens[lit_var(pConflict->pLits[v])] = 1; |
| |
| // start the anticedents |
| // pFinal->pAntis = Vec_PtrAlloc( 32 ); |
| // Vec_PtrPush( pFinal->pAntis, pConflict ); |
| |
| if ( p->nClausesA ) |
| pFinal->uTruth = pConflict->uTruth; |
| |
| // follow the trail backwards |
| PrevId = (int)pConflict->pProof; |
| for ( i = p->nTrailSize - 1; i >= 0; i-- ) |
| { |
| // skip literals that are not involved |
| Var = lit_var(p->pTrail[i]); |
| if ( !p->pSeens[Var] ) |
| continue; |
| p->pSeens[Var] = 0; |
| |
| // skip literals of the resulting clause |
| pReason = p->pReasons[Var]; |
| if ( pReason == NULL ) |
| continue; |
| assert( p->pTrail[i] == pReason->pLits[0] ); |
| |
| // add the variables to seen |
| for ( v = 1; v < (int)pReason->nLits; v++ ) |
| p->pSeens[lit_var(pReason->pLits[v])] = 1; |
| |
| |
| // record the reason clause |
| assert( pReason->pProof > 0 ); |
| p->Counter++; |
| if ( p->fProofWrite ) |
| fprintf( (FILE *)p->pManProof, "%d * %d %d 0\n", p->Counter, PrevId, (int)pReason->pProof ); |
| PrevId = p->Counter; |
| |
| if ( p->nClausesA ) |
| { |
| if ( p->pVarTypes[Var] == 1 ) // var of A |
| pFinal->uTruth |= pReason->uTruth; |
| else |
| pFinal->uTruth &= pReason->uTruth; |
| } |
| |
| // resolve the temporary resolvent with the reason clause |
| if ( p->fProofVerif ) |
| { |
| int v1, v2; |
| if ( fPrint ) |
| Pr_ManPrintResolvent( p->pResLits, p->nResLits ); |
| // check that the var is present in the resolvent |
| for ( v1 = 0; v1 < p->nResLits; v1++ ) |
| if ( lit_var(p->pResLits[v1]) == Var ) |
| break; |
| if ( v1 == p->nResLits ) |
| printf( "Recording clause %d: Cannot find variable %d in the temporary resolvent.\n", pFinal->Id, Var ); |
| if ( p->pResLits[v1] != lit_neg(pReason->pLits[0]) ) |
| printf( "Recording clause %d: The resolved variable %d is in the wrong polarity.\n", pFinal->Id, Var ); |
| // remove this variable from the resolvent |
| assert( lit_var(p->pResLits[v1]) == Var ); |
| p->nResLits--; |
| for ( ; v1 < p->nResLits; v1++ ) |
| p->pResLits[v1] = p->pResLits[v1+1]; |
| // add variables of the reason clause |
| for ( v2 = 1; v2 < (int)pReason->nLits; v2++ ) |
| { |
| for ( v1 = 0; v1 < p->nResLits; v1++ ) |
| if ( lit_var(p->pResLits[v1]) == lit_var(pReason->pLits[v2]) ) |
| break; |
| // if it is a new variable, add it to the resolvent |
| if ( v1 == p->nResLits ) |
| { |
| if ( p->nResLits == p->nResLitsAlloc ) |
| printf( "Recording clause %d: Ran out of space for intermediate resolvent.\n, pFinal->Id" ); |
| p->pResLits[ p->nResLits++ ] = pReason->pLits[v2]; |
| continue; |
| } |
| // if the variable is the same, the literal should be the same too |
| if ( p->pResLits[v1] == pReason->pLits[v2] ) |
| continue; |
| // the literal is different |
| printf( "Recording clause %d: Trying to resolve the clause with more than one opposite literal.\n", pFinal->Id ); |
| } |
| } |
| |
| // Vec_PtrPush( pFinal->pAntis, pReason ); |
| } |
| |
| // unmark all seen variables |
| // for ( i = p->nTrailSize - 1; i >= 0; i-- ) |
| // p->pSeens[lit_var(p->pTrail[i])] = 0; |
| // check that the literals are unmarked |
| // for ( i = p->nTrailSize - 1; i >= 0; i-- ) |
| // assert( p->pSeens[lit_var(p->pTrail[i])] == 0 ); |
| |
| // use the resulting clause to check the correctness of resolution |
| if ( p->fProofVerif ) |
| { |
| int v1, v2; |
| if ( fPrint ) |
| Pr_ManPrintResolvent( p->pResLits, p->nResLits ); |
| for ( v1 = 0; v1 < p->nResLits; v1++ ) |
| { |
| for ( v2 = 0; v2 < (int)pFinal->nLits; v2++ ) |
| if ( pFinal->pLits[v2] == p->pResLits[v1] ) |
| break; |
| if ( v2 < (int)pFinal->nLits ) |
| continue; |
| break; |
| } |
| if ( v1 < p->nResLits ) |
| { |
| printf( "Recording clause %d: The final resolvent is wrong.\n", pFinal->Id ); |
| Pr_ManPrintClause( pConflict ); |
| Pr_ManPrintResolvent( p->pResLits, p->nResLits ); |
| Pr_ManPrintClause( pFinal ); |
| } |
| } |
| p->timeTrace += Abc_Clock() - clk; |
| |
| // return the proof pointer |
| if ( p->nClausesA ) |
| { |
| Pr_ManPrintInterOne( p, pFinal ); |
| } |
| return p->Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof for one clause.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManProofRecordOne( Pr_Man_t * p, Pr_Cls_t * pClause ) |
| { |
| Pr_Cls_t * pConflict; |
| int i; |
| |
| // empty clause never ends up there |
| assert( pClause->nLits > 0 ); |
| if ( pClause->nLits == 0 ) |
| printf( "Error: Empty clause is attempted.\n" ); |
| |
| // add assumptions to the trail |
| assert( !pClause->fRoot ); |
| assert( p->nTrailSize == p->nRootSize ); |
| for ( i = 0; i < (int)pClause->nLits; i++ ) |
| if ( !Pr_ManEnqueue( p, lit_neg(pClause->pLits[i]), NULL ) ) |
| { |
| assert( 0 ); // impossible |
| return 0; |
| } |
| |
| // propagate the assumptions |
| pConflict = Pr_ManPropagate( p, p->nRootSize ); |
| if ( pConflict == NULL ) |
| { |
| assert( 0 ); // cannot prove |
| return 0; |
| } |
| |
| // construct the proof |
| pClause->pProof = (void *)Pr_ManProofTraceOne( p, pConflict, pClause ); |
| |
| // undo to the root level |
| Pr_ManCancelUntil( p, p->nRootSize ); |
| |
| // add large clauses to the watched lists |
| if ( pClause->nLits > 1 ) |
| { |
| Pr_ManWatchClause( p, pClause, pClause->pLits[0] ); |
| Pr_ManWatchClause( p, pClause, pClause->pLits[1] ); |
| return 1; |
| } |
| assert( pClause->nLits == 1 ); |
| |
| // if the clause proved is unit, add it and propagate |
| if ( !Pr_ManEnqueue( p, pClause->pLits[0], pClause ) ) |
| { |
| assert( 0 ); // impossible |
| return 0; |
| } |
| |
| // propagate the assumption |
| pConflict = Pr_ManPropagate( p, p->nRootSize ); |
| if ( pConflict ) |
| { |
| // construct the proof |
| p->pEmpty->pProof = (void *)Pr_ManProofTraceOne( p, pConflict, p->pEmpty ); |
| printf( "Found last conflict after adding unit clause number %d!\n", pClause->Id ); |
| return 0; |
| } |
| |
| // update the root level |
| p->nRootSize = p->nTrailSize; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Propagate the root clauses.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManProcessRoots( Pr_Man_t * p ) |
| { |
| Pr_Cls_t * pClause; |
| int Counter; |
| |
| // make sure the root clauses are preceeding the learnt clauses |
| Counter = 0; |
| Pr_ManForEachClause( p, pClause ) |
| { |
| assert( (int)pClause->fA == (Counter < (int)p->nClausesA) ); |
| assert( (int)pClause->fRoot == (Counter < (int)p->nRoots) ); |
| Counter++; |
| } |
| assert( p->nClauses == Counter ); |
| |
| // make sure the last clause if empty |
| assert( p->pTail->nLits == 0 ); |
| |
| // go through the root unit clauses |
| p->nTrailSize = 0; |
| Pr_ManForEachClauseRoot( p, pClause ) |
| { |
| // create watcher lists for the root clauses |
| if ( pClause->nLits > 1 ) |
| { |
| Pr_ManWatchClause( p, pClause, pClause->pLits[0] ); |
| Pr_ManWatchClause( p, pClause, pClause->pLits[1] ); |
| } |
| // empty clause and large clauses |
| if ( pClause->nLits != 1 ) |
| continue; |
| // unit clause |
| assert( lit_check(pClause->pLits[0], p->nVars) ); |
| if ( !Pr_ManEnqueue( p, pClause->pLits[0], pClause ) ) |
| { |
| // detected root level conflict |
| printf( "Pr_ManProcessRoots(): Detected a root-level conflict\n" ); |
| assert( 0 ); |
| return 0; |
| } |
| } |
| |
| // propagate the root unit clauses |
| pClause = Pr_ManPropagate( p, 0 ); |
| if ( pClause ) |
| { |
| // detected root level conflict |
| printf( "Pr_ManProcessRoots(): Detected a root-level conflict\n" ); |
| assert( 0 ); |
| return 0; |
| } |
| |
| // set the root level |
| p->nRootSize = p->nTrailSize; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Pr_ManPrepareInter( Pr_Man_t * p ) |
| { |
| unsigned uTruths[5] = { 0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000 }; |
| Pr_Cls_t * pClause; |
| int Var, v; |
| |
| // mark the variable encountered in the clauses of A |
| Pr_ManForEachClauseRoot( p, pClause ) |
| { |
| if ( !pClause->fA ) |
| break; |
| for ( v = 0; v < (int)pClause->nLits; v++ ) |
| p->pVarTypes[lit_var(pClause->pLits[v])] = 1; |
| } |
| |
| // check variables that appear in clauses of B |
| p->nVarsAB = 0; |
| Pr_ManForEachClauseRoot( p, pClause ) |
| { |
| if ( pClause->fA ) |
| continue; |
| for ( v = 0; v < (int)pClause->nLits; v++ ) |
| { |
| Var = lit_var(pClause->pLits[v]); |
| if ( p->pVarTypes[Var] == 1 ) // var of A |
| { |
| // change it into a global variable |
| p->nVarsAB++; |
| p->pVarTypes[Var] = -1; |
| } |
| } |
| } |
| |
| // order global variables |
| p->nVarsAB = 0; |
| for ( v = 0; v < p->nVars; v++ ) |
| if ( p->pVarTypes[v] == -1 ) |
| p->pVarTypes[v] -= p->nVarsAB++; |
| printf( "There are %d global variables.\n", p->nVarsAB ); |
| |
| // set interpolants for root clauses |
| Pr_ManForEachClauseRoot( p, pClause ) |
| { |
| if ( !pClause->fA ) // clause of B |
| { |
| pClause->uTruth = ~0; |
| Pr_ManPrintInterOne( p, pClause ); |
| continue; |
| } |
| // clause of A |
| pClause->uTruth = 0; |
| for ( v = 0; v < (int)pClause->nLits; v++ ) |
| { |
| Var = lit_var(pClause->pLits[v]); |
| if ( p->pVarTypes[Var] < 0 ) // global var |
| { |
| if ( lit_sign(pClause->pLits[v]) ) // negative var |
| pClause->uTruth |= ~uTruths[ -p->pVarTypes[Var]-1 ]; |
| else |
| pClause->uTruth |= uTruths[ -p->pVarTypes[Var]-1 ]; |
| } |
| } |
| Pr_ManPrintInterOne( p, pClause ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManProofWrite( Pr_Man_t * p ) |
| { |
| Pr_Cls_t * pClause; |
| int RetValue = 1; |
| |
| // propagate root level assignments |
| Pr_ManProcessRoots( p ); |
| |
| // prepare the interpolant computation |
| if ( p->nClausesA ) |
| Pr_ManPrepareInter( p ); |
| |
| // construct proof for each clause |
| // start the proof |
| if ( p->fProofWrite ) |
| p->pManProof = fopen( "proof.cnf_", "w" ); |
| p->Counter = 0; |
| |
| // write the root clauses |
| Pr_ManForEachClauseRoot( p, pClause ) |
| Pr_ManProofWriteOne( p, pClause ); |
| |
| // consider each learned clause |
| Pr_ManForEachClauseLearnt( p, pClause ) |
| { |
| if ( !Pr_ManProofRecordOne( p, pClause ) ) |
| { |
| RetValue = 0; |
| break; |
| } |
| } |
| |
| if ( p->nClausesA ) |
| { |
| printf( "Interpolant: " ); |
| } |
| |
| |
| // stop the proof |
| if ( p->fProofWrite ) |
| { |
| fclose( (FILE *)p->pManProof ); |
| p->pManProof = NULL; |
| } |
| return RetValue; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads clauses from file.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Pr_Man_t * Pr_ManProofRead( char * pFileName ) |
| { |
| Pr_Man_t * p = NULL; |
| char * pCur, * pBuffer = NULL; |
| int * pArray = NULL; |
| FILE * pFile; |
| int RetValue, Counter, nNumbers, Temp; |
| int nClauses, nClausesA, nRoots, nVars; |
| |
| // open the file |
| pFile = fopen( pFileName, "r" ); |
| if ( pFile == NULL ) |
| { |
| printf( "Count not open input file \"%s\".\n", pFileName ); |
| return NULL; |
| } |
| |
| // read the file |
| pBuffer = (char *)ABC_ALLOC( char, (1<<16) ); |
| for ( Counter = 0; fgets( pBuffer, (1<<16), pFile ); ) |
| { |
| if ( pBuffer[0] == 'c' ) |
| continue; |
| if ( pBuffer[0] == 'p' ) |
| { |
| assert( p == NULL ); |
| nClausesA = 0; |
| RetValue = sscanf( pBuffer + 1, "%d %d %d %d", &nVars, &nClauses, &nRoots, &nClausesA ); |
| if ( RetValue != 3 && RetValue != 4 ) |
| { |
| printf( "Wrong input file format.\n" ); |
| } |
| p = Pr_ManAlloc( nVars ); |
| pArray = (int *)ABC_ALLOC( char, sizeof(int) * (nVars + 10) ); |
| continue; |
| } |
| // skip empty lines |
| for ( pCur = pBuffer; *pCur; pCur++ ) |
| if ( !(*pCur == ' ' || *pCur == '\t' || *pCur == '\r' || *pCur == '\n') ) |
| break; |
| if ( *pCur == 0 ) |
| continue; |
| // scan the numbers from file |
| nNumbers = 0; |
| pCur = pBuffer; |
| while ( *pCur ) |
| { |
| // skip spaces |
| for ( ; *pCur && *pCur == ' '; pCur++ ); |
| // read next number |
| Temp = 0; |
| sscanf( pCur, "%d", &Temp ); |
| if ( Temp == 0 ) |
| break; |
| pArray[ nNumbers++ ] = lit_read( Temp ); |
| // skip non-spaces |
| for ( ; *pCur && *pCur != ' '; pCur++ ); |
| } |
| // add the clause |
| if ( !Pr_ManAddClause( p, (unsigned *)pArray, (unsigned *)pArray + nNumbers, Counter < nRoots, Counter < nClausesA ) ) |
| { |
| printf( "Bad clause number %d.\n", Counter ); |
| return NULL; |
| } |
| // count the clauses |
| Counter++; |
| } |
| // check the number of clauses |
| if ( Counter != nClauses ) |
| printf( "Expected %d clauses but read %d.\n", nClauses, Counter ); |
| |
| // finish |
| if ( pArray ) ABC_FREE( pArray ); |
| if ( pBuffer ) ABC_FREE( pBuffer ); |
| fclose( pFile ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| /* |
| int Pr_ManProofCount_rec( Pr_Cls_t * pClause ) |
| { |
| Pr_Cls_t * pNext; |
| int i, Counter; |
| if ( pClause->fRoot ) |
| return 0; |
| if ( pClause->fVisit ) |
| return 0; |
| pClause->fVisit = 1; |
| // count the number of visited clauses |
| Counter = 1; |
| Vec_PtrForEachEntry( Pr_Cls_t *, pClause->pAntis, pNext, i ) |
| Counter += Pr_ManProofCount_rec( pNext ); |
| return Counter; |
| } |
| */ |
| |
| /**Function************************************************************* |
| |
| Synopsis [Records the proof.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Pr_ManProofTest( char * pFileName ) |
| { |
| Pr_Man_t * p; |
| abctime clk, clkTotal = Abc_Clock(); |
| |
| clk = Abc_Clock(); |
| p = Pr_ManProofRead( pFileName ); |
| p->timeRead = Abc_Clock() - clk; |
| if ( p == NULL ) |
| return 0; |
| |
| Pr_ManProofWrite( p ); |
| |
| // print stats |
| /* |
| nUsed = Pr_ManProofCount_rec( p->pEmpty ); |
| printf( "Roots = %d. Learned = %d. Total = %d. Steps = %d. Ave = %.2f. Used = %d. Ratio = %.2f. \n", |
| p->nRoots, p->nClauses-p->nRoots, p->nClauses, p->Counter, |
| 1.0*(p->Counter-p->nRoots)/(p->nClauses-p->nRoots), |
| nUsed, 1.0*nUsed/(p->nClauses-p->nRoots) ); |
| */ |
| printf( "Vars = %d. Roots = %d. Learned = %d. Resol steps = %d. Ave = %.2f. Mem = %.2f MB\n", |
| p->nVars, p->nRoots, p->nClauses-p->nRoots, p->Counter, |
| 1.0*(p->Counter-p->nRoots)/(p->nClauses-p->nRoots), |
| 1.0*Pr_ManMemoryReport(p)/(1<<20) ); |
| |
| p->timeTotal = Abc_Clock() - clkTotal; |
| Pr_ManFree( p ); |
| return 1; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |