blob: 027d8eb27067187b6af534a46283fa5e0e0c886f [file] [log] [blame]
/**CFile****************************************************************
FileName [fraImp.c]
SystemName [ABC: Logic synthesis and verification system.]
PackageName [New FRAIG package.]
Synopsis [Detecting and proving implications.]
Author [Alan Mishchenko]
Affiliation [UC Berkeley]
Date [Ver. 1.0. Started - June 30, 2007.]
Revision [$Id: fraImp.c,v 1.00 2007/06/30 00:00:00 alanmi Exp $]
***********************************************************************/
#include "fra.h"
ABC_NAMESPACE_IMPL_START
////////////////////////////////////////////////////////////////////////
/// DECLARATIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
/**Function*************************************************************
Synopsis [Counts the number of 1s in each siminfo of each node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Fra_SmlCountOnesOne( Fra_Sml_t * p, int Node )
{
unsigned * pSim;
int k, Counter = 0;
pSim = Fra_ObjSim( p, Node );
for ( k = p->nWordsPref; k < p->nWordsTotal; k++ )
Counter += Aig_WordCountOnes( pSim[k] );
return Counter;
}
/**Function*************************************************************
Synopsis [Counts the number of 1s in each siminfo of each node.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int * Fra_SmlCountOnes( Fra_Sml_t * p )
{
Aig_Obj_t * pObj;
int i, * pnBits;
pnBits = ABC_ALLOC( int, Aig_ManObjNumMax(p->pAig) );
memset( pnBits, 0, sizeof(int) * Aig_ManObjNumMax(p->pAig) );
Aig_ManForEachObj( p->pAig, pObj, i )
pnBits[i] = Fra_SmlCountOnesOne( p, i );
return pnBits;
}
/**Function*************************************************************
Synopsis [Returns 1 if implications holds.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Sml_NodeCheckImp( Fra_Sml_t * p, int Left, int Right )
{
unsigned * pSimL, * pSimR;
int k;
pSimL = Fra_ObjSim( p, Left );
pSimR = Fra_ObjSim( p, Right );
for ( k = p->nWordsPref; k < p->nWordsTotal; k++ )
if ( pSimL[k] & ~pSimR[k] )
return 0;
return 1;
}
/**Function*************************************************************
Synopsis [Counts the number of 1s in the complement of the implication.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline int Sml_NodeNotImpWeight( Fra_Sml_t * p, int Left, int Right )
{
unsigned * pSimL, * pSimR;
int k, Counter = 0;
pSimL = Fra_ObjSim( p, Left );
pSimR = Fra_ObjSim( p, Right );
for ( k = p->nWordsPref; k < p->nWordsTotal; k++ )
Counter += Aig_WordCountOnes( pSimL[k] & ~pSimR[k] );
return Counter;
}
/**Function*************************************************************
Synopsis [Computes the complement of the implication.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
static inline void Sml_NodeSaveNotImpPatterns( Fra_Sml_t * p, int Left, int Right, unsigned * pResult )
{
unsigned * pSimL, * pSimR;
int k;
pSimL = Fra_ObjSim( p, Left );
pSimR = Fra_ObjSim( p, Right );
for ( k = p->nWordsPref; k < p->nWordsTotal; k++ )
pResult[k] |= pSimL[k] & ~pSimR[k];
}
/**Function*************************************************************
Synopsis [Returns the array of nodes sorted by the number of 1s.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Ptr_t * Fra_SmlSortUsingOnes( Fra_Sml_t * p, int fLatchCorr )
{
Aig_Obj_t * pObj;
Vec_Ptr_t * vNodes;
int i, nNodes, nTotal, nBits, * pnNodes, * pnBits, * pMemory;
assert( p->nWordsTotal > 0 );
// count 1s in each node's siminfo
pnBits = Fra_SmlCountOnes( p );
// count number of nodes having that many 1s
nNodes = 0;
nBits = p->nWordsTotal * 32;
pnNodes = ABC_ALLOC( int, nBits + 1 );
memset( pnNodes, 0, sizeof(int) * (nBits + 1) );
Aig_ManForEachObj( p->pAig, pObj, i )
{
if ( i == 0 ) continue;
// skip non-PI and non-internal nodes
if ( fLatchCorr )
{
if ( !Aig_ObjIsCi(pObj) )
continue;
}
else
{
if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) )
continue;
}
// skip nodes participating in the classes
// if ( Fra_ClassObjRepr(pObj) )
// continue;
assert( pnBits[i] <= nBits ); // "<" because of normalized info
pnNodes[pnBits[i]]++;
nNodes++;
}
// allocate memory for all the nodes
pMemory = ABC_ALLOC( int, nNodes + nBits + 1 );
// markup the memory for each node
vNodes = Vec_PtrAlloc( nBits + 1 );
Vec_PtrPush( vNodes, pMemory );
for ( i = 1; i <= nBits; i++ )
{
pMemory += pnNodes[i-1] + 1;
Vec_PtrPush( vNodes, pMemory );
}
// add the nodes
memset( pnNodes, 0, sizeof(int) * (nBits + 1) );
Aig_ManForEachObj( p->pAig, pObj, i )
{
if ( i == 0 ) continue;
// skip non-PI and non-internal nodes
if ( fLatchCorr )
{
if ( !Aig_ObjIsCi(pObj) )
continue;
}
else
{
if ( !Aig_ObjIsNode(pObj) && !Aig_ObjIsCi(pObj) )
continue;
}
// skip nodes participating in the classes
// if ( Fra_ClassObjRepr(pObj) )
// continue;
pMemory = (int *)Vec_PtrEntry( vNodes, pnBits[i] );
pMemory[ pnNodes[pnBits[i]]++ ] = i;
}
// add 0s in the end
nTotal = 0;
Vec_PtrForEachEntry( int *, vNodes, pMemory, i )
{
pMemory[ pnNodes[i]++ ] = 0;
nTotal += pnNodes[i];
}
assert( nTotal == nNodes + nBits + 1 );
ABC_FREE( pnNodes );
ABC_FREE( pnBits );
return vNodes;
}
/**Function*************************************************************
Synopsis [Returns the array of implications with the highest cost.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Fra_SmlSelectMaxCost( Vec_Int_t * vImps, int * pCosts, int nCostMax, int nImpLimit, int * pCostRange )
{
Vec_Int_t * vImpsNew;
int * pCostCount, nImpCount, Imp, i, c;
assert( Vec_IntSize(vImps) >= nImpLimit );
// count how many implications have each cost
pCostCount = ABC_ALLOC( int, nCostMax + 1 );
memset( pCostCount, 0, sizeof(int) * (nCostMax + 1) );
for ( i = 0; i < Vec_IntSize(vImps); i++ )
{
assert( pCosts[i] <= nCostMax );
pCostCount[ pCosts[i] ]++;
}
assert( pCostCount[0] == 0 );
// select the bound on the cost (above this bound, implication will be included)
nImpCount = 0;
for ( c = nCostMax; c > 0; c-- )
{
nImpCount += pCostCount[c];
if ( nImpCount >= nImpLimit )
break;
}
// printf( "Cost range >= %d.\n", c );
// collect implications with the given costs
vImpsNew = Vec_IntAlloc( nImpLimit );
Vec_IntForEachEntry( vImps, Imp, i )
{
if ( pCosts[i] < c )
continue;
Vec_IntPush( vImpsNew, Imp );
if ( Vec_IntSize( vImpsNew ) == nImpLimit )
break;
}
ABC_FREE( pCostCount );
if ( pCostRange )
*pCostRange = c;
return vImpsNew;
}
/**Function*************************************************************
Synopsis [Compares two implications using their largest ID.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Sml_CompareMaxId( unsigned short * pImp1, unsigned short * pImp2 )
{
int Max1 = Abc_MaxInt( pImp1[0], pImp1[1] );
int Max2 = Abc_MaxInt( pImp2[0], pImp2[1] );
if ( Max1 < Max2 )
return -1;
if ( Max1 > Max2 )
return 1;
return 0;
}
/**Function*************************************************************
Synopsis [Derives implication candidates.]
Description [Implication candidates have the property that
(1) they hold using sequential simulation information
(2) they do not hold using combinational simulation information
(3) they have as high expressive power as possible (heuristically)
that is, they are easy to disprove combinationally
meaning they cover relatively larger sequential subspace.]
SideEffects []
SeeAlso []
***********************************************************************/
Vec_Int_t * Fra_ImpDerive( Fra_Man_t * p, int nImpMaxLimit, int nImpUseLimit, int fLatchCorr )
{
int nSimWords = 64;
Fra_Sml_t * pSeq, * pComb;
Vec_Int_t * vImps, * vTemp;
Vec_Ptr_t * vNodes;
int * pImpCosts, * pNodesI, * pNodesK;
int nImpsTotal = 0, nImpsTried = 0, nImpsNonSeq = 0, nImpsComb = 0, nImpsCollected = 0;
int CostMin = ABC_INFINITY, CostMax = 0;
int i, k, Imp, CostRange;
abctime clk = Abc_Clock();
assert( Aig_ManObjNumMax(p->pManAig) < (1 << 15) );
assert( nImpMaxLimit > 0 && nImpUseLimit > 0 && nImpUseLimit <= nImpMaxLimit );
// normalize both managers
pComb = Fra_SmlSimulateComb( p->pManAig, nSimWords, 0 );
pSeq = Fra_SmlSimulateSeq( p->pManAig, p->pPars->nFramesP, nSimWords, 1, 1 );
// get the nodes sorted by the number of 1s
vNodes = Fra_SmlSortUsingOnes( pSeq, fLatchCorr );
// count the total number of implications
for ( k = nSimWords * 32; k > 0; k-- )
for ( i = k - 1; i > 0; i-- )
for ( pNodesI = (int *)Vec_PtrEntry( vNodes, i ); *pNodesI; pNodesI++ )
for ( pNodesK = (int *)Vec_PtrEntry( vNodes, k ); *pNodesK; pNodesK++ )
nImpsTotal++;
// compute implications and their costs
pImpCosts = ABC_ALLOC( int, nImpMaxLimit );
vImps = Vec_IntAlloc( nImpMaxLimit );
for ( k = pSeq->nWordsTotal * 32; k > 0; k-- )
for ( i = k - 1; i > 0; i-- )
{
// HERE WE ARE MISSING SOME POTENTIAL IMPLICATIONS (with complement!)
for ( pNodesI = (int *)Vec_PtrEntry( vNodes, i ); *pNodesI; pNodesI++ )
for ( pNodesK = (int *)Vec_PtrEntry( vNodes, k ); *pNodesK; pNodesK++ )
{
nImpsTried++;
if ( !Sml_NodeCheckImp(pSeq, *pNodesI, *pNodesK) )
{
nImpsNonSeq++;
continue;
}
if ( Sml_NodeCheckImp(pComb, *pNodesI, *pNodesK) )
{
nImpsComb++;
continue;
}
nImpsCollected++;
Imp = Fra_ImpCreate( *pNodesI, *pNodesK );
pImpCosts[ Vec_IntSize(vImps) ] = Sml_NodeNotImpWeight(pComb, *pNodesI, *pNodesK);
CostMin = Abc_MinInt( CostMin, pImpCosts[ Vec_IntSize(vImps) ] );
CostMax = Abc_MaxInt( CostMax, pImpCosts[ Vec_IntSize(vImps) ] );
Vec_IntPush( vImps, Imp );
if ( Vec_IntSize(vImps) == nImpMaxLimit )
goto finish;
}
}
finish:
Fra_SmlStop( pComb );
Fra_SmlStop( pSeq );
// select implications with the highest cost
CostRange = CostMin;
if ( Vec_IntSize(vImps) > nImpUseLimit )
{
vImps = Fra_SmlSelectMaxCost( vTemp = vImps, pImpCosts, nSimWords * 32, nImpUseLimit, &CostRange );
Vec_IntFree( vTemp );
}
// dealloc
ABC_FREE( pImpCosts );
{
void * pTemp = Vec_PtrEntry(vNodes, 0);
ABC_FREE( pTemp );
}
Vec_PtrFree( vNodes );
// reorder implications topologically
qsort( (void *)Vec_IntArray(vImps), Vec_IntSize(vImps), sizeof(int),
(int (*)(const void *, const void *)) Sml_CompareMaxId );
if ( p->pPars->fVerbose )
{
printf( "Implications: All = %d. Try = %d. NonSeq = %d. Comb = %d. Res = %d.\n",
nImpsTotal, nImpsTried, nImpsNonSeq, nImpsComb, nImpsCollected );
printf( "Implication weight: Min = %d. Pivot = %d. Max = %d. ",
CostMin, CostRange, CostMax );
ABC_PRT( "Time", Abc_Clock() - clk );
}
return vImps;
}
// the following three procedures are called to
// - add implications to the SAT solver
// - check implications using the SAT solver
// - refine implications using after a cex is generated
/**Function*************************************************************
Synopsis [Add implication clauses to the SAT solver.]
Description [Note that implications should be checked in the first frame!]
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ImpAddToSolver( Fra_Man_t * p, Vec_Int_t * vImps, int * pSatVarNums )
{
sat_solver * pSat = p->pSat;
Aig_Obj_t * pLeft, * pRight;
Aig_Obj_t * pLeftF, * pRightF;
int pLits[2], Imp, Left, Right, i, f, status;
int fComplL, fComplR;
Vec_IntForEachEntry( vImps, Imp, i )
{
// get the corresponding nodes
pLeft = Aig_ManObj( p->pManAig, Fra_ImpLeft(Imp) );
pRight = Aig_ManObj( p->pManAig, Fra_ImpRight(Imp) );
// check if all the nodes are present
for ( f = 0; f < p->pPars->nFramesK; f++ )
{
// map these info fraig
pLeftF = Fra_ObjFraig( pLeft, f );
pRightF = Fra_ObjFraig( pRight, f );
if ( Aig_ObjIsNone(Aig_Regular(pLeftF)) || Aig_ObjIsNone(Aig_Regular(pRightF)) )
{
Vec_IntWriteEntry( vImps, i, 0 );
break;
}
}
if ( f < p->pPars->nFramesK )
continue;
// add constraints in each timeframe
for ( f = 0; f < p->pPars->nFramesK; f++ )
{
// map these info fraig
pLeftF = Fra_ObjFraig( pLeft, f );
pRightF = Fra_ObjFraig( pRight, f );
// get the corresponding SAT numbers
Left = pSatVarNums[ Aig_Regular(pLeftF)->Id ];
Right = pSatVarNums[ Aig_Regular(pRightF)->Id ];
assert( Left > 0 && Left < p->nSatVars );
assert( Right > 0 && Right < p->nSatVars );
// get the complemented attributes
fComplL = pLeft->fPhase ^ Aig_IsComplement(pLeftF);
fComplR = pRight->fPhase ^ Aig_IsComplement(pRightF);
// get the constraint
// L => R L' v R (complement = L & R')
pLits[0] = 2 * Left + !fComplL;
pLits[1] = 2 * Right + fComplR;
// add constraint to solver
if ( !sat_solver_addclause( pSat, pLits, pLits + 2 ) )
{
sat_solver_delete( pSat );
p->pSat = NULL;
return;
}
}
}
status = sat_solver_simplify(pSat);
if ( status == 0 )
{
sat_solver_delete( pSat );
p->pSat = NULL;
}
// printf( "Total imps = %d. ", Vec_IntSize(vImps) );
Fra_ImpCompactArray( vImps );
// printf( "Valid imps = %d. \n", Vec_IntSize(vImps) );
}
/**Function*************************************************************
Synopsis [Check implications for the node (if they are present).]
Description [Returns the new position in the array.]
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ImpCheckForNode( Fra_Man_t * p, Vec_Int_t * vImps, Aig_Obj_t * pNode, int Pos )
{
Aig_Obj_t * pLeft, * pRight;
Aig_Obj_t * pLeftF, * pRightF;
int i, Imp, Left, Right, Max, RetValue;
int fComplL, fComplR;
Vec_IntForEachEntryStart( vImps, Imp, i, Pos )
{
if ( Imp == 0 )
continue;
Left = Fra_ImpLeft(Imp);
Right = Fra_ImpRight(Imp);
Max = Abc_MaxInt( Left, Right );
assert( Max >= pNode->Id );
if ( Max > pNode->Id )
return i;
// get the corresponding nodes
pLeft = Aig_ManObj( p->pManAig, Left );
pRight = Aig_ManObj( p->pManAig, Right );
// get the corresponding FRAIG nodes
pLeftF = Fra_ObjFraig( pLeft, p->pPars->nFramesK );
pRightF = Fra_ObjFraig( pRight, p->pPars->nFramesK );
// get the complemented attributes
fComplL = pLeft->fPhase ^ Aig_IsComplement(pLeftF);
fComplR = pRight->fPhase ^ Aig_IsComplement(pRightF);
// check equality
if ( Aig_Regular(pLeftF) == Aig_Regular(pRightF) )
{
if ( fComplL == fComplR ) // x => x - always true
continue;
assert( fComplL != fComplR );
// consider 4 possibilities:
// NOT(1) => 1 or 0 => 1 - always true
// 1 => NOT(1) or 1 => 0 - never true
// NOT(x) => x or x - not always true
// x => NOT(x) or NOT(x) - not always true
if ( Aig_ObjIsConst1(Aig_Regular(pLeftF)) && fComplL ) // proved implication
continue;
// disproved implication
p->pCla->fRefinement = 1;
Vec_IntWriteEntry( vImps, i, 0 );
continue;
}
// check the implication
// - if true, a clause is added
// - if false, a cex is simulated
// make sure the implication is refined
RetValue = Fra_NodesAreImp( p, Aig_Regular(pLeftF), Aig_Regular(pRightF), fComplL, fComplR );
if ( RetValue != 1 )
{
p->pCla->fRefinement = 1;
if ( RetValue == 0 )
Fra_SmlResimulate( p );
if ( Vec_IntEntry(vImps, i) != 0 )
printf( "Fra_ImpCheckForNode(): Implication is not refined!\n" );
assert( Vec_IntEntry(vImps, i) == 0 );
}
}
return i;
}
/**Function*************************************************************
Synopsis [Removes those implications that no longer hold.]
Description [Returns 1 if refinement has happened.]
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ImpRefineUsingCex( Fra_Man_t * p, Vec_Int_t * vImps )
{
Aig_Obj_t * pLeft, * pRight;
int Imp, i, RetValue = 0;
Vec_IntForEachEntry( vImps, Imp, i )
{
if ( Imp == 0 )
continue;
// get the corresponding nodes
pLeft = Aig_ManObj( p->pManAig, Fra_ImpLeft(Imp) );
pRight = Aig_ManObj( p->pManAig, Fra_ImpRight(Imp) );
// check if implication holds using this simulation info
if ( !Sml_NodeCheckImp(p->pSml, pLeft->Id, pRight->Id) )
{
Vec_IntWriteEntry( vImps, i, 0 );
RetValue = 1;
}
}
return RetValue;
}
/**Function*************************************************************
Synopsis [Removes empty implications.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ImpCompactArray( Vec_Int_t * vImps )
{
int i, k, Imp;
k = 0;
Vec_IntForEachEntry( vImps, Imp, i )
if ( Imp )
Vec_IntWriteEntry( vImps, k++, Imp );
Vec_IntShrink( vImps, k );
}
/**Function*************************************************************
Synopsis [Determines the ratio of the state space by computed implications.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
double Fra_ImpComputeStateSpaceRatio( Fra_Man_t * p )
{
int nSimWords = 64;
Fra_Sml_t * pComb;
unsigned * pResult;
double Ratio = 0.0;
int Left, Right, Imp, i;
if ( p->pCla->vImps == NULL || Vec_IntSize(p->pCla->vImps) == 0 )
return Ratio;
// simulate the AIG manager with combinational patterns
pComb = Fra_SmlSimulateComb( p->pManAig, nSimWords, 0 );
// go through the implications and collect where they do not hold
pResult = Fra_ObjSim( pComb, 0 );
assert( pResult[0] == 0 );
Vec_IntForEachEntry( p->pCla->vImps, Imp, i )
{
Left = Fra_ImpLeft(Imp);
Right = Fra_ImpRight(Imp);
Sml_NodeSaveNotImpPatterns( pComb, Left, Right, pResult );
}
// count the number of ones in this area
Ratio = 100.0 * Fra_SmlCountOnesOne( pComb, 0 ) / (32*(pComb->nWordsTotal-pComb->nWordsPref));
Fra_SmlStop( pComb );
return Ratio;
}
/**Function*************************************************************
Synopsis [Returns the number of failed implications.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
int Fra_ImpVerifyUsingSimulation( Fra_Man_t * p )
{
int nFrames = 2000;
int nSimWords = 8;
Fra_Sml_t * pSeq;
char * pfFails;
int Left, Right, Imp, i, Counter;
if ( p->pCla->vImps == NULL || Vec_IntSize(p->pCla->vImps) == 0 )
return 0;
// simulate the AIG manager with combinational patterns
pSeq = Fra_SmlSimulateSeq( p->pManAig, p->pPars->nFramesP, nFrames, nSimWords, 1 );
// go through the implications and check how many of them do not hold
pfFails = ABC_ALLOC( char, Vec_IntSize(p->pCla->vImps) );
memset( pfFails, 0, sizeof(char) * Vec_IntSize(p->pCla->vImps) );
Vec_IntForEachEntry( p->pCla->vImps, Imp, i )
{
Left = Fra_ImpLeft(Imp);
Right = Fra_ImpRight(Imp);
pfFails[i] = !Sml_NodeCheckImp( pSeq, Left, Right );
}
// count how many has failed
Counter = 0;
for ( i = 0; i < Vec_IntSize(p->pCla->vImps); i++ )
Counter += pfFails[i];
ABC_FREE( pfFails );
Fra_SmlStop( pSeq );
return Counter;
}
/**Function*************************************************************
Synopsis [Record proven implications in the AIG manager.]
Description []
SideEffects []
SeeAlso []
***********************************************************************/
void Fra_ImpRecordInManager( Fra_Man_t * p, Aig_Man_t * pNew )
{
Aig_Obj_t * pLeft, * pRight, * pMiter;
int nPosOld, Imp, i;
if ( p->pCla->vImps == NULL || Vec_IntSize(p->pCla->vImps) == 0 )
return;
// go through the implication
nPosOld = Aig_ManCoNum(pNew);
Vec_IntForEachEntry( p->pCla->vImps, Imp, i )
{
pLeft = Aig_ManObj( p->pManAig, Fra_ImpLeft(Imp) );
pRight = Aig_ManObj( p->pManAig, Fra_ImpRight(Imp) );
// record the implication: L' + R
pMiter = Aig_Or( pNew,
Aig_NotCond((Aig_Obj_t *)pLeft->pData, !pLeft->fPhase),
Aig_NotCond((Aig_Obj_t *)pRight->pData, pRight->fPhase) );
Aig_ObjCreateCo( pNew, pMiter );
}
pNew->nAsserts = Aig_ManCoNum(pNew) - nPosOld;
}
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
////////////////////////////////////////////////////////////////////////
ABC_NAMESPACE_IMPL_END