blob: f0ed1532028ca71b6330d213c2dfa97a0c6cb1e5 [file] [log] [blame]
/**CFile****************************************************************
FileName [abcSat.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [Network and node package.]
Synopsis [Procedures to solve the miter using the internal SAT sat_solver.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 20, 2005.]
Revision [$Id: abcSat.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
***********************************************************************/
#include "base/abc/abc.h"
#include "base/main/main.h"
#include "base/cmd/cmd.h"
#include "sat/bsat/satSolver.h"
#ifdef ABC_USE_CUDD
#include "bdd/extrab/extraBdd.h"
#endif
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
static sat_solver * Abc_NtkMiterSatCreateLogic( Abc_Ntk_t * pNtk, int fAllPrimes );
extern Vec_Int_t * Abc_NtkGetCiSatVarNums( Abc_Ntk_t * pNtk );
static int nMuxes;
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Attempts to solve the miter using an internal SAT sat_solver.]
Description [Returns -1 if timed out; 0 if SAT; 1 if UNSAT.]
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMiterSat( Abc_Ntk_t * pNtk, ABC_INT64_T nConfLimit, ABC_INT64_T nInsLimit, int fVerbose, ABC_INT64_T * pNumConfs, ABC_INT64_T * pNumInspects )
{
sat_solver * pSat;
lbool status;
int RetValue = 0;
abctime clk;
if ( pNumConfs )
*pNumConfs = 0;
if ( pNumInspects )
*pNumInspects = 0;
assert( Abc_NtkLatchNum(pNtk) == 0 );
// if ( Abc_NtkPoNum(pNtk) > 1 )
// fprintf( stdout, "Warning: The miter has %d outputs. SAT will try to prove all of them.\n", Abc_NtkPoNum(pNtk) );
// load clauses into the sat_solver
clk = Abc_Clock();
pSat = (sat_solver *)Abc_NtkMiterSatCreate( pNtk, 0 );
if ( pSat == NULL )
return 1;
//printf( "%d \n", pSat->clauses.size );
//sat_solver_delete( pSat );
//return 1;
// printf( "Created SAT problem with %d variable and %d clauses. ", sat_solver_nvars(pSat), sat_solver_nclauses(pSat) );
// ABC_PRT( "Time", Abc_Clock() - clk );
// simplify the problem
clk = Abc_Clock();
status = sat_solver_simplify(pSat);
// printf( "Simplified the problem to %d variables and %d clauses. ", sat_solver_nvars(pSat), sat_solver_nclauses(pSat) );
// ABC_PRT( "Time", Abc_Clock() - clk );
if ( status == 0 )
{
sat_solver_delete( pSat );
// printf( "The problem is UNSATISFIABLE after simplification.\n" );
return 1;
}
// solve the miter
clk = Abc_Clock();
if ( fVerbose )
pSat->verbosity = 1;
status = sat_solver_solve( pSat, NULL, NULL, (ABC_INT64_T)nConfLimit, (ABC_INT64_T)nInsLimit, (ABC_INT64_T)0, (ABC_INT64_T)0 );
if ( status == l_Undef )
{
// printf( "The problem timed out.\n" );
RetValue = -1;
}
else if ( status == l_True )
{
// printf( "The problem is SATISFIABLE.\n" );
RetValue = 0;
}
else if ( status == l_False )
{
// printf( "The problem is UNSATISFIABLE.\n" );
RetValue = 1;
}
else
assert( 0 );
// ABC_PRT( "SAT sat_solver time", Abc_Clock() - clk );
// printf( "The number of conflicts = %d.\n", (int)pSat->sat_solver_stats.conflicts );
// if the problem is SAT, get the counterexample
if ( status == l_True )
{
// Vec_Int_t * vCiIds = Abc_NtkGetCiIds( pNtk );
Vec_Int_t * vCiIds = Abc_NtkGetCiSatVarNums( pNtk );
pNtk->pModel = Sat_SolverGetModel( pSat, vCiIds->pArray, vCiIds->nSize );
Vec_IntFree( vCiIds );
}
// free the sat_solver
if ( fVerbose )
Sat_SolverPrintStats( stdout, pSat );
if ( pNumConfs )
*pNumConfs = (int)pSat->stats.conflicts;
if ( pNumInspects )
*pNumInspects = (int)pSat->stats.inspects;
sat_solver_store_write( pSat, "trace.cnf" );
sat_solver_store_free( pSat );
sat_solver_delete( pSat );
return RetValue;
}
/**Function*************************************************************
Synopsis [Returns the array of CI IDs.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Abc_NtkGetCiSatVarNums( Abc_Ntk_t * pNtk )
{
Vec_Int_t * vCiIds;
Abc_Obj_t * pObj;
int i;
vCiIds = Vec_IntAlloc( Abc_NtkCiNum(pNtk) );
Abc_NtkForEachCi( pNtk, pObj, i )
Vec_IntPush( vCiIds, (int)(ABC_PTRINT_T)pObj->pCopy );
return vCiIds;
}
/**Function*************************************************************
Synopsis [Adds trivial clause.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkClauseTriv( sat_solver * pSat, Abc_Obj_t * pNode, Vec_Int_t * vVars )
{
//printf( "Adding triv %d. %d\n", Abc_ObjRegular(pNode)->Id, (int)pSat->sat_solver_stats.clauses );
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond( (int)(ABC_PTRINT_T)Abc_ObjRegular(pNode)->pCopy, Abc_ObjIsComplement(pNode) ) );
// Vec_IntPush( vVars, toLitCond( (int)Abc_ObjRegular(pNode)->Id, Abc_ObjIsComplement(pNode) ) );
return sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
}
/**Function*************************************************************
Synopsis [Adds trivial clause.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkClauseTop( sat_solver * pSat, Vec_Ptr_t * vNodes, Vec_Int_t * vVars )
{
Abc_Obj_t * pNode;
int i;
//printf( "Adding triv %d. %d\n", Abc_ObjRegular(pNode)->Id, (int)pSat->sat_solver_stats.clauses );
vVars->nSize = 0;
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i )
Vec_IntPush( vVars, toLitCond( (int)(ABC_PTRINT_T)Abc_ObjRegular(pNode)->pCopy, Abc_ObjIsComplement(pNode) ) );
// Vec_IntPush( vVars, toLitCond( (int)Abc_ObjRegular(pNode)->Id, Abc_ObjIsComplement(pNode) ) );
return sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
}
/**Function*************************************************************
Synopsis [Adds trivial clause.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkClauseAnd( sat_solver * pSat, Abc_Obj_t * pNode, Vec_Ptr_t * vSuper, Vec_Int_t * vVars )
{
int fComp1, Var, Var1, i;
//printf( "Adding AND %d. (%d) %d\n", pNode->Id, vSuper->nSize+1, (int)pSat->sat_solver_stats.clauses );
assert( !Abc_ObjIsComplement( pNode ) );
assert( Abc_ObjIsNode( pNode ) );
// nVars = sat_solver_nvars(pSat);
Var = (int)(ABC_PTRINT_T)pNode->pCopy;
// Var = pNode->Id;
// assert( Var < nVars );
for ( i = 0; i < vSuper->nSize; i++ )
{
// get the predecessor nodes
// get the complemented attributes of the nodes
fComp1 = Abc_ObjIsComplement((Abc_Obj_t *)vSuper->pArray[i]);
// determine the variable numbers
Var1 = (int)(ABC_PTRINT_T)Abc_ObjRegular((Abc_Obj_t *)vSuper->pArray[i])->pCopy;
// Var1 = (int)Abc_ObjRegular(vSuper->pArray[i])->Id;
// check that the variables are in the SAT manager
// assert( Var1 < nVars );
// suppose the AND-gate is A * B = C
// add !A => !C or A + !C
// fprintf( pFile, "%d %d 0%c", Var1, -Var, 10 );
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(Var1, fComp1) );
Vec_IntPush( vVars, toLitCond(Var, 1 ) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
}
// add A & B => C or !A + !B + C
// fprintf( pFile, "%d %d %d 0%c", -Var1, -Var2, Var, 10 );
vVars->nSize = 0;
for ( i = 0; i < vSuper->nSize; i++ )
{
// get the predecessor nodes
// get the complemented attributes of the nodes
fComp1 = Abc_ObjIsComplement((Abc_Obj_t *)vSuper->pArray[i]);
// determine the variable numbers
Var1 = (int)(ABC_PTRINT_T)Abc_ObjRegular((Abc_Obj_t *)vSuper->pArray[i])->pCopy;
// Var1 = (int)Abc_ObjRegular(vSuper->pArray[i])->Id;
// add this variable to the array
Vec_IntPush( vVars, toLitCond(Var1, !fComp1) );
}
Vec_IntPush( vVars, toLitCond(Var, 0) );
return sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
}
/**Function*************************************************************
Synopsis [Adds trivial clause.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkClauseMux( sat_solver * pSat, Abc_Obj_t * pNode, Abc_Obj_t * pNodeC, Abc_Obj_t * pNodeT, Abc_Obj_t * pNodeE, Vec_Int_t * vVars )
{
int VarF, VarI, VarT, VarE, fCompT, fCompE;
//printf( "Adding mux %d. %d\n", pNode->Id, (int)pSat->sat_solver_stats.clauses );
assert( !Abc_ObjIsComplement( pNode ) );
assert( Abc_NodeIsMuxType( pNode ) );
// get the variable numbers
VarF = (int)(ABC_PTRINT_T)pNode->pCopy;
VarI = (int)(ABC_PTRINT_T)pNodeC->pCopy;
VarT = (int)(ABC_PTRINT_T)Abc_ObjRegular(pNodeT)->pCopy;
VarE = (int)(ABC_PTRINT_T)Abc_ObjRegular(pNodeE)->pCopy;
// VarF = (int)pNode->Id;
// VarI = (int)pNodeC->Id;
// VarT = (int)Abc_ObjRegular(pNodeT)->Id;
// VarE = (int)Abc_ObjRegular(pNodeE)->Id;
// get the complementation flags
fCompT = Abc_ObjIsComplement(pNodeT);
fCompE = Abc_ObjIsComplement(pNodeE);
// f = ITE(i, t, e)
// i' + t' + f
// i' + t + f'
// i + e' + f
// i + e + f'
// create four clauses
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarI, 1) );
Vec_IntPush( vVars, toLitCond(VarT, 1^fCompT) );
Vec_IntPush( vVars, toLitCond(VarF, 0) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarI, 1) );
Vec_IntPush( vVars, toLitCond(VarT, 0^fCompT) );
Vec_IntPush( vVars, toLitCond(VarF, 1) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarI, 0) );
Vec_IntPush( vVars, toLitCond(VarE, 1^fCompE) );
Vec_IntPush( vVars, toLitCond(VarF, 0) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarI, 0) );
Vec_IntPush( vVars, toLitCond(VarE, 0^fCompE) );
Vec_IntPush( vVars, toLitCond(VarF, 1) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
if ( VarT == VarE )
{
// assert( fCompT == !fCompE );
return 1;
}
// two additional clauses
// t' & e' -> f' t + e + f'
// t & e -> f t' + e' + f
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarT, 0^fCompT) );
Vec_IntPush( vVars, toLitCond(VarE, 0^fCompE) );
Vec_IntPush( vVars, toLitCond(VarF, 1) );
if ( !sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize ) )
return 0;
vVars->nSize = 0;
Vec_IntPush( vVars, toLitCond(VarT, 1^fCompT) );
Vec_IntPush( vVars, toLitCond(VarE, 1^fCompE) );
Vec_IntPush( vVars, toLitCond(VarF, 0) );
return sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
}
/**Function*************************************************************
Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkCollectSupergate_rec( Abc_Obj_t * pNode, Vec_Ptr_t * vSuper, int fFirst, int fStopAtMux )
{
int RetValue1, RetValue2, i;
// check if the node is visited
if ( Abc_ObjRegular(pNode)->fMarkB )
{
// check if the node occurs in the same polarity
for ( i = 0; i < vSuper->nSize; i++ )
if ( vSuper->pArray[i] == pNode )
return 1;
// check if the node is present in the opposite polarity
for ( i = 0; i < vSuper->nSize; i++ )
if ( vSuper->pArray[i] == Abc_ObjNot(pNode) )
return -1;
assert( 0 );
return 0;
}
// if the new node is complemented or a PI, another gate begins
if ( !fFirst )
if ( Abc_ObjIsComplement(pNode) || !Abc_ObjIsNode(pNode) || Abc_ObjFanoutNum(pNode) > 1 || (fStopAtMux && Abc_NodeIsMuxType(pNode)) )
{
Vec_PtrPush( vSuper, pNode );
Abc_ObjRegular(pNode)->fMarkB = 1;
return 0;
}
assert( !Abc_ObjIsComplement(pNode) );
assert( Abc_ObjIsNode(pNode) );
// go through the branches
RetValue1 = Abc_NtkCollectSupergate_rec( Abc_ObjChild0(pNode), vSuper, 0, fStopAtMux );
RetValue2 = Abc_NtkCollectSupergate_rec( Abc_ObjChild1(pNode), vSuper, 0, fStopAtMux );
if ( RetValue1 == -1 || RetValue2 == -1 )
return -1;
// return 1 if at least one branch has a duplicate
return RetValue1 || RetValue2;
}
/**Function*************************************************************
Synopsis [Returns the array of nodes to be combined into one multi-input AND-gate.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkCollectSupergate( Abc_Obj_t * pNode, int fStopAtMux, Vec_Ptr_t * vNodes )
{
int RetValue, i;
assert( !Abc_ObjIsComplement(pNode) );
// collect the nodes in the implication supergate
Vec_PtrClear( vNodes );
RetValue = Abc_NtkCollectSupergate_rec( pNode, vNodes, 1, fStopAtMux );
assert( vNodes->nSize > 1 );
// unmark the visited nodes
for ( i = 0; i < vNodes->nSize; i++ )
Abc_ObjRegular((Abc_Obj_t *)vNodes->pArray[i])->fMarkB = 0;
// if we found the node and its complement in the same implication supergate,
// return empty set of nodes (meaning that we should use constant-0 node)
if ( RetValue == -1 )
vNodes->nSize = 0;
}
/**Function*************************************************************
Synopsis [Computes the factor of the node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkNodeFactor( Abc_Obj_t * pObj, int nLevelMax )
{
// nLevelMax = ((nLevelMax)/2)*3;
assert( (int)pObj->Level <= nLevelMax );
// return (int)(100000000.0 * pow(0.999, nLevelMax - pObj->Level));
return (int)(100000000.0 * (1 + 0.01 * pObj->Level));
// return (int)(100000000.0 / ((nLevelMax)/2)*3 - pObj->Level);
}
/**Function*************************************************************
Synopsis [Sets up the SAT sat_solver.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NtkMiterSatCreateInt( sat_solver * pSat, Abc_Ntk_t * pNtk )
{
Abc_Obj_t * pNode, * pFanin, * pNodeC, * pNodeT, * pNodeE;
Vec_Ptr_t * vNodes, * vSuper;
Vec_Int_t * vVars;
int i, k, fUseMuxes = 1;
// int fOrderCiVarsFirst = 0;
int RetValue = 0;
assert( Abc_NtkIsStrash(pNtk) );
// clean the CI node pointers
Abc_NtkForEachCi( pNtk, pNode, i )
pNode->pCopy = NULL;
// start the data structures
vNodes = Vec_PtrAlloc( 1000 ); // the nodes corresponding to vars in the sat_solver
vSuper = Vec_PtrAlloc( 100 ); // the nodes belonging to the given implication supergate
vVars = Vec_IntAlloc( 100 ); // the temporary array for variables in the clause
// add the clause for the constant node
pNode = Abc_AigConst1(pNtk);
pNode->fMarkA = 1;
pNode->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)vNodes->nSize;
Vec_PtrPush( vNodes, pNode );
Abc_NtkClauseTriv( pSat, pNode, vVars );
/*
// add the PI variables first
Abc_NtkForEachCi( pNtk, pNode, i )
{
pNode->fMarkA = 1;
pNode->pCopy = (Abc_Obj_t *)vNodes->nSize;
Vec_PtrPush( vNodes, pNode );
}
*/
// collect the nodes that need clauses and top-level assignments
Vec_PtrClear( vSuper );
Abc_NtkForEachCo( pNtk, pNode, i )
{
// get the fanin
pFanin = Abc_ObjFanin0(pNode);
// create the node's variable
if ( pFanin->fMarkA == 0 )
{
pFanin->fMarkA = 1;
pFanin->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)vNodes->nSize;
Vec_PtrPush( vNodes, pFanin );
}
// add the trivial clause
Vec_PtrPush( vSuper, Abc_ObjChild0(pNode) );
}
if ( !Abc_NtkClauseTop( pSat, vSuper, vVars ) )
goto Quits;
// add the clauses
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pNode, i )
{
assert( !Abc_ObjIsComplement(pNode) );
if ( !Abc_AigNodeIsAnd(pNode) )
continue;
//printf( "%d ", pNode->Id );
// add the clauses
if ( fUseMuxes && Abc_NodeIsMuxType(pNode) )
{
nMuxes++;
pNodeC = Abc_NodeRecognizeMux( pNode, &pNodeT, &pNodeE );
Vec_PtrClear( vSuper );
Vec_PtrPush( vSuper, pNodeC );
Vec_PtrPush( vSuper, pNodeT );
Vec_PtrPush( vSuper, pNodeE );
// add the fanin nodes to explore
Vec_PtrForEachEntry( Abc_Obj_t *, vSuper, pFanin, k )
{
pFanin = Abc_ObjRegular(pFanin);
if ( pFanin->fMarkA == 0 )
{
pFanin->fMarkA = 1;
pFanin->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)vNodes->nSize;
Vec_PtrPush( vNodes, pFanin );
}
}
// add the clauses
if ( !Abc_NtkClauseMux( pSat, pNode, pNodeC, pNodeT, pNodeE, vVars ) )
goto Quits;
}
else
{
// get the supergate
Abc_NtkCollectSupergate( pNode, fUseMuxes, vSuper );
// add the fanin nodes to explore
Vec_PtrForEachEntry( Abc_Obj_t *, vSuper, pFanin, k )
{
pFanin = Abc_ObjRegular(pFanin);
if ( pFanin->fMarkA == 0 )
{
pFanin->fMarkA = 1;
pFanin->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)vNodes->nSize;
Vec_PtrPush( vNodes, pFanin );
}
}
// add the clauses
if ( vSuper->nSize == 0 )
{
if ( !Abc_NtkClauseTriv( pSat, Abc_ObjNot(pNode), vVars ) )
// if ( !Abc_NtkClauseTriv( pSat, pNode, vVars ) )
goto Quits;
}
else
{
if ( !Abc_NtkClauseAnd( pSat, pNode, vSuper, vVars ) )
goto Quits;
}
}
}
/*
// set preferred variables
if ( fOrderCiVarsFirst )
{
int * pPrefVars = ABC_ALLOC( int, Abc_NtkCiNum(pNtk) );
int nVars = 0;
Abc_NtkForEachCi( pNtk, pNode, i )
{
if ( pNode->fMarkA == 0 )
continue;
pPrefVars[nVars++] = (int)pNode->pCopy;
}
nVars = Abc_MinInt( nVars, 10 );
ASat_SolverSetPrefVars( pSat, pPrefVars, nVars );
}
*/
/*
Abc_NtkForEachObj( pNtk, pNode, i )
{
if ( !pNode->fMarkA )
continue;
printf( "%10s : ", Abc_ObjName(pNode) );
printf( "%3d\n", (int)pNode->pCopy );
}
printf( "\n" );
*/
RetValue = 1;
Quits :
// delete
Vec_IntFree( vVars );
Vec_PtrFree( vNodes );
Vec_PtrFree( vSuper );
return RetValue;
}
/**Function*************************************************************
Synopsis [Sets up the SAT sat_solver.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void * Abc_NtkMiterSatCreate( Abc_Ntk_t * pNtk, int fAllPrimes )
{
sat_solver * pSat;
Abc_Obj_t * pNode;
int RetValue, i; //, clk = Abc_Clock();
assert( Abc_NtkIsStrash(pNtk) || Abc_NtkIsBddLogic(pNtk) );
if ( Abc_NtkIsBddLogic(pNtk) )
return Abc_NtkMiterSatCreateLogic(pNtk, fAllPrimes);
nMuxes = 0;
pSat = sat_solver_new();
//sat_solver_store_alloc( pSat );
RetValue = Abc_NtkMiterSatCreateInt( pSat, pNtk );
sat_solver_store_mark_roots( pSat );
Abc_NtkForEachObj( pNtk, pNode, i )
pNode->fMarkA = 0;
// ASat_SolverWriteDimacs( pSat, "temp_sat.cnf", NULL, NULL, 1 );
if ( RetValue == 0 )
{
sat_solver_delete(pSat);
return NULL;
}
// printf( "Ands = %6d. Muxes = %6d (%5.2f %%). ", Abc_NtkNodeNum(pNtk), nMuxes, 300.0*nMuxes/Abc_NtkNodeNum(pNtk) );
// ABC_PRT( "Creating sat_solver", Abc_Clock() - clk );
return pSat;
}
#ifdef ABC_USE_CUDD
/**Function*************************************************************
Synopsis [Adds clauses for the internal node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeAddClauses( sat_solver * pSat, char * pSop0, char * pSop1, Abc_Obj_t * pNode, Vec_Int_t * vVars )
{
Abc_Obj_t * pFanin;
int i, c, nFanins;
int RetValue = 0;
char * pCube;
nFanins = Abc_ObjFaninNum( pNode );
assert( nFanins == Abc_SopGetVarNum( pSop0 ) );
// if ( nFanins == 0 )
if ( Cudd_Regular((Abc_Obj_t *)pNode->pData) == Cudd_ReadOne((DdManager *)pNode->pNtk->pManFunc) )
{
vVars->nSize = 0;
// if ( Abc_SopIsConst1(pSop1) )
if ( !Cudd_IsComplement(pNode->pData) )
Vec_IntPush( vVars, toLit(pNode->Id) );
else
Vec_IntPush( vVars, lit_neg(toLit(pNode->Id)) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
return 1;
}
// add clauses for the negative phase
for ( c = 0; ; c++ )
{
// get the cube
pCube = pSop0 + c * (nFanins + 3);
if ( *pCube == 0 )
break;
// add the clause
vVars->nSize = 0;
Abc_ObjForEachFanin( pNode, pFanin, i )
{
if ( pCube[i] == '0' )
Vec_IntPush( vVars, toLit(pFanin->Id) );
else if ( pCube[i] == '1' )
Vec_IntPush( vVars, lit_neg(toLit(pFanin->Id)) );
}
Vec_IntPush( vVars, lit_neg(toLit(pNode->Id)) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
}
// add clauses for the positive phase
for ( c = 0; ; c++ )
{
// get the cube
pCube = pSop1 + c * (nFanins + 3);
if ( *pCube == 0 )
break;
// add the clause
vVars->nSize = 0;
Abc_ObjForEachFanin( pNode, pFanin, i )
{
if ( pCube[i] == '0' )
Vec_IntPush( vVars, toLit(pFanin->Id) );
else if ( pCube[i] == '1' )
Vec_IntPush( vVars, lit_neg(toLit(pFanin->Id)) );
}
Vec_IntPush( vVars, toLit(pNode->Id) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
}
return 1;
}
/**Function*************************************************************
Synopsis [Adds clauses for the PO node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Abc_NodeAddClausesTop( sat_solver * pSat, Abc_Obj_t * pNode, Vec_Int_t * vVars )
{
Abc_Obj_t * pFanin;
int RetValue = 0;
pFanin = Abc_ObjFanin0(pNode);
if ( Abc_ObjFaninC0(pNode) )
{
vVars->nSize = 0;
Vec_IntPush( vVars, toLit(pFanin->Id) );
Vec_IntPush( vVars, toLit(pNode->Id) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
vVars->nSize = 0;
Vec_IntPush( vVars, lit_neg(toLit(pFanin->Id)) );
Vec_IntPush( vVars, lit_neg(toLit(pNode->Id)) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
}
else
{
vVars->nSize = 0;
Vec_IntPush( vVars, lit_neg(toLit(pFanin->Id)) );
Vec_IntPush( vVars, toLit(pNode->Id) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
vVars->nSize = 0;
Vec_IntPush( vVars, toLit(pFanin->Id) );
Vec_IntPush( vVars, lit_neg(toLit(pNode->Id)) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
}
vVars->nSize = 0;
Vec_IntPush( vVars, toLit(pNode->Id) );
RetValue = sat_solver_addclause( pSat, vVars->pArray, vVars->pArray + vVars->nSize );
if ( !RetValue )
{
printf( "The CNF is trivially UNSAT.\n" );
return 0;
}
return 1;
}
/**Function*************************************************************
Synopsis [Sets up the SAT sat_solver.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
sat_solver * Abc_NtkMiterSatCreateLogic( Abc_Ntk_t * pNtk, int fAllPrimes )
{
sat_solver * pSat;
Mem_Flex_t * pMmFlex;
Abc_Obj_t * pNode;
Vec_Str_t * vCube;
Vec_Int_t * vVars;
char * pSop0, * pSop1;
int i;
assert( Abc_NtkIsBddLogic(pNtk) );
// transfer the IDs to the copy field
Abc_NtkForEachPi( pNtk, pNode, i )
pNode->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)pNode->Id;
// start the data structures
pSat = sat_solver_new();
sat_solver_store_alloc( pSat );
pMmFlex = Mem_FlexStart();
vCube = Vec_StrAlloc( 100 );
vVars = Vec_IntAlloc( 100 );
// add clauses for each internal nodes
Abc_NtkForEachNode( pNtk, pNode, i )
{
// derive SOPs for both phases of the node
Abc_NodeBddToCnf( pNode, pMmFlex, vCube, fAllPrimes, &pSop0, &pSop1 );
// add the clauses to the sat_solver
if ( !Abc_NodeAddClauses( pSat, pSop0, pSop1, pNode, vVars ) )
{
sat_solver_delete( pSat );
pSat = NULL;
goto finish;
}
}
// add clauses for each PO
Abc_NtkForEachPo( pNtk, pNode, i )
{
if ( !Abc_NodeAddClausesTop( pSat, pNode, vVars ) )
{
sat_solver_delete( pSat );
pSat = NULL;
goto finish;
}
}
sat_solver_store_mark_roots( pSat );
finish:
// delete
Vec_StrFree( vCube );
Vec_IntFree( vVars );
Mem_FlexStop( pMmFlex, 0 );
return pSat;
}
#else
sat_solver * Abc_NtkMiterSatCreateLogic( Abc_Ntk_t * pNtk, int fAllPrimes ) { return NULL; }
#endif
/**Function*************************************************************
Synopsis [Writes CNF for the sorter with N inputs asserting Q ones.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Abc_NtkWriteSorterCnf( char * pFileName, int nVars, int nQueens )
{
char Command[100];
void * pAbc;
Abc_Ntk_t * pNtk;
Abc_Obj_t * pObj, * ppNodes[2], * ppRoots[2];
Vec_Ptr_t * vNodes;
FILE * pFile;
int i, Counter;
if ( nQueens <= 0 && nQueens >= nVars )
{
printf( "The number of queens (Q = %d) should belong to the interval: 0 < Q < %d.\n", nQueens, nQueens);
return;
}
assert( nQueens > 0 && nQueens < nVars );
pAbc = Abc_FrameGetGlobalFrame();
// generate sorter
sprintf( Command, "gen -s -N %d sorter%d.blif", nVars, nVars );
if ( Cmd_CommandExecute( (Abc_Frame_t *)pAbc, Command ) )
{
fprintf( stdout, "Cannot execute command \"%s\".\n", Command );
return;
}
// read the file
sprintf( Command, "read sorter%d.blif; strash", nVars );
if ( Cmd_CommandExecute( (Abc_Frame_t *)pAbc, Command ) )
{
fprintf( stdout, "Cannot execute command \"%s\".\n", Command );
return;
}
// get the current network
pNtk = Abc_FrameReadNtk((Abc_Frame_t *)pAbc);
// collect the nodes for the given two primary outputs
ppNodes[0] = Abc_NtkPo( pNtk, nVars - nQueens - 1 );
ppNodes[1] = Abc_NtkPo( pNtk, nVars - nQueens );
ppRoots[0] = Abc_ObjFanin0( ppNodes[0] );
ppRoots[1] = Abc_ObjFanin0( ppNodes[1] );
vNodes = Abc_NtkDfsNodes( pNtk, ppRoots, 2 );
// assign CNF variables
Counter = 0;
Abc_NtkForEachObj( pNtk, pObj, i )
pObj->pCopy = (Abc_Obj_t *)~0;
Abc_NtkForEachPi( pNtk, pObj, i )
pObj->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)Counter++;
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
pObj->pCopy = (Abc_Obj_t *)(ABC_PTRINT_T)Counter++;
/*
OutVar = pCnf->pVarNums[ pObj->Id ];
pVars[0] = pCnf->pVarNums[ Aig_ObjFanin0(pObj)->Id ];
pVars[1] = pCnf->pVarNums[ Aig_ObjFanin1(pObj)->Id ];
// positive phase
*pClas++ = pLits;
*pLits++ = 2 * OutVar;
*pLits++ = 2 * pVars[0] + !Aig_ObjFaninC0(pObj);
*pLits++ = 2 * pVars[1] + !Aig_ObjFaninC1(pObj);
// negative phase
*pClas++ = pLits;
*pLits++ = 2 * OutVar + 1;
*pLits++ = 2 * pVars[0] + Aig_ObjFaninC0(pObj);
*pClas++ = pLits;
*pLits++ = 2 * OutVar + 1;
*pLits++ = 2 * pVars[1] + Aig_ObjFaninC1(pObj);
*/
// add clauses for these nodes
pFile = fopen( pFileName, "w" );
fprintf( pFile, "c CNF for %d-bit sorter with %d bits set to 1 generated by ABC.\n", nVars, nQueens );
fprintf( pFile, "p cnf %d %d\n", Counter, 3 * Vec_PtrSize(vNodes) + 2 );
Vec_PtrForEachEntry( Abc_Obj_t *, vNodes, pObj, i )
{
// positive phase
fprintf( pFile, "%d %s%d %s%d 0\n", 1+(int)(ABC_PTRINT_T)pObj->pCopy,
Abc_ObjFaninC0(pObj)? "" : "-", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin0(pObj)->pCopy,
Abc_ObjFaninC1(pObj)? "" : "-", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin1(pObj)->pCopy );
// negative phase
fprintf( pFile, "-%d %s%d 0\n", 1+(int)(ABC_PTRINT_T)pObj->pCopy,
Abc_ObjFaninC0(pObj)? "-" : "", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin0(pObj)->pCopy );
fprintf( pFile, "-%d %s%d 0\n", 1+(int)(ABC_PTRINT_T)pObj->pCopy,
Abc_ObjFaninC1(pObj)? "-" : "", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin1(pObj)->pCopy );
}
Vec_PtrFree( vNodes );
/*
*pClas++ = pLits;
*pLits++ = 2 * OutVar + Aig_ObjFaninC0(pObj);
*/
// assert the first literal to zero
fprintf( pFile, "%s%d 0\n",
Abc_ObjFaninC0(ppNodes[0])? "" : "-", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin0(ppNodes[0])->pCopy );
// assert the second literal to one
fprintf( pFile, "%s%d 0\n",
Abc_ObjFaninC0(ppNodes[1])? "-" : "", 1+(int)(ABC_PTRINT_T)Abc_ObjFanin0(ppNodes[1])->pCopy );
fclose( pFile );
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END