/**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