blob: 708a1067fc9466eb638c260946113a343c082f96 [file] [log] [blame]
/**CFile****************************************************************
FileName [cnfFast.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [AIG-to-CNF conversion.]
Synopsis []
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - April 28, 2007.]
Revision [$Id: cnfFast.c,v 1.00 2007/04/28 00:00:00 alanmi Exp $]
***********************************************************************/
#include "cnf.h"
#include "bool/kit/kit.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Detects multi-input gate rooted at this node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_CollectLeaves_rec( Aig_Obj_t * pRoot, Aig_Obj_t * pObj, Vec_Ptr_t * vSuper, int fStopCompl )
{
if ( pRoot != pObj && (pObj->fMarkA || (fStopCompl && Aig_IsComplement(pObj))) )
{
Vec_PtrPushUnique( vSuper, fStopCompl ? pObj : Aig_Regular(pObj) );
return;
}
assert( Aig_ObjIsNode(pObj) );
if ( fStopCompl )
{
Cnf_CollectLeaves_rec( pRoot, Aig_ObjChild0(pObj), vSuper, 1 );
Cnf_CollectLeaves_rec( pRoot, Aig_ObjChild1(pObj), vSuper, 1 );
}
else
{
Cnf_CollectLeaves_rec( pRoot, Aig_ObjFanin0(pObj), vSuper, 0 );
Cnf_CollectLeaves_rec( pRoot, Aig_ObjFanin1(pObj), vSuper, 0 );
}
}
/**Function*************************************************************
Synopsis [Detects multi-input gate rooted at this node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_CollectLeaves( Aig_Obj_t * pRoot, Vec_Ptr_t * vSuper, int fStopCompl )
{
assert( !Aig_IsComplement(pRoot) );
Vec_PtrClear( vSuper );
Cnf_CollectLeaves_rec( pRoot, pRoot, vSuper, fStopCompl );
}
/**Function*************************************************************
Synopsis [Collects nodes inside the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_CollectVolume_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes )
{
if ( Aig_ObjIsTravIdCurrent( p, pObj ) )
return;
Aig_ObjSetTravIdCurrent( p, pObj );
assert( Aig_ObjIsNode(pObj) );
Cnf_CollectVolume_rec( p, Aig_ObjFanin0(pObj), vNodes );
Cnf_CollectVolume_rec( p, Aig_ObjFanin1(pObj), vNodes );
Vec_PtrPush( vNodes, pObj );
}
/**Function*************************************************************
Synopsis [Collects nodes inside the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_CollectVolume( Aig_Man_t * p, Aig_Obj_t * pRoot, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vNodes )
{
Aig_Obj_t * pObj;
int i;
Aig_ManIncrementTravId( p );
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pObj, i )
Aig_ObjSetTravIdCurrent( p, pObj );
Vec_PtrClear( vNodes );
Cnf_CollectVolume_rec( p, pRoot, vNodes );
}
/**Function*************************************************************
Synopsis [Derive truth table.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
word Cnf_CutDeriveTruth( Aig_Man_t * p, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vNodes )
{
static word Truth6[6] = {
ABC_CONST(0xAAAAAAAAAAAAAAAA),
ABC_CONST(0xCCCCCCCCCCCCCCCC),
ABC_CONST(0xF0F0F0F0F0F0F0F0),
ABC_CONST(0xFF00FF00FF00FF00),
ABC_CONST(0xFFFF0000FFFF0000),
ABC_CONST(0xFFFFFFFF00000000)
};
static word C[2] = { 0, ~(word)0 };
static word S[256];
Aig_Obj_t * pObj = NULL;
int i;
assert( Vec_PtrSize(vLeaves) <= 6 && Vec_PtrSize(vNodes) > 0 );
assert( Vec_PtrSize(vLeaves) + Vec_PtrSize(vNodes) <= 256 );
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pObj, i )
{
pObj->iData = i;
S[pObj->iData] = Truth6[i];
}
Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
{
pObj->iData = Vec_PtrSize(vLeaves) + i;
S[pObj->iData] = (S[Aig_ObjFanin0(pObj)->iData] ^ C[Aig_ObjFaninC0(pObj)]) &
(S[Aig_ObjFanin1(pObj)->iData] ^ C[Aig_ObjFaninC1(pObj)]);
}
return S[pObj->iData];
}
/**Function*************************************************************
Synopsis [Collects nodes inside the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Cnf_ObjGetLit( Vec_Int_t * vMap, Aig_Obj_t * pObj, int fCompl )
{
int iSatVar = vMap ? Vec_IntEntry(vMap, Aig_ObjId(pObj)) : Aig_ObjId(pObj);
assert( iSatVar > 0 );
return iSatVar + iSatVar + fCompl;
}
/**Function*************************************************************
Synopsis [Collects nodes inside the cone.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_ComputeClauses( Aig_Man_t * p, Aig_Obj_t * pRoot,
Vec_Ptr_t * vLeaves, Vec_Ptr_t * vNodes, Vec_Int_t * vMap, Vec_Int_t * vCover, Vec_Int_t * vClauses )
{
Aig_Obj_t * pLeaf;
int c, k, Cube, OutLit, RetValue;
word Truth;
assert( pRoot->fMarkA );
Vec_IntClear( vClauses );
OutLit = Cnf_ObjGetLit( vMap, pRoot, 0 );
// detect cone
Cnf_CollectLeaves( pRoot, vLeaves, 0 );
Cnf_CollectVolume( p, pRoot, vLeaves, vNodes );
assert( pRoot == Vec_PtrEntryLast(vNodes) );
// check if this is an AND-gate
Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pLeaf, k )
{
if ( Aig_ObjFaninC0(pLeaf) && !Aig_ObjFanin0(pLeaf)->fMarkA )
break;
if ( Aig_ObjFaninC1(pLeaf) && !Aig_ObjFanin1(pLeaf)->fMarkA )
break;
}
if ( k == Vec_PtrSize(vNodes) )
{
Cnf_CollectLeaves( pRoot, vLeaves, 1 );
// write big clause
Vec_IntPush( vClauses, 0 );
Vec_IntPush( vClauses, OutLit );
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pLeaf, k )
Vec_IntPush( vClauses, Cnf_ObjGetLit(vMap, Aig_Regular(pLeaf), !Aig_IsComplement(pLeaf)) );
// write small clauses
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pLeaf, k )
{
Vec_IntPush( vClauses, 0 );
Vec_IntPush( vClauses, OutLit ^ 1 );
Vec_IntPush( vClauses, Cnf_ObjGetLit(vMap, Aig_Regular(pLeaf), Aig_IsComplement(pLeaf)) );
}
return;
}
if ( Vec_PtrSize(vLeaves) > 6 )
printf( "FastCnfGeneration: Internal error!!!\n" );
assert( Vec_PtrSize(vLeaves) <= 6 );
Truth = Cnf_CutDeriveTruth( p, vLeaves, vNodes );
if ( Truth == 0 || Truth == ~(word)0 )
{
Vec_IntPush( vClauses, 0 );
Vec_IntPush( vClauses, (Truth == 0) ? (OutLit ^ 1) : OutLit );
return;
}
RetValue = Kit_TruthIsop( (unsigned *)&Truth, Vec_PtrSize(vLeaves), vCover, 0 );
assert( RetValue >= 0 );
Vec_IntForEachEntry( vCover, Cube, c )
{
Vec_IntPush( vClauses, 0 );
Vec_IntPush( vClauses, OutLit );
for ( k = 0; k < Vec_PtrSize(vLeaves); k++, Cube >>= 2 )
{
if ( (Cube & 3) == 0 )
continue;
assert( (Cube & 3) != 3 );
Vec_IntPush( vClauses, Cnf_ObjGetLit(vMap, (Aig_Obj_t *)Vec_PtrEntry(vLeaves,k), (Cube&3)!=1) );
}
}
Truth = ~Truth;
RetValue = Kit_TruthIsop( (unsigned *)&Truth, Vec_PtrSize(vLeaves), vCover, 0 );
assert( RetValue >= 0 );
Vec_IntForEachEntry( vCover, Cube, c )
{
Vec_IntPush( vClauses, 0 );
Vec_IntPush( vClauses, OutLit ^ 1 );
for ( k = 0; k < Vec_PtrSize(vLeaves); k++, Cube >>= 2 )
{
if ( (Cube & 3) == 0 )
continue;
assert( (Cube & 3) != 3 );
Vec_IntPush( vClauses, Cnf_ObjGetLit(vMap, (Aig_Obj_t *)Vec_PtrEntry(vLeaves,k), (Cube&3)!=1) );
}
}
}
/**Function*************************************************************
Synopsis [Marks AIG for CNF computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Cnf_DeriveFastMark( Aig_Man_t * p )
{
Vec_Int_t * vSupps;
Vec_Ptr_t * vLeaves, * vNodes;
Aig_Obj_t * pObj, * pTemp, * pObjC, * pObj0, * pObj1;
int i, k, nFans, Counter;
vLeaves = Vec_PtrAlloc( 100 );
vNodes = Vec_PtrAlloc( 100 );
vSupps = Vec_IntStart( Aig_ManObjNumMax(p) );
// mark CIs
Aig_ManForEachCi( p, pObj, i )
pObj->fMarkA = 1;
// mark CO drivers
Aig_ManForEachCo( p, pObj, i )
Aig_ObjFanin0(pObj)->fMarkA = 1;
// mark MUX/XOR nodes
Aig_ManForEachNode( p, pObj, i )
{
assert( !pObj->fMarkB );
if ( !Aig_ObjIsMuxType(pObj) )
continue;
pObj0 = Aig_ObjFanin0(pObj);
if ( pObj0->fMarkB || Aig_ObjRefs(pObj0) > 1 )
continue;
pObj1 = Aig_ObjFanin1(pObj);
if ( pObj1->fMarkB || Aig_ObjRefs(pObj1) > 1 )
continue;
// mark nodes
pObj->fMarkB = 1;
pObj0->fMarkB = 1;
pObj1->fMarkB = 1;
// mark inputs and outputs
pObj->fMarkA = 1;
Aig_ObjFanin0(pObj0)->fMarkA = 1;
Aig_ObjFanin1(pObj0)->fMarkA = 1;
Aig_ObjFanin0(pObj1)->fMarkA = 1;
Aig_ObjFanin1(pObj1)->fMarkA = 1;
}
// mark nodes with multiple fanouts and pointed to by complemented edges
Aig_ManForEachNode( p, pObj, i )
{
// mark nodes with many fanouts
if ( Aig_ObjRefs(pObj) > 1 )
pObj->fMarkA = 1;
// mark nodes pointed to by a complemented edge
if ( Aig_ObjFaninC0(pObj) && !Aig_ObjFanin0(pObj)->fMarkB )
Aig_ObjFanin0(pObj)->fMarkA = 1;
if ( Aig_ObjFaninC1(pObj) && !Aig_ObjFanin1(pObj)->fMarkB )
Aig_ObjFanin1(pObj)->fMarkA = 1;
}
// compute supergate size for internal marked nodes
Aig_ManForEachNode( p, pObj, i )
{
if ( !pObj->fMarkA )
continue;
if ( pObj->fMarkB )
{
if ( !Aig_ObjIsMuxType(pObj) )
continue;
pObjC = Aig_ObjRecognizeMux( pObj, &pObj1, &pObj0 );
pObj0 = Aig_Regular(pObj0);
pObj1 = Aig_Regular(pObj1);
assert( pObj0->fMarkA );
assert( pObj1->fMarkA );
// if ( pObj0 == pObj1 )
// continue;
nFans = 1 + (pObj0 == pObj1);
if ( !pObj0->fMarkB && !Aig_ObjIsCi(pObj0) && Aig_ObjRefs(pObj0) == nFans && Vec_IntEntry(vSupps, Aig_ObjId(pObj0)) < 3 )
{
pObj0->fMarkA = 0;
continue;
}
if ( !pObj1->fMarkB && !Aig_ObjIsCi(pObj1) && Aig_ObjRefs(pObj1) == nFans && Vec_IntEntry(vSupps, Aig_ObjId(pObj1)) < 3 )
{
pObj1->fMarkA = 0;
continue;
}
continue;
}
Cnf_CollectLeaves( pObj, vLeaves, 1 );
Vec_IntWriteEntry( vSupps, Aig_ObjId(pObj), Vec_PtrSize(vLeaves) );
if ( Vec_PtrSize(vLeaves) >= 6 )
continue;
Vec_PtrForEachEntry( Aig_Obj_t *, vLeaves, pTemp, k )
{
pTemp = Aig_Regular(pTemp);
assert( pTemp->fMarkA );
if ( pTemp->fMarkB || Aig_ObjIsCi(pTemp) || Aig_ObjRefs(pTemp) > 1 )
continue;
assert( Vec_IntEntry(vSupps, Aig_ObjId(pTemp)) > 0 );
if ( Vec_PtrSize(vLeaves) - 1 + Vec_IntEntry(vSupps, Aig_ObjId(pTemp)) > 6 )
continue;
pTemp->fMarkA = 0;
Vec_IntWriteEntry( vSupps, Aig_ObjId(pObj), 6 );
//printf( "%d %d ", Vec_PtrSize(vLeaves), Vec_IntEntry(vSupps, Aig_ObjId(pTemp)) );
break;
}
}
Aig_ManCleanMarkB( p );
// check CO drivers
Counter = 0;
Aig_ManForEachCo( p, pObj, i )
Counter += !Aig_ObjFanin0(pObj)->fMarkA;
if ( Counter )
printf( "PO-driver rule is violated %d times.\n", Counter );
// check that the AND-gates are fine
Counter = 0;
Aig_ManForEachNode( p, pObj, i )
{
assert( pObj->fMarkB == 0 );
if ( !pObj->fMarkA )
continue;
Cnf_CollectLeaves( pObj, vLeaves, 0 );
if ( Vec_PtrSize(vLeaves) <= 6 )
continue;
Cnf_CollectVolume( p, pObj, vLeaves, vNodes );
Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pTemp, k )
{
if ( Aig_ObjFaninC0(pTemp) && !Aig_ObjFanin0(pTemp)->fMarkA )
Counter++;
if ( Aig_ObjFaninC1(pTemp) && !Aig_ObjFanin1(pTemp)->fMarkA )
Counter++;
}
}
if ( Counter )
printf( "AND-gate rule is violated %d times.\n", Counter );
Vec_PtrFree( vLeaves );
Vec_PtrFree( vNodes );
Vec_IntFree( vSupps );
}
/**Function*************************************************************
Synopsis [Counts the number of clauses.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Cnf_CutCountClauses( Aig_Man_t * p, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vNodes, Vec_Int_t * vCover )
{
word Truth;
Aig_Obj_t * pObj;
int i, RetValue, nSize = 0;
if ( Vec_PtrSize(vLeaves) > 6 )
{
// make sure this is an AND gate
Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i )
{
if ( Aig_ObjFaninC0(pObj) && !Aig_ObjFanin0(pObj)->fMarkA )
printf( "Unusual 1!\n" );
if ( Aig_ObjFaninC1(pObj) && !Aig_ObjFanin1(pObj)->fMarkA )
printf( "Unusual 2!\n" );
continue;
assert( !Aig_ObjFaninC0(pObj) || Aig_ObjFanin0(pObj)->fMarkA );
assert( !Aig_ObjFaninC1(pObj) || Aig_ObjFanin1(pObj)->fMarkA );
}
return Vec_PtrSize(vLeaves) + 1;
}
Truth = Cnf_CutDeriveTruth( p, vLeaves, vNodes );
RetValue = Kit_TruthIsop( (unsigned *)&Truth, Vec_PtrSize(vLeaves), vCover, 0 );
assert( RetValue >= 0 );
nSize += Vec_IntSize(vCover);
Truth = ~Truth;
RetValue = Kit_TruthIsop( (unsigned *)&Truth, Vec_PtrSize(vLeaves), vCover, 0 );
assert( RetValue >= 0 );
nSize += Vec_IntSize(vCover);
return nSize;
}
/**Function*************************************************************
Synopsis [Counts the size of the CNF, assuming marks are set.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Cnf_CountCnfSize( Aig_Man_t * p )
{
Vec_Ptr_t * vLeaves, * vNodes;
Vec_Int_t * vCover;
Aig_Obj_t * pObj;
int nVars = 0, nClauses = 0;
int i, nSize;
vLeaves = Vec_PtrAlloc( 100 );
vNodes = Vec_PtrAlloc( 100 );
vCover = Vec_IntAlloc( 1 << 16 );
Aig_ManForEachObj( p, pObj, i )
nVars += pObj->fMarkA;
Aig_ManForEachNode( p, pObj, i )
{
if ( !pObj->fMarkA )
continue;
Cnf_CollectLeaves( pObj, vLeaves, 0 );
Cnf_CollectVolume( p, pObj, vLeaves, vNodes );
assert( pObj == Vec_PtrEntryLast(vNodes) );
nSize = Cnf_CutCountClauses( p, vLeaves, vNodes, vCover );
// printf( "%d(%d) ", Vec_PtrSize(vLeaves), nSize );
nClauses += nSize;
}
// printf( "\n" );
printf( "Vars = %d Clauses = %d\n", nVars, nClauses );
Vec_PtrFree( vLeaves );
Vec_PtrFree( vNodes );
Vec_IntFree( vCover );
return nClauses;
}
/**Function*************************************************************
Synopsis [Derives CNF from the marked AIG.]
Description [Assumes that marking is such that when we traverse from each
marked node, the logic cone has 6 inputs or less, or it is a multi-input AND.]
SideEffects []
SeeAlso []
***********************************************************************/
Cnf_Dat_t * Cnf_DeriveFastClauses( Aig_Man_t * p, int nOutputs )
{
Cnf_Dat_t * pCnf;
Vec_Int_t * vLits, * vClas, * vMap, * vTemp;
Vec_Ptr_t * vLeaves, * vNodes;
Vec_Int_t * vCover;
Aig_Obj_t * pObj;
int i, k, nVars, Entry, OutLit, DriLit;
vLits = Vec_IntAlloc( 1 << 16 );
vClas = Vec_IntAlloc( 1 << 12 );
vMap = Vec_IntStartFull( Aig_ManObjNumMax(p) );
// assign variables for the outputs
nVars = 1;
if ( nOutputs )
{
if ( Aig_ManRegNum(p) == 0 )
{
assert( nOutputs == Aig_ManCoNum(p) );
Aig_ManForEachCo( p, pObj, i )
Vec_IntWriteEntry( vMap, Aig_ObjId(pObj), nVars++ );
}
else
{
assert( nOutputs == Aig_ManRegNum(p) );
Aig_ManForEachLiSeq( p, pObj, i )
Vec_IntWriteEntry( vMap, Aig_ObjId(pObj), nVars++ );
}
}
// assign variables to the internal nodes
Aig_ManForEachNodeReverse( p, pObj, i )
if ( pObj->fMarkA )
Vec_IntWriteEntry( vMap, Aig_ObjId(pObj), nVars++ );
// assign variables to the PIs and constant node
Aig_ManForEachCi( p, pObj, i )
Vec_IntWriteEntry( vMap, Aig_ObjId(pObj), nVars++ );
Vec_IntWriteEntry( vMap, Aig_ObjId(Aig_ManConst1(p)), nVars++ );
// create clauses
vLeaves = Vec_PtrAlloc( 100 );
vNodes = Vec_PtrAlloc( 100 );
vCover = Vec_IntAlloc( 1 << 16 );
vTemp = Vec_IntAlloc( 100 );
Aig_ManForEachNodeReverse( p, pObj, i )
{
if ( !pObj->fMarkA )
continue;
Cnf_ComputeClauses( p, pObj, vLeaves, vNodes, vMap, vCover, vTemp );
Vec_IntForEachEntry( vTemp, Entry, k )
{
if ( Entry == 0 )
Vec_IntPush( vClas, Vec_IntSize(vLits) );
else
Vec_IntPush( vLits, Entry );
}
}
Vec_PtrFree( vLeaves );
Vec_PtrFree( vNodes );
Vec_IntFree( vCover );
Vec_IntFree( vTemp );
// create clauses for the outputs
Aig_ManForEachCo( p, pObj, i )
{
DriLit = Cnf_ObjGetLit( vMap, Aig_ObjFanin0(pObj), Aig_ObjFaninC0(pObj) );
if ( i < Aig_ManCoNum(p) - nOutputs )
{
Vec_IntPush( vClas, Vec_IntSize(vLits) );
Vec_IntPush( vLits, DriLit );
}
else
{
OutLit = Cnf_ObjGetLit( vMap, pObj, 0 );
// first clause
Vec_IntPush( vClas, Vec_IntSize(vLits) );
Vec_IntPush( vLits, OutLit );
Vec_IntPush( vLits, DriLit ^ 1 );
// second clause
Vec_IntPush( vClas, Vec_IntSize(vLits) );
Vec_IntPush( vLits, OutLit ^ 1 );
Vec_IntPush( vLits, DriLit );
}
}
// write the constant literal
OutLit = Cnf_ObjGetLit( vMap, Aig_ManConst1(p), 0 );
Vec_IntPush( vClas, Vec_IntSize(vLits) );
Vec_IntPush( vLits, OutLit );
// create structure
pCnf = ABC_CALLOC( Cnf_Dat_t, 1 );
pCnf->pMan = p;
pCnf->nVars = nVars;
pCnf->nLiterals = Vec_IntSize( vLits );
pCnf->nClauses = Vec_IntSize( vClas );
pCnf->pClauses = ABC_ALLOC( int *, pCnf->nClauses + 1 );
pCnf->pClauses[0] = Vec_IntReleaseArray( vLits );
Vec_IntForEachEntry( vClas, Entry, i )
pCnf->pClauses[i] = pCnf->pClauses[0] + Entry;
pCnf->pClauses[pCnf->nClauses] = pCnf->pClauses[0] + pCnf->nLiterals;
pCnf->pVarNums = Vec_IntReleaseArray( vMap );
// cleanup
Vec_IntFree( vLits );
Vec_IntFree( vClas );
Vec_IntFree( vMap );
return pCnf;
}
/**Function*************************************************************
Synopsis [Fast CNF computation.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Cnf_Dat_t * Cnf_DeriveFast( Aig_Man_t * p, int nOutputs )
{
Cnf_Dat_t * pCnf = NULL;
abctime clk;//, clkTotal = Abc_Clock();
// printf( "\n" );
Aig_ManCleanMarkAB( p );
// create initial marking
clk = Abc_Clock();
Cnf_DeriveFastMark( p );
// Abc_PrintTime( 1, "Marking", Abc_Clock() - clk );
// compute CNF size
clk = Abc_Clock();
pCnf = Cnf_DeriveFastClauses( p, nOutputs );
// Abc_PrintTime( 1, "Clauses", Abc_Clock() - clk );
// derive the resulting CNF
Aig_ManCleanMarkA( p );
// Abc_PrintTime( 1, "TOTAL ", Abc_Clock() - clkTotal );
// printf( "CNF stats: Vars = %6d. Clauses = %7d. Literals = %8d. \n", pCnf->nVars, pCnf->nClauses, pCnf->nLiterals );
// Cnf_DataFree( pCnf );
// pCnf = NULL;
return pCnf;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END