/**CFile**************************************************************** FileName [fraCore.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [New FRAIG package.] Synopsis [] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 30, 2007.] Revision [$Id: fraCore.c,v 1.00 2007/06/30 00:00:00 alanmi Exp $] ***********************************************************************/ #include "fra.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// /* Speculating reduction in the sequential case leads to an interesting situation when a counter-ex may not refine any classes. This happens for non-constant equivalence classes. In such cases the representative of the class (proved by simulation to be non-constant) may be reduced to a constant during the speculative reduction. The fraig-representative of this representative node is a constant node, even though this is a non-constant class. Experiments have shown that this situation happens very often at the beginning of the refinement iteration when there are many spurious candidate equivalence classes (especially if heavy-duty simulatation of BMC was node used at the beginning). As a result, the SAT solver run may return a counter-ex that distinguishes the given representative node from the constant-1 node but this counter-ex does not distinguish the nodes in the non-costant class... This is why there is no check of refinement after a counter-ex in the sequential case. */ //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Reports the status of the miter.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Fra_FraigMiterStatus( Aig_Man_t * p ) { Aig_Obj_t * pObj, * pChild; int i, CountConst0 = 0, CountNonConst0 = 0, CountUndecided = 0; if ( p->pData ) return 0; Aig_ManForEachPoSeq( p, pObj, i ) { pChild = Aig_ObjChild0(pObj); // check if the output is constant 0 if ( pChild == Aig_ManConst0(p) ) { CountConst0++; continue; } // check if the output is constant 1 if ( pChild == Aig_ManConst1(p) ) { CountNonConst0++; continue; } // check if the output is a primary input if ( Aig_ObjIsCi(Aig_Regular(pChild)) && Aig_ObjCioId(Aig_Regular(pChild)) < p->nTruePis ) { CountNonConst0++; continue; } // check if the output can be not constant 0 if ( Aig_Regular(pChild)->fPhase != (unsigned)Aig_IsComplement(pChild) ) { CountNonConst0++; continue; } CountUndecided++; } /* if ( p->pParams->fVerbose ) { printf( "Miter has %d outputs. ", Aig_ManCoNum(p->pManAig) ); printf( "Const0 = %d. ", CountConst0 ); printf( "NonConst0 = %d. ", CountNonConst0 ); printf( "Undecided = %d. ", CountUndecided ); printf( "\n" ); } */ if ( CountNonConst0 ) return 0; if ( CountUndecided ) return -1; return 1; } /**Function************************************************************* Synopsis [Reports the status of the miter.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Fra_FraigMiterAssertedOutput( Aig_Man_t * p ) { Aig_Obj_t * pObj, * pChild; int i; Aig_ManForEachPoSeq( p, pObj, i ) { pChild = Aig_ObjChild0(pObj); // check if the output is constant 0 if ( pChild == Aig_ManConst0(p) ) continue; // check if the output is constant 1 if ( pChild == Aig_ManConst1(p) ) return i; // check if the output can be not constant 0 if ( Aig_Regular(pChild)->fPhase != (unsigned)Aig_IsComplement(pChild) ) return i; } return -1; } /**Function************************************************************* Synopsis [Write speculative miter for one node.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ static inline void Fra_FraigNodeSpeculate( Fra_Man_t * p, Aig_Obj_t * pObj, Aig_Obj_t * pObjFraig, Aig_Obj_t * pObjReprFraig ) { static int Counter = 0; char FileName[20]; Aig_Man_t * pTemp; Aig_Obj_t * pNode; int i; // create manager with the logic for these two nodes pTemp = Aig_ManExtractMiter( p->pManFraig, pObjFraig, pObjReprFraig ); // dump the logic into a file sprintf( FileName, "aig\\%03d.blif", ++Counter ); Aig_ManDumpBlif( pTemp, FileName, NULL, NULL ); printf( "Speculation cone with %d nodes was written into file \"%s\".\n", Aig_ManNodeNum(pTemp), FileName ); // clean up Aig_ManStop( pTemp ); Aig_ManForEachObj( p->pManFraig, pNode, i ) pNode->pData = p; } /**Function************************************************************* Synopsis [Verifies the generated counter-ex.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Fra_FraigVerifyCounterEx( Fra_Man_t * p, Vec_Int_t * vCex ) { Aig_Obj_t * pObj, ** ppClass; int i, c; assert( Aig_ManCiNum(p->pManAig) == Vec_IntSize(vCex) ); // make sure the input pattern is not used Aig_ManForEachObj( p->pManAig, pObj, i ) assert( !pObj->fMarkB ); // simulate the cex through the AIG Aig_ManConst1(p->pManAig)->fMarkB = 1; Aig_ManForEachCi( p->pManAig, pObj, i ) pObj->fMarkB = Vec_IntEntry(vCex, i); Aig_ManForEachNode( p->pManAig, pObj, i ) pObj->fMarkB = (Aig_ObjFanin0(pObj)->fMarkB ^ Aig_ObjFaninC0(pObj)) & (Aig_ObjFanin1(pObj)->fMarkB ^ Aig_ObjFaninC1(pObj)); Aig_ManForEachCo( p->pManAig, pObj, i ) pObj->fMarkB = Aig_ObjFanin0(pObj)->fMarkB ^ Aig_ObjFaninC0(pObj); // check if the classes hold Vec_PtrForEachEntry( Aig_Obj_t *, p->pCla->vClasses1, pObj, i ) { if ( pObj->fPhase != pObj->fMarkB ) printf( "The node %d is not constant under cex!\n", pObj->Id ); } Vec_PtrForEachEntry( Aig_Obj_t **, p->pCla->vClasses, ppClass, i ) { for ( c = 1; ppClass[c]; c++ ) if ( (ppClass[0]->fPhase ^ ppClass[c]->fPhase) != (ppClass[0]->fMarkB ^ ppClass[c]->fMarkB) ) printf( "The nodes %d and %d are not equal under cex!\n", ppClass[0]->Id, ppClass[c]->Id ); // for ( c = 0; ppClass[c]; c++ ) // if ( Fra_ObjFraig(ppClass[c],p->pPars->nFramesK) == Aig_ManConst1(p->pManFraig) ) // printf( "A member of non-constant class has a constant repr!\n" ); } // clean the simulation pattern Aig_ManForEachObj( p->pManAig, pObj, i ) pObj->fMarkB = 0; } /**Function************************************************************* Synopsis [Performs fraiging for one node.] Description [Returns the fraiged node.] SideEffects [] SeeAlso [] ***********************************************************************/ static inline void Fra_FraigNode( Fra_Man_t * p, Aig_Obj_t * pObj ) { Aig_Obj_t * pObjRepr, * pObjFraig, * pObjFraig2, * pObjReprFraig; int RetValue; assert( !Aig_IsComplement(pObj) ); // get representative of this class pObjRepr = Fra_ClassObjRepr( pObj ); if ( pObjRepr == NULL || // this is a unique node (!p->pPars->fDoSparse && pObjRepr == Aig_ManConst1(p->pManAig)) ) // this is a sparse node return; // get the fraiged node pObjFraig = Fra_ObjFraig( pObj, p->pPars->nFramesK ); // get the fraiged representative pObjReprFraig = Fra_ObjFraig( pObjRepr, p->pPars->nFramesK ); // if the fraiged nodes are the same, return if ( Aig_Regular(pObjFraig) == Aig_Regular(pObjReprFraig) ) { p->nSatCallsSkipped++; return; } assert( p->pPars->nFramesK || Aig_Regular(pObjFraig) != Aig_ManConst1(p->pManFraig) ); // if they are proved different, the c-ex will be in p->pPatWords RetValue = Fra_NodesAreEquiv( p, Aig_Regular(pObjReprFraig), Aig_Regular(pObjFraig) ); if ( RetValue == 1 ) // proved equivalent { // if ( p->pPars->fChoicing ) // Aig_ObjCreateRepr( p->pManFraig, Aig_Regular(pObjReprFraig), Aig_Regular(pObjFraig) ); // the nodes proved equal pObjFraig2 = Aig_NotCond( pObjReprFraig, pObj->fPhase ^ pObjRepr->fPhase ); Fra_ObjSetFraig( pObj, p->pPars->nFramesK, pObjFraig2 ); return; } if ( RetValue == -1 ) // failed { if ( p->vTimeouts == NULL ) p->vTimeouts = Vec_PtrAlloc( 100 ); Vec_PtrPush( p->vTimeouts, pObj ); if ( !p->pPars->fSpeculate ) return; assert( 0 ); // speculate p->nSpeculs++; pObjFraig2 = Aig_NotCond( pObjReprFraig, pObj->fPhase ^ pObjRepr->fPhase ); Fra_ObjSetFraig( pObj, p->pPars->nFramesK, pObjFraig2 ); Fra_FraigNodeSpeculate( p, pObj, Aig_Regular(pObjFraig), Aig_Regular(pObjReprFraig) ); return; } // disprove the nodes p->pCla->fRefinement = 1; // if we do not include the node into those disproved, we may end up // merging this node with another representative, for which proof has timed out if ( p->vTimeouts ) Vec_PtrPush( p->vTimeouts, pObj ); // verify that the counter-example satisfies all the constraints // if ( p->vCex ) // Fra_FraigVerifyCounterEx( p, p->vCex ); // simulate the counter-example and return the Fraig node Fra_SmlResimulate( p ); if ( p->pManFraig->pData ) return; if ( !p->pPars->nFramesK && Fra_ClassObjRepr(pObj) == pObjRepr ) printf( "Fra_FraigNode(): Error in class refinement!\n" ); assert( p->pPars->nFramesK || Fra_ClassObjRepr(pObj) != pObjRepr ); } /**Function************************************************************* Synopsis [Performs fraiging for the internal nodes.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Fra_FraigSweep( Fra_Man_t * p ) { // Bar_Progress_t * pProgress = NULL; Aig_Obj_t * pObj, * pObjNew; int i, Pos = 0; int nBTracksOld; // fraig latch outputs Aig_ManForEachLoSeq( p->pManAig, pObj, i ) { Fra_FraigNode( p, pObj ); if ( p->pPars->fUseImps ) Pos = Fra_ImpCheckForNode( p, p->pCla->vImps, pObj, Pos ); } if ( p->pPars->fLatchCorr ) return; // fraig internal nodes // if ( !p->pPars->fDontShowBar ) // pProgress = Bar_ProgressStart( stdout, Aig_ManObjNumMax(p->pManAig) ); nBTracksOld = p->pPars->nBTLimitNode; Aig_ManForEachNode( p->pManAig, pObj, i ) { // if ( pProgress ) // Bar_ProgressUpdate( pProgress, i, NULL ); // derive and remember the new fraig node pObjNew = Aig_And( p->pManFraig, Fra_ObjChild0Fra(pObj,p->pPars->nFramesK), Fra_ObjChild1Fra(pObj,p->pPars->nFramesK) ); Fra_ObjSetFraig( pObj, p->pPars->nFramesK, pObjNew ); Aig_Regular(pObjNew)->pData = p; // quit if simulation detected a counter-example for a PO if ( p->pManFraig->pData ) continue; // if ( Aig_SupportSize(p->pManAig,pObj) > 16 ) // continue; // perform fraiging if ( p->pPars->nLevelMax && (int)pObj->Level > p->pPars->nLevelMax ) p->pPars->nBTLimitNode = 5; Fra_FraigNode( p, pObj ); if ( p->pPars->nLevelMax && (int)pObj->Level > p->pPars->nLevelMax ) p->pPars->nBTLimitNode = nBTracksOld; // check implications if ( p->pPars->fUseImps ) Pos = Fra_ImpCheckForNode( p, p->pCla->vImps, pObj, Pos ); } // if ( pProgress ) // Bar_ProgressStop( pProgress ); // try to prove the outputs of the miter p->nNodesMiter = Aig_ManNodeNum(p->pManFraig); // Fra_MiterStatus( p->pManFraig ); // if ( p->pPars->fProve && p->pManFraig->pData == NULL ) // Fra_MiterProve( p ); // compress implications after processing all of them if ( p->pPars->fUseImps ) Fra_ImpCompactArray( p->pCla->vImps ); } /**Function************************************************************* Synopsis [Performs fraiging of the AIG.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Aig_Man_t * Fra_FraigPerform( Aig_Man_t * pManAig, Fra_Par_t * pPars ) { Fra_Man_t * p; Aig_Man_t * pManAigNew; abctime clk; if ( Aig_ManNodeNum(pManAig) == 0 ) return Aig_ManDupOrdered(pManAig); clk = Abc_Clock(); p = Fra_ManStart( pManAig, pPars ); p->pManFraig = Fra_ManPrepareComb( p ); p->pSml = Fra_SmlStart( pManAig, 0, 1, pPars->nSimWords ); Fra_SmlSimulate( p, 0 ); // if ( p->pPars->fChoicing ) // Aig_ManReprStart( p->pManFraig, Aig_ManObjNumMax(p->pManAig) ); // collect initial states p->nLitsBeg = Fra_ClassesCountLits( p->pCla ); p->nNodesBeg = Aig_ManNodeNum(pManAig); p->nRegsBeg = Aig_ManRegNum(pManAig); // perform fraig sweep if ( p->pPars->fVerbose ) Fra_ClassesPrint( p->pCla, 1 ); Fra_FraigSweep( p ); // call back the procedure to check implications if ( pManAig->pImpFunc ) pManAig->pImpFunc( p, pManAig->pImpData ); // no need to filter one-hot clauses because they satisfy base case by construction // finalize the fraiged manager Fra_ManFinalizeComb( p ); if ( p->pPars->fChoicing ) { abctime clk2 = Abc_Clock(); Fra_ClassesCopyReprs( p->pCla, p->vTimeouts ); pManAigNew = Aig_ManDupRepr( p->pManAig, 1 ); Aig_ManReprStart( pManAigNew, Aig_ManObjNumMax(pManAigNew) ); Aig_ManTransferRepr( pManAigNew, p->pManAig ); Aig_ManMarkValidChoices( pManAigNew ); Aig_ManStop( p->pManFraig ); p->pManFraig = NULL; p->timeTrav += Abc_Clock() - clk2; } else { Fra_ClassesCopyReprs( p->pCla, p->vTimeouts ); Aig_ManCleanup( p->pManFraig ); pManAigNew = p->pManFraig; p->pManFraig = NULL; } p->timeTotal = Abc_Clock() - clk; // collect final stats p->nLitsEnd = Fra_ClassesCountLits( p->pCla ); p->nNodesEnd = Aig_ManNodeNum(pManAigNew); p->nRegsEnd = Aig_ManRegNum(pManAigNew); Fra_ManStop( p ); return pManAigNew; } /**Function************************************************************* Synopsis [Performs choicing of the AIG.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Aig_Man_t * Fra_FraigChoice( Aig_Man_t * pManAig, int nConfMax, int nLevelMax ) { Fra_Par_t Pars, * pPars = &Pars; Fra_ParamsDefault( pPars ); pPars->nBTLimitNode = nConfMax; pPars->fChoicing = 1; pPars->fDoSparse = 1; pPars->fSpeculate = 0; pPars->fProve = 0; pPars->fVerbose = 0; pPars->fDontShowBar = 1; pPars->nLevelMax = nLevelMax; return Fra_FraigPerform( pManAig, pPars ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Aig_Man_t * Fra_FraigEquivence( Aig_Man_t * pManAig, int nConfMax, int fProve ) { Aig_Man_t * pFraig; Fra_Par_t Pars, * pPars = &Pars; Fra_ParamsDefault( pPars ); pPars->nBTLimitNode = nConfMax; pPars->fChoicing = 0; pPars->fDoSparse = 1; pPars->fSpeculate = 0; pPars->fProve = fProve; pPars->fVerbose = 0; pPars->fDontShowBar = 1; pFraig = Fra_FraigPerform( pManAig, pPars ); return pFraig; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END