blob: 82e12ec61650cab23881bbb3884984fc6a51c2f7 [file] [log] [blame]
/**CFile****************************************************************
FileName [msatOrder.c]
PackageName [A C version of SAT solver MINISAT, originally developed
in C++ by Niklas Een and Niklas Sorensson, Chalmers University of
Technology, Sweden: http://www.cs.chalmers.se/~een/Satzoo.]
Synopsis [The manager of variable assignment.]
Author [Alan Mishchenko <alanmi@eecs.berkeley.edu>]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - January 1, 2004.]
Revision [$Id: msatOrder.c,v 1.0 2005/05/30 1:00:00 alanmi Exp $]
***********************************************************************/
#include "msatInt.h"
ABC_NAMESPACE_IMPL_START
/*
The J-boundary (justification boundary) is defined as a set of unassigned
variables belonging to the cone of interest, such that for each of them,
there exist an adjacent assigned variable in the cone of interest.
*/
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
typedef struct Msat_OrderVar_t_ Msat_OrderVar_t;
typedef struct Msat_OrderRing_t_ Msat_OrderRing_t;
// the variable data structure
struct Msat_OrderVar_t_
{
Msat_OrderVar_t * pNext;
Msat_OrderVar_t * pPrev;
int Num;
};
// the ring of variables data structure (J-boundary)
struct Msat_OrderRing_t_
{
Msat_OrderVar_t * pRoot;
int nItems;
};
// the variable package data structure
struct Msat_Order_t_
{
Msat_Solver_t * pSat; // the SAT solver
Msat_OrderVar_t * pVars; // the storage for variables
int nVarsAlloc; // the number of variables allocated
Msat_OrderRing_t rVars; // the J-boundary as a ring of variables
};
//The solver can communicate to the variable order the following parts:
//- the array of current assignments (pSat->pAssigns)
//- the array of variable activities (pSat->pdActivity)
//- the array of variables currently in the cone (pSat->vConeVars)
//- the array of arrays of variables adjucent to each(pSat->vAdjacents)
#define Msat_OrderVarIsInBoundary( p, i ) ((p)->pVars[i].pNext)
#define Msat_OrderVarIsAssigned( p, i ) ((p)->pSat->pAssigns[i] != MSAT_VAR_UNASSIGNED)
#define Msat_OrderVarIsUsedInCone( p, i ) ((p)->pSat->vVarsUsed->pArray[i])
// iterator through the entries in J-boundary
#define Msat_OrderRingForEachEntry( pRing, pVar, pNext ) \
for ( pVar = pRing, \
pNext = pVar? pVar->pNext : NULL; \
pVar; \
pVar = (pNext != pRing)? pNext : NULL, \
pNext = pVar? pVar->pNext : NULL )
static void Msat_OrderRingAddLast( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar );
static void Msat_OrderRingRemove( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar );
extern clock_t timeSelect;
extern clock_t timeAssign;
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Allocates the ordering structure.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Msat_Order_t * Msat_OrderAlloc( Msat_Solver_t * pSat )
{
Msat_Order_t * p;
p = ALLOC( Msat_Order_t, 1 );
memset( p, 0, sizeof(Msat_Order_t) );
p->pSat = pSat;
Msat_OrderSetBounds( p, pSat->nVarsAlloc );
return p;
}
/**Function*************************************************************
Synopsis [Sets the bound of the ordering structure.]
Description [Should be called whenever the SAT solver is resized.]
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderSetBounds( Msat_Order_t * p, int nVarsMax )
{
int i;
// add variables if they are missing
if ( p->nVarsAlloc < nVarsMax )
{
p->pVars = REALLOC( Msat_OrderVar_t, p->pVars, nVarsMax );
for ( i = p->nVarsAlloc; i < nVarsMax; i++ )
{
p->pVars[i].pNext = p->pVars[i].pPrev = NULL;
p->pVars[i].Num = i;
}
p->nVarsAlloc = nVarsMax;
}
}
/**Function*************************************************************
Synopsis [Cleans the ordering structure.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderClean( Msat_Order_t * p, Msat_IntVec_t * vCone )
{
Msat_OrderVar_t * pVar, * pNext;
// quickly undo the ring
Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
pVar->pNext = pVar->pPrev = NULL;
p->rVars.pRoot = NULL;
p->rVars.nItems = 0;
}
/**Function*************************************************************
Synopsis [Checks that the J-boundary is okay.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Msat_OrderCheck( Msat_Order_t * p )
{
Msat_OrderVar_t * pVar, * pNext;
Msat_IntVec_t * vRound;
int * pRound, nRound;
int * pVars, nVars, i, k;
int Counter = 0;
// go through all the variables in the boundary
Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
{
assert( !Msat_OrderVarIsAssigned(p, pVar->Num) );
// go though all the variables in the neighborhood
// and check that it is true that there is least one assigned
vRound = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( p->pSat->vAdjacents, pVar->Num );
nRound = Msat_IntVecReadSize( vRound );
pRound = Msat_IntVecReadArray( vRound );
for ( i = 0; i < nRound; i++ )
{
if ( !Msat_OrderVarIsUsedInCone(p, pRound[i]) )
continue;
if ( Msat_OrderVarIsAssigned(p, pRound[i]) )
break;
}
// assert( i != nRound );
// if ( i == nRound )
// return 0;
if ( i == nRound )
Counter++;
}
if ( Counter > 0 )
printf( "%d(%d) ", Counter, p->rVars.nItems );
// we may also check other unassigned variables in the cone
// to make sure that if they are not in J-boundary,
// then they do not have an assigned neighbor
nVars = Msat_IntVecReadSize( p->pSat->vConeVars );
pVars = Msat_IntVecReadArray( p->pSat->vConeVars );
for ( i = 0; i < nVars; i++ )
{
assert( Msat_OrderVarIsUsedInCone(p, pVars[i]) );
// skip assigned vars, vars in the boundary, and vars not used in the cone
if ( Msat_OrderVarIsAssigned(p, pVars[i]) ||
Msat_OrderVarIsInBoundary(p, pVars[i]) )
continue;
// make sure, it does not have assigned neighbors
vRound = (Msat_IntVec_t *)Msat_ClauseVecReadEntry( p->pSat->vAdjacents, pVars[i] );
nRound = Msat_IntVecReadSize( vRound );
pRound = Msat_IntVecReadArray( vRound );
for ( k = 0; k < nRound; k++ )
{
if ( !Msat_OrderVarIsUsedInCone(p, pRound[k]) )
continue;
if ( Msat_OrderVarIsAssigned(p, pRound[k]) )
break;
}
// assert( k == nRound );
// if ( k != nRound )
// return 0;
}
return 1;
}
/**Function*************************************************************
Synopsis [Frees the ordering structure.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderFree( Msat_Order_t * p )
{
free( p->pVars );
free( p );
}
/**Function*************************************************************
Synopsis [Selects the next variable to assign.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Msat_OrderVarSelect( Msat_Order_t * p )
{
Msat_OrderVar_t * pVar, * pNext, * pVarBest;
double * pdActs = p->pSat->pdActivity;
double dfActBest;
// clock_t clk = clock();
pVarBest = NULL;
dfActBest = -1.0;
Msat_OrderRingForEachEntry( p->rVars.pRoot, pVar, pNext )
{
if ( dfActBest < pdActs[pVar->Num] )
{
dfActBest = pdActs[pVar->Num];
pVarBest = pVar;
}
}
//timeSelect += clock() - clk;
//timeAssign += clock() - clk;
//if ( pVarBest && pVarBest->Num % 1000 == 0 )
//printf( "%d ", p->rVars.nItems );
// Msat_OrderCheck( p );
if ( pVarBest )
{
assert( Msat_OrderVarIsUsedInCone(p, pVarBest->Num) );
return pVarBest->Num;
}
return MSAT_ORDER_UNKNOWN;
}
/**Function*************************************************************
Synopsis [Updates J-boundary when the variable is assigned.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderVarAssigned( Msat_Order_t * p, int Var )
{
Msat_IntVec_t * vRound;
int i;//, clk = clock();
// make sure the variable is in the boundary
assert( Var < p->nVarsAlloc );
// if it is not in the boundary (initial decision, random decision), do not remove
if ( Msat_OrderVarIsInBoundary( p, Var ) )
Msat_OrderRingRemove( &p->rVars, &p->pVars[Var] );
// add to the boundary those neighbors that are (1) unassigned, (2) not in boundary
// because for them we know that there is a variable (Var) which is assigned
vRound = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[Var];
for ( i = 0; i < vRound->nSize; i++ )
{
if ( !Msat_OrderVarIsUsedInCone(p, vRound->pArray[i]) )
continue;
if ( Msat_OrderVarIsAssigned(p, vRound->pArray[i]) )
continue;
if ( Msat_OrderVarIsInBoundary(p, vRound->pArray[i]) )
continue;
Msat_OrderRingAddLast( &p->rVars, &p->pVars[vRound->pArray[i]] );
}
//timeSelect += clock() - clk;
// Msat_OrderCheck( p );
}
/**Function*************************************************************
Synopsis [Updates the order after a variable is unassigned.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderVarUnassigned( Msat_Order_t * p, int Var )
{
Msat_IntVec_t * vRound, * vRound2;
int i, k;//, clk = clock();
// make sure the variable is not in the boundary
assert( Var < p->nVarsAlloc );
assert( !Msat_OrderVarIsInBoundary( p, Var ) );
// go through its neigbors - if one of them is assigned add this var
// add to the boundary those neighbors that are not there already
// this will also get rid of variable outside of the current cone
// because they are unassigned in Msat_SolverPrepare()
vRound = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[Var];
for ( i = 0; i < vRound->nSize; i++ )
if ( Msat_OrderVarIsAssigned(p, vRound->pArray[i]) )
break;
if ( i != vRound->nSize )
Msat_OrderRingAddLast( &p->rVars, &p->pVars[Var] );
// unassigning a variable may lead to its adjacents dropping from the boundary
for ( i = 0; i < vRound->nSize; i++ )
if ( Msat_OrderVarIsInBoundary(p, vRound->pArray[i]) )
{ // the neighbor is in the J-boundary (and unassigned)
assert( !Msat_OrderVarIsAssigned(p, vRound->pArray[i]) );
vRound2 = (Msat_IntVec_t *)p->pSat->vAdjacents->pArray[vRound->pArray[i]];
// go through its neighbors and determine if there is at least one assigned
for ( k = 0; k < vRound2->nSize; k++ )
if ( Msat_OrderVarIsAssigned(p, vRound2->pArray[k]) )
break;
if ( k == vRound2->nSize ) // there is no assigned vars, delete this one
Msat_OrderRingRemove( &p->rVars, &p->pVars[vRound->pArray[i]] );
}
//timeSelect += clock() - clk;
// Msat_OrderCheck( p );
}
/**Function*************************************************************
Synopsis [Updates the order after a variable changed weight.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderUpdate( Msat_Order_t * p, int Var )
{
}
/**Function*************************************************************
Synopsis [Adds node to the end of the ring.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderRingAddLast( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar )
{
//printf( "adding %d\n", pVar->Num );
// check that the node is not in a ring
assert( pVar->pPrev == NULL );
assert( pVar->pNext == NULL );
// if the ring is empty, make the node point to itself
pRing->nItems++;
if ( pRing->pRoot == NULL )
{
pRing->pRoot = pVar;
pVar->pPrev = pVar;
pVar->pNext = pVar;
return;
}
// if the ring is not empty, add it as the last entry
pVar->pPrev = pRing->pRoot->pPrev;
pVar->pNext = pRing->pRoot;
pVar->pPrev->pNext = pVar;
pVar->pNext->pPrev = pVar;
// move the root so that it points to the new entry
// pRing->pRoot = pRing->pRoot->pPrev;
}
/**Function*************************************************************
Synopsis [Removes the node from the ring.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Msat_OrderRingRemove( Msat_OrderRing_t * pRing, Msat_OrderVar_t * pVar )
{
//printf( "removing %d\n", pVar->Num );
// check that the var is in a ring
assert( pVar->pPrev );
assert( pVar->pNext );
pRing->nItems--;
if ( pRing->nItems == 0 )
{
assert( pRing->pRoot == pVar );
pVar->pPrev = NULL;
pVar->pNext = NULL;
pRing->pRoot = NULL;
return;
}
// move the root if needed
if ( pRing->pRoot == pVar )
pRing->pRoot = pVar->pNext;
// move the root to the next entry after pVar
// this way all the additions to the list will be traversed first
// pRing->pRoot = pVar->pPrev;
// delete the node
pVar->pPrev->pNext = pVar->pNext;
pVar->pNext->pPrev = pVar->pPrev;
pVar->pPrev = NULL;
pVar->pNext = NULL;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END