/**CFile**************************************************************** FileName [llb2Nonlin.c] SystemName [ABC: Logic synthesis and verification system.] PackageName [BDD based reachability.] Synopsis [Non-linear quantification scheduling.] Author [Alan Mishchenko] Affiliation [UC Berkeley] Date [Ver. 1.0. Started - June 20, 2005.] Revision [$Id: llb2Nonlin.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] ***********************************************************************/ #include "llbInt.h" #include "base/abc/abc.h" #include "aig/gia/giaAig.h" ABC_NAMESPACE_IMPL_START //////////////////////////////////////////////////////////////////////// /// DECLARATIONS /// //////////////////////////////////////////////////////////////////////// typedef struct Llb_Mnx_t_ Llb_Mnx_t; struct Llb_Mnx_t_ { // user info Aig_Man_t * pAig; // AIG manager Gia_ParLlb_t * pPars; // parameters // intermediate BDDs DdManager * dd; // BDD manager DdNode * bBad; // bad states in terms of CIs DdNode * bReached; // reached states DdNode * bCurrent; // from states DdNode * bNext; // to states Vec_Ptr_t * vRings; // onion rings in ddR Vec_Ptr_t * vRoots; // BDDs for partitions // structural info Vec_Int_t * vOrder; // for each object ID, its BDD variable number or -1 Vec_Int_t * vVars2Q; // 1 if variable is quantifiable; 0 othervise abctime timeImage; abctime timeRemap; abctime timeReo; abctime timeOther; abctime timeTotal; }; //extern int timeBuild, timeAndEx, timeOther; //extern int nSuppMax; //////////////////////////////////////////////////////////////////////// /// FUNCTION DEFINITIONS /// //////////////////////////////////////////////////////////////////////// /**Function************************************************************* Synopsis [Computes bad in working manager.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * Llb_Nonlin4ComputeBad( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) { Vec_Ptr_t * vNodes; DdNode * bBdd, * bBdd0, * bBdd1, * bTemp, * bResult, * bCube; Aig_Obj_t * pObj; int i; Aig_ManCleanData( pAig ); // assign elementary variables Aig_ManConst1(pAig)->pData = Cudd_ReadOne(dd); Aig_ManForEachCi( pAig, pObj, i ) pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); // compute internal nodes vNodes = Aig_ManDfsNodes( pAig, (Aig_Obj_t **)Vec_PtrArray(pAig->vCos), Saig_ManPoNum(pAig) ); Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) { if ( !Aig_ObjIsNode(pObj) ) continue; bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); if ( bBdd == NULL ) { Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) if ( Aig_ObjIsNode(pObj) && pObj->pData != NULL ) Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); Vec_PtrFree( vNodes ); return NULL; } Cudd_Ref( bBdd ); pObj->pData = bBdd; } // quantify PIs of each PO bResult = Cudd_ReadLogicZero( dd ); Cudd_Ref( bResult ); Saig_ManForEachPo( pAig, pObj, i ) { bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); bResult = Cudd_bddOr( dd, bTemp = bResult, bBdd0 ); if ( bResult == NULL ) { Cudd_RecursiveDeref( dd, bTemp ); break; } Cudd_Ref( bResult ); Cudd_RecursiveDeref( dd, bTemp ); } // deref Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) if ( Aig_ObjIsNode(pObj) && pObj->pData != NULL ) Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); Vec_PtrFree( vNodes ); if ( bResult ) { bCube = Cudd_ReadOne(dd); Cudd_Ref( bCube ); Saig_ManForEachPi( pAig, pObj, i ) { bCube = Cudd_bddAnd( dd, bTemp = bCube, (DdNode *)pObj->pData ); if ( bCube == NULL ) { Cudd_RecursiveDeref( dd, bTemp ); Cudd_RecursiveDeref( dd, bResult ); bResult = NULL; break; } Cudd_Ref( bCube ); Cudd_RecursiveDeref( dd, bTemp ); } if ( bResult != NULL ) { bResult = Cudd_bddExistAbstract( dd, bTemp = bResult, bCube ); Cudd_Ref( bResult ); Cudd_RecursiveDeref( dd, bTemp ); Cudd_RecursiveDeref( dd, bCube ); Cudd_Deref( bResult ); } } //if ( bResult ) //printf( "Bad state = %d.\n", Cudd_DagSize(bResult) ); return bResult; } /**Function************************************************************* Synopsis [Derives BDDs for the partitions.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Ptr_t * Llb_Nonlin4DerivePartitions( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) { Vec_Ptr_t * vRoots; Aig_Obj_t * pObj; DdNode * bBdd, * bBdd0, * bBdd1, * bPart; int i; Aig_ManCleanData( pAig ); // assign elementary variables Aig_ManConst1(pAig)->pData = Cudd_ReadOne(dd); Aig_ManForEachCi( pAig, pObj, i ) pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); Aig_ManForEachNode( pAig, pObj, i ) if ( Llb_ObjBddVar(vOrder, pObj) >= 0 ) { pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); Cudd_Ref( (DdNode *)pObj->pData ); } Saig_ManForEachLi( pAig, pObj, i ) pObj->pData = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObj) ); // compute intermediate BDDs vRoots = Vec_PtrAlloc( 100 ); Aig_ManForEachNode( pAig, pObj, i ) { bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); bBdd = Cudd_bddAnd( dd, bBdd0, bBdd1 ); if ( bBdd == NULL ) goto finish; Cudd_Ref( bBdd ); if ( pObj->pData == NULL ) { pObj->pData = bBdd; continue; } // create new partition bPart = Cudd_bddXnor( dd, (DdNode *)pObj->pData, bBdd ); if ( bPart == NULL ) goto finish; Cudd_Ref( bPart ); Cudd_RecursiveDeref( dd, bBdd ); Vec_PtrPush( vRoots, bPart ); //printf( "%d ", Cudd_DagSize(bPart) ); } // compute register output BDDs Saig_ManForEachLi( pAig, pObj, i ) { bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); bPart = Cudd_bddXnor( dd, (DdNode *)pObj->pData, bBdd0 ); if ( bPart == NULL ) goto finish; Cudd_Ref( bPart ); Vec_PtrPush( vRoots, bPart ); //printf( "%d ", Cudd_DagSize(bPart) ); } //printf( "\n" ); Aig_ManForEachNode( pAig, pObj, i ) Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); return vRoots; // early termination finish: Aig_ManForEachNode( pAig, pObj, i ) if ( pObj->pData ) Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); Vec_PtrForEachEntry( DdNode *, vRoots, bPart, i ) Cudd_RecursiveDeref( dd, bPart ); Vec_PtrFree( vRoots ); return NULL; } /**Function************************************************************* Synopsis [Find simple variable ordering.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Llb_Nonlin4CreateOrderSimple( Aig_Man_t * pAig ) { Vec_Int_t * vOrder; Aig_Obj_t * pObj; int i, Counter = 0; vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); Aig_ManForEachCi( pAig, pObj, i ) Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); Saig_ManForEachLi( pAig, pObj, i ) Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); return vOrder; } /**Function************************************************************* Synopsis [Find good static variable ordering.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_Nonlin4CreateOrder_rec( Aig_Man_t * pAig, Aig_Obj_t * pObj, Vec_Int_t * vOrder, int * pCounter ) { Aig_Obj_t * pFanin0, * pFanin1; if ( Aig_ObjIsTravIdCurrent(pAig, pObj) ) return; Aig_ObjSetTravIdCurrent( pAig, pObj ); assert( Llb_ObjBddVar(vOrder, pObj) < 0 ); if ( Aig_ObjIsCi(pObj) ) { // if ( Saig_ObjIsLo(pAig, pObj) ) // Vec_IntWriteEntry( vOrder, Aig_ObjId(Saig_ObjLoToLi(pAig, pObj)), (*pCounter)++ ); Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); return; } // try fanins with higher level first pFanin0 = Aig_ObjFanin0(pObj); pFanin1 = Aig_ObjFanin1(pObj); // if ( pFanin0->Level > pFanin1->Level || (pFanin0->Level == pFanin1->Level && pFanin0->Id < pFanin1->Id) ) if ( pFanin0->Level > pFanin1->Level ) { Llb_Nonlin4CreateOrder_rec( pAig, pFanin0, vOrder, pCounter ); Llb_Nonlin4CreateOrder_rec( pAig, pFanin1, vOrder, pCounter ); } else { Llb_Nonlin4CreateOrder_rec( pAig, pFanin1, vOrder, pCounter ); Llb_Nonlin4CreateOrder_rec( pAig, pFanin0, vOrder, pCounter ); } if ( pObj->fMarkA ) Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), (*pCounter)++ ); } /**Function************************************************************* Synopsis [Collect nodes with the given fanout count.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Llb_Nonlin4CollectHighRefNodes( Aig_Man_t * pAig, int nFans ) { Vec_Int_t * vNodes; Aig_Obj_t * pObj; int i; Aig_ManCleanMarkA( pAig ); Aig_ManForEachNode( pAig, pObj, i ) if ( Aig_ObjRefs(pObj) >= nFans ) pObj->fMarkA = 1; // unmark flop drivers Saig_ManForEachLi( pAig, pObj, i ) Aig_ObjFanin0(pObj)->fMarkA = 0; // collect mapping vNodes = Vec_IntAlloc( 100 ); Aig_ManForEachNode( pAig, pObj, i ) if ( pObj->fMarkA ) Vec_IntPush( vNodes, Aig_ObjId(pObj) ); Aig_ManCleanMarkA( pAig ); return vNodes; } /**Function************************************************************* Synopsis [Find good static variable ordering.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Llb_Nonlin4CreateOrder( Aig_Man_t * pAig ) { Vec_Int_t * vNodes = NULL; Vec_Int_t * vOrder; Aig_Obj_t * pObj; int i, Counter = 0; /* // mark internal nodes to be used Aig_ManCleanMarkA( pAig ); vNodes = Llb_Nonlin4CollectHighRefNodes( pAig, 4 ); Aig_ManForEachObjVec( vNodes, pAig, pObj, i ) pObj->fMarkA = 1; printf( "Techmapping added %d pivots.\n", Vec_IntSize(vNodes) ); */ // collect nodes in the order vOrder = Vec_IntStartFull( Aig_ManObjNumMax(pAig) ); Aig_ManIncrementTravId( pAig ); Aig_ObjSetTravIdCurrent( pAig, Aig_ManConst1(pAig) ); Saig_ManForEachLi( pAig, pObj, i ) { Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); Llb_Nonlin4CreateOrder_rec( pAig, Aig_ObjFanin0(pObj), vOrder, &Counter ); } Aig_ManForEachCi( pAig, pObj, i ) if ( Llb_ObjBddVar(vOrder, pObj) < 0 ) { // if ( Saig_ObjIsLo(pAig, pObj) ) // Vec_IntWriteEntry( vOrder, Aig_ObjId(Saig_ObjLoToLi(pAig, pObj)), Counter++ ); Vec_IntWriteEntry( vOrder, Aig_ObjId(pObj), Counter++ ); } assert( Counter <= Aig_ManCiNum(pAig) + Aig_ManRegNum(pAig) + (vNodes?Vec_IntSize(vNodes):0) ); Aig_ManCleanMarkA( pAig ); Vec_IntFreeP( &vNodes ); return vOrder; } /**Function************************************************************* Synopsis [Creates quantifiable varaibles for both types of traversal.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Int_t * Llb_Nonlin4CreateVars2Q( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fBackward ) { Vec_Int_t * vVars2Q; Aig_Obj_t * pObjLi, * pObjLo; int i; vVars2Q = Vec_IntAlloc( 0 ); Vec_IntFill( vVars2Q, Cudd_ReadSize(dd), 1 ); Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) Vec_IntWriteEntry( vVars2Q, Llb_ObjBddVar(vOrder, fBackward ? pObjLo : pObjLi), 0 ); return vVars2Q; } /**Function************************************************************* Synopsis [Compute initial state in terms of current state variables.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_Nonlin4SetupVarMap( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder ) { DdNode ** pVarsX, ** pVarsY; Aig_Obj_t * pObjLo, * pObjLi; int i; pVarsX = ABC_ALLOC( DdNode *, Cudd_ReadSize(dd) ); pVarsY = ABC_ALLOC( DdNode *, Cudd_ReadSize(dd) ); Saig_ManForEachLiLo( pAig, pObjLo, pObjLi, i ) { assert( Llb_ObjBddVar(vOrder, pObjLo) >= 0 ); assert( Llb_ObjBddVar(vOrder, pObjLi) >= 0 ); pVarsX[i] = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLo) ); pVarsY[i] = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLi) ); } Cudd_SetVarMap( dd, pVarsX, pVarsY, Aig_ManRegNum(pAig) ); ABC_FREE( pVarsX ); ABC_FREE( pVarsY ); } /**Function************************************************************* Synopsis [Compute initial state in terms of current state variables.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * Llb_Nonlin4ComputeInitState( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, int fBackward ) { Aig_Obj_t * pObjLi, * pObjLo; DdNode * bRes, * bVar, * bTemp; int i; abctime TimeStop; TimeStop = dd->TimeStop; dd->TimeStop = 0; bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) { bVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, fBackward? pObjLi : pObjLo) ); bRes = Cudd_bddAnd( dd, bTemp = bRes, Cudd_Not(bVar) ); Cudd_Ref( bRes ); Cudd_RecursiveDeref( dd, bTemp ); } Cudd_Deref( bRes ); dd->TimeStop = TimeStop; return bRes; } /**Function************************************************************* Synopsis [Compute initial state in terms of current state variables.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * Llb_Nonlin4ComputeCube( DdManager * dd, Aig_Man_t * pAig, Vec_Int_t * vOrder, char * pValues, int Flag ) { Aig_Obj_t * pObjLo, * pObjLi, * pObjTemp; DdNode * bRes, * bVar, * bTemp; int i; abctime TimeStop; TimeStop = dd->TimeStop; dd->TimeStop = 0; bRes = Cudd_ReadOne( dd ); Cudd_Ref( bRes ); Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) { if ( Flag ) pObjTemp = pObjLo, pObjLo = pObjLi, pObjLi = pObjTemp; // get the correspoding flop input variable bVar = Cudd_bddIthVar( dd, Llb_ObjBddVar(vOrder, pObjLi) ); if ( pValues[Llb_ObjBddVar(vOrder, pObjLo)] != 1 ) bVar = Cudd_Not(bVar); // create cube bRes = Cudd_bddAnd( dd, bTemp = bRes, bVar ); Cudd_Ref( bRes ); Cudd_RecursiveDeref( dd, bTemp ); } Cudd_Deref( bRes ); dd->TimeStop = TimeStop; return bRes; } /**Function************************************************************* Synopsis [Compute initial state in terms of current state variables.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_Nonlin4RecordState( Aig_Man_t * pAig, Vec_Int_t * vOrder, unsigned * pState, char * pValues, int fBackward ) { Aig_Obj_t * pObjLo, * pObjLi; int i; Saig_ManForEachLiLo( pAig, pObjLi, pObjLo, i ) if ( pValues[Llb_ObjBddVar(vOrder, fBackward? pObjLi : pObjLo)] == 1 ) Abc_InfoSetBit( pState, i ); } /**Function************************************************************* Synopsis [Multiply every partition by the cube.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Ptr_t * Llb_Nonlin4Multiply( DdManager * dd, DdNode * bCube, Vec_Ptr_t * vParts ) { Vec_Ptr_t * vNew; DdNode * bTemp, * bFunc; int i; vNew = Vec_PtrAlloc( Vec_PtrSize(vParts) ); Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) { bTemp = Cudd_bddAnd( dd, bFunc, bCube ); Cudd_Ref( bTemp ); Vec_PtrPush( vNew, bTemp ); } return vNew; } /**Function************************************************************* Synopsis [Multiply every partition by the cube.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_Nonlin4Deref( DdManager * dd, Vec_Ptr_t * vParts ) { DdNode * bFunc; int i; Vec_PtrForEachEntry( DdNode *, vParts, bFunc, i ) Cudd_RecursiveDeref( dd, bFunc ); Vec_PtrFree( vParts ); } /**Function************************************************************* Synopsis [Derives counter-example by backward reachability.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Vec_Ptr_t * Llb_Nonlin4DeriveCex( Llb_Mnx_t * p, int fBackward, int fVerbose ) { Vec_Int_t * vVars2Q; Vec_Ptr_t * vStates, * vRootsNew; Aig_Obj_t * pObj; DdNode * bState = NULL, * bImage, * bOneCube, * bRing; int i, v, RetValue;//, clk = Abc_Clock(); char * pValues; assert( Vec_PtrSize(p->vRings) > 0 ); // disable the timeout p->dd->TimeStop = 0; // start the state set vStates = Vec_PtrAllocSimInfo( Vec_PtrSize(p->vRings), Abc_BitWordNum(Aig_ManRegNum(p->pAig)) ); Vec_PtrCleanSimInfo( vStates, 0, Abc_BitWordNum(Aig_ManRegNum(p->pAig)) ); if ( fBackward ) Vec_PtrReverseOrder( vStates ); // get the last cube pValues = ABC_ALLOC( char, Cudd_ReadSize(p->dd) ); bOneCube = Cudd_bddIntersect( p->dd, (DdNode *)Vec_PtrEntryLast(p->vRings), p->bBad ); Cudd_Ref( bOneCube ); RetValue = Cudd_bddPickOneCube( p->dd, bOneCube, pValues ); Cudd_RecursiveDeref( p->dd, bOneCube ); assert( RetValue ); // record the cube Llb_Nonlin4RecordState( p->pAig, p->vOrder, (unsigned *)Vec_PtrEntryLast(vStates), pValues, fBackward ); // write state in terms of NS variables if ( Vec_PtrSize(p->vRings) > 1 ) { bState = Llb_Nonlin4ComputeCube( p->dd, p->pAig, p->vOrder, pValues, fBackward ); Cudd_Ref( bState ); } // perform backward analysis vVars2Q = Llb_Nonlin4CreateVars2Q( p->dd, p->pAig, p->vOrder, !fBackward ); Vec_PtrForEachEntryReverse( DdNode *, p->vRings, bRing, v ) { if ( v == Vec_PtrSize(p->vRings) - 1 ) continue; // preprocess partitions vRootsNew = Llb_Nonlin4Multiply( p->dd, bState, p->vRoots ); Cudd_RecursiveDeref( p->dd, bState ); // compute the next states bImage = Llb_Nonlin4Image( p->dd, vRootsNew, NULL, vVars2Q ); Cudd_Ref( bImage ); Llb_Nonlin4Deref( p->dd, vRootsNew ); // intersect with the previous set bOneCube = Cudd_bddIntersect( p->dd, bImage, bRing ); Cudd_Ref( bOneCube ); Cudd_RecursiveDeref( p->dd, bImage ); // find any assignment of the BDD RetValue = Cudd_bddPickOneCube( p->dd, bOneCube, pValues ); Cudd_RecursiveDeref( p->dd, bOneCube ); assert( RetValue ); // record the cube Llb_Nonlin4RecordState( p->pAig, p->vOrder, (unsigned *)Vec_PtrEntry(vStates, v), pValues, fBackward ); // check that we get the init state if ( v == 0 ) { Saig_ManForEachLo( p->pAig, pObj, i ) assert( fBackward || pValues[Llb_ObjBddVar(p->vOrder, pObj)] == 0 ); break; } // write state in terms of NS variables bState = Llb_Nonlin4ComputeCube( p->dd, p->pAig, p->vOrder, pValues, fBackward ); Cudd_Ref( bState ); } Vec_IntFree( vVars2Q ); ABC_FREE( pValues ); if ( fBackward ) Vec_PtrReverseOrder( vStates ); // if ( fVerbose ) // Abc_PrintTime( 1, "BDD-based cex generation time", Abc_Clock() - clk ); return vStates; } /**Function************************************************************* Synopsis [Perform reachability with hints.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Llb_Nonlin4Reachability( Llb_Mnx_t * p ) { DdNode * bAux; int nIters, nBddSizeFr = 0, nBddSizeTo = 0, nBddSizeTo2 = 0; abctime clkTemp, clkIter, clk = Abc_Clock(); assert( Aig_ManRegNum(p->pAig) > 0 ); if ( p->pPars->fBackward ) { // create bad state in the ring manager if ( !p->pPars->fSkipOutCheck ) { p->bBad = Llb_Nonlin4ComputeInitState( p->dd, p->pAig, p->vOrder, p->pPars->fBackward ); Cudd_Ref( p->bBad ); } // create init state if ( p->pPars->fCluster ) p->bCurrent = p->dd->bFunc, p->dd->bFunc = NULL; else { p->bCurrent = Llb_Nonlin4ComputeBad( p->dd, p->pAig, p->vOrder ); if ( p->bCurrent == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); p->pPars->iFrame = -1; return -1; } Cudd_Ref( p->bCurrent ); } // remap into the next states p->bCurrent = Cudd_bddVarMap( p->dd, bAux = p->bCurrent ); if ( p->bCurrent == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during remapping bad states.\n", p->pPars->TimeLimit ); Cudd_RecursiveDeref( p->dd, bAux ); p->pPars->iFrame = -1; return -1; } Cudd_Ref( p->bCurrent ); Cudd_RecursiveDeref( p->dd, bAux ); } else { // create bad state in the ring manager if ( !p->pPars->fSkipOutCheck ) { if ( p->pPars->fCluster ) p->bBad = p->dd->bFunc, p->dd->bFunc = NULL; else { p->bBad = Llb_Nonlin4ComputeBad( p->dd, p->pAig, p->vOrder ); if ( p->bBad == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during constructing the bad states.\n", p->pPars->TimeLimit ); p->pPars->iFrame = -1; return -1; } Cudd_Ref( p->bBad ); } } else if ( p->dd->bFunc ) Cudd_RecursiveDeref( p->dd, p->dd->bFunc ), p->dd->bFunc = NULL; // compute the starting set of states p->bCurrent = Llb_Nonlin4ComputeInitState( p->dd, p->pAig, p->vOrder, p->pPars->fBackward ); Cudd_Ref( p->bCurrent ); } // perform iterations p->bReached = p->bCurrent; Cudd_Ref( p->bReached ); for ( nIters = 0; nIters < p->pPars->nIterMax; nIters++ ) { clkIter = Abc_Clock(); // check the runtime limit if ( p->pPars->TimeLimit && Abc_Clock() > p->pPars->TimeTarget ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during image computation.\n", p->pPars->TimeLimit ); p->pPars->iFrame = nIters - 1; return -1; } // save the onion ring Vec_PtrPush( p->vRings, p->bCurrent ); Cudd_Ref( p->bCurrent ); // check it for bad states if ( !p->pPars->fSkipOutCheck && !Cudd_bddLeq( p->dd, p->bCurrent, Cudd_Not(p->bBad) ) ) { Vec_Ptr_t * vStates; assert( p->pAig->pSeqModel == NULL ); vStates = Llb_Nonlin4DeriveCex( p, p->pPars->fBackward, p->pPars->fVerbose ); p->pAig->pSeqModel = Llb4_Nonlin4TransformCex( p->pAig, vStates, -1, p->pPars->fVerbose ); Vec_PtrFreeP( &vStates ); if ( !p->pPars->fSilent ) { Abc_Print( 1, "Output %d of miter \"%s\" was asserted in frame %d. ", p->pAig->pSeqModel->iPo, p->pAig->pName, nIters ); Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); } p->pPars->iFrame = nIters - 1; return 0; } // compute the next states clkTemp = Abc_Clock(); p->bNext = Llb_Nonlin4Image( p->dd, p->vRoots, p->bCurrent, p->vVars2Q ); if ( p->bNext == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during image computation in quantification.\n", p->pPars->TimeLimit ); p->pPars->iFrame = nIters - 1; return -1; } Cudd_Ref( p->bNext ); p->timeImage += Abc_Clock() - clkTemp; // remap into current states clkTemp = Abc_Clock(); p->bNext = Cudd_bddVarMap( p->dd, bAux = p->bNext ); if ( p->bNext == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during remapping next states.\n", p->pPars->TimeLimit ); Cudd_RecursiveDeref( p->dd, bAux ); p->pPars->iFrame = nIters - 1; return -1; } Cudd_Ref( p->bNext ); Cudd_RecursiveDeref( p->dd, bAux ); p->timeRemap += Abc_Clock() - clkTemp; // collect statistics if ( p->pPars->fVerbose ) { nBddSizeFr = Cudd_DagSize( p->bCurrent ); nBddSizeTo = Cudd_DagSize( bAux ); nBddSizeTo2 = Cudd_DagSize( p->bNext ); } Cudd_RecursiveDeref( p->dd, p->bCurrent ); p->bCurrent = NULL; // derive new states p->bCurrent = Cudd_bddAnd( p->dd, p->bNext, Cudd_Not(p->bReached) ); if ( p->bCurrent == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); p->pPars->iFrame = nIters - 1; return -1; } Cudd_Ref( p->bCurrent ); Cudd_RecursiveDeref( p->dd, p->bNext ); p->bNext = NULL; if ( Cudd_IsConstant(p->bCurrent) ) break; /* // reduce BDD size using constrain // Cudd_bddRestrict p->bCurrent = Cudd_bddRestrict( p->dd, bAux = p->bCurrent, Cudd_Not(p->bReached) ); Cudd_Ref( p->bCurrent ); printf( "Before = %d. After = %d.\n", Cudd_DagSize(bAux), Cudd_DagSize(p->bCurrent) ); Cudd_RecursiveDeref( p->dd, bAux ); */ // add to the reached set p->bReached = Cudd_bddOr( p->dd, bAux = p->bReached, p->bCurrent ); if ( p->bReached == NULL ) { if ( !p->pPars->fSilent ) printf( "Reached timeout (%d seconds) during image computation in transfer 1.\n", p->pPars->TimeLimit ); p->pPars->iFrame = nIters - 1; Cudd_RecursiveDeref( p->dd, bAux ); return -1; } Cudd_Ref( p->bReached ); Cudd_RecursiveDeref( p->dd, bAux ); // report the results if ( p->pPars->fVerbose ) { printf( "I =%5d : ", nIters ); printf( "Fr =%7d ", nBddSizeFr ); printf( "ImNs =%7d ", nBddSizeTo ); printf( "ImCs =%7d ", nBddSizeTo2 ); printf( "Rea =%7d ", Cudd_DagSize(p->bReached) ); printf( "(%4d %4d) ", Cudd_ReadReorderings(p->dd), Cudd_ReadGarbageCollections(p->dd) ); Abc_PrintTime( 1, "T", Abc_Clock() - clkIter ); } /* if ( pPars->fVerbose ) { double nMints = Cudd_CountMinterm(p->dd, bReached, Saig_ManRegNum(p->pAig) ); // Extra_bddPrint( p->dd, bReached );printf( "\n" ); printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); fflush( stdout ); } */ if ( nIters == p->pPars->nIterMax - 1 ) { if ( !p->pPars->fSilent ) printf( "Reached limit on the number of timeframes (%d).\n", p->pPars->nIterMax ); p->pPars->iFrame = nIters; return -1; } } // report the stats if ( p->pPars->fVerbose ) { double nMints = Cudd_CountMinterm(p->dd, p->bReached, Saig_ManRegNum(p->pAig) ); if ( p->bCurrent && Cudd_IsConstant(p->bCurrent) ) printf( "Reachability analysis completed after %d frames.\n", nIters ); else printf( "Reachability analysis is stopped after %d frames.\n", nIters ); printf( "Reachable states = %.0f. (Ratio = %.4f %%)\n", nMints, 100.0*nMints/pow(2.0, Saig_ManRegNum(p->pAig)) ); fflush( stdout ); } if ( p->bCurrent == NULL || !Cudd_IsConstant(p->bCurrent) ) { if ( !p->pPars->fSilent ) printf( "Verified only for states reachable in %d frames. ", nIters ); p->pPars->iFrame = p->pPars->nIterMax; return -1; // undecided } // report if ( !p->pPars->fSilent ) printf( "The miter is proved unreachable after %d iterations. ", nIters ); if ( !p->pPars->fSilent ) Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); p->pPars->iFrame = nIters - 1; return 1; // unreachable } /**Function************************************************************* Synopsis [Reorders BDDs in the working manager.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_Nonlin4Reorder( DdManager * dd, int fTwice, int fVerbose ) { abctime clk = Abc_Clock(); if ( fVerbose ) Abc_Print( 1, "Reordering... Before =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); if ( fVerbose ) Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); if ( fTwice ) { Cudd_ReduceHeap( dd, CUDD_REORDER_SYMM_SIFT, 100 ); if ( fVerbose ) Abc_Print( 1, "After =%5d. ", Cudd_ReadKeys(dd) - Cudd_ReadDead(dd) ); } if ( fVerbose ) Abc_PrintTime( 1, "Time", Abc_Clock() - clk ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Llb_Mnx_t * Llb_MnxStart( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) { Llb_Mnx_t * p; p = ABC_CALLOC( Llb_Mnx_t, 1 ); p->pAig = pAig; p->pPars = pPars; // compute time to stop p->pPars->TimeTarget = p->pPars->TimeLimit ? p->pPars->TimeLimit * CLOCKS_PER_SEC + Abc_Clock(): 0; if ( pPars->fCluster ) { // Llb_Nonlin4Cluster( p->pAig, &p->dd, &p->vOrder, &p->vRoots, pPars->nBddMax, pPars->fVerbose ); // Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); Llb4_Nonlin4Sweep( p->pAig, pPars->nBddMax, pPars->nClusterMax, &p->dd, &p->vOrder, &p->vRoots, pPars->fVerbose ); // set the stop time parameter p->dd->TimeStop = p->pPars->TimeTarget; } else { // p->vOrder = Llb_Nonlin4CreateOrderSimple( pAig ); p->vOrder = Llb_Nonlin4CreateOrder( pAig ); p->dd = Cudd_Init( Vec_IntCountPositive(p->vOrder) + 1, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); Cudd_AutodynEnable( p->dd, CUDD_REORDER_SYMM_SIFT ); Cudd_SetMaxGrowth( p->dd, 1.05 ); // set the stop time parameter p->dd->TimeStop = p->pPars->TimeTarget; p->vRoots = Llb_Nonlin4DerivePartitions( p->dd, pAig, p->vOrder ); } Llb_Nonlin4SetupVarMap( p->dd, pAig, p->vOrder ); p->vVars2Q = Llb_Nonlin4CreateVars2Q( p->dd, pAig, p->vOrder, p->pPars->fBackward ); p->vRings = Vec_PtrAlloc( 100 ); if ( pPars->fReorder ) Llb_Nonlin4Reorder( p->dd, 0, 1 ); return p; } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_MnxStop( Llb_Mnx_t * p ) { DdNode * bTemp; int i; if ( p->pPars->fVerbose ) { p->timeReo = Cudd_ReadReorderingTime(p->dd); p->timeOther = p->timeTotal - p->timeImage - p->timeRemap; ABC_PRTP( "Image ", p->timeImage, p->timeTotal ); ABC_PRTP( "Remap ", p->timeRemap, p->timeTotal ); ABC_PRTP( "Other ", p->timeOther, p->timeTotal ); ABC_PRTP( "TOTAL ", p->timeTotal, p->timeTotal ); ABC_PRTP( " reo ", p->timeReo, p->timeTotal ); } // remove BDDs if ( p->bBad ) Cudd_RecursiveDeref( p->dd, p->bBad ); if ( p->bReached ) Cudd_RecursiveDeref( p->dd, p->bReached ); if ( p->bCurrent ) Cudd_RecursiveDeref( p->dd, p->bCurrent ); if ( p->bNext ) Cudd_RecursiveDeref( p->dd, p->bNext ); if ( p->vRings ) Vec_PtrForEachEntry( DdNode *, p->vRings, bTemp, i ) Cudd_RecursiveDeref( p->dd, bTemp ); if ( p->vRoots ) Vec_PtrForEachEntry( DdNode *, p->vRoots, bTemp, i ) Cudd_RecursiveDeref( p->dd, bTemp ); // remove arrays Vec_PtrFreeP( &p->vRings ); Vec_PtrFreeP( &p->vRoots ); //Cudd_PrintInfo( p->dd, stdout ); Extra_StopManager( p->dd ); Vec_IntFreeP( &p->vOrder ); Vec_IntFreeP( &p->vVars2Q ); ABC_FREE( p ); } /**Function************************************************************* Synopsis [] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Llb_MnxCheckNextStateVars( Llb_Mnx_t * p ) { Aig_Obj_t * pObj; int i, Counter0 = 0, Counter1 = 0; Saig_ManForEachLi( p->pAig, pObj, i ) if ( Saig_ObjIsLo(p->pAig, Aig_ObjFanin0(pObj)) ) { if ( Aig_ObjFaninC0(pObj) ) Counter0++; else Counter1++; } printf( "Total = %d. Direct LO = %d. Compl LO = %d.\n", Aig_ManRegNum(p->pAig), Counter1, Counter0 ); } /**Function************************************************************* Synopsis [Finds balanced cut.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Llb_Nonlin4CoreReach( Aig_Man_t * pAig, Gia_ParLlb_t * pPars ) { Llb_Mnx_t * pMnn; int RetValue = -1; if ( pPars->fVerbose ) Aig_ManPrintStats( pAig ); if ( pPars->fCluster && Aig_ManObjNum(pAig) >= (1 << 15) ) { printf( "The number of objects is more than 2^15. Clustering cannot be used.\n" ); return RetValue; } { abctime clk = Abc_Clock(); pMnn = Llb_MnxStart( pAig, pPars ); //Llb_MnxCheckNextStateVars( pMnn ); if ( !pPars->fSkipReach ) RetValue = Llb_Nonlin4Reachability( pMnn ); pMnn->timeTotal = Abc_Clock() - clk; Llb_MnxStop( pMnn ); } return RetValue; } /**Function************************************************************* Synopsis [Takes an AIG and returns an AIG representing reachable states.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ Aig_Man_t * Llb_ReachableStates( Aig_Man_t * pAig ) { extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters ); Vec_Int_t * vPermute; Vec_Ptr_t * vNames; Gia_ParLlb_t Pars, * pPars = &Pars; DdManager * dd; DdNode * bReached; Llb_Mnx_t * pMnn; Abc_Ntk_t * pNtk, * pNtkMuxes; Aig_Obj_t * pObj; int i, RetValue; abctime clk = Abc_Clock(); // create parameters Llb_ManSetDefaultParams( pPars ); pPars->fSkipOutCheck = 1; pPars->fCluster = 0; pPars->fReorder = 0; pPars->fSilent = 1; pPars->nBddMax = 100; pPars->nClusterMax = 500; // run reachability pMnn = Llb_MnxStart( pAig, pPars ); RetValue = Llb_Nonlin4Reachability( pMnn ); assert( RetValue == 1 ); // print BDD // Extra_bddPrint( pMnn->dd, pMnn->bReached ); // Extra_bddPrintSupport( pMnn->dd, pMnn->bReached ); // printf( "\n" ); // collect flop output variables vPermute = Vec_IntStartFull( Cudd_ReadSize(pMnn->dd) ); Saig_ManForEachLo( pAig, pObj, i ) Vec_IntWriteEntry( vPermute, Llb_ObjBddVar(pMnn->vOrder, pObj), i ); // transfer the reached state BDD into the new manager dd = Cudd_Init( Saig_ManRegNum(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); bReached = Extra_TransferPermute( pMnn->dd, dd, pMnn->bReached, Vec_IntArray(vPermute) ); Cudd_Ref( bReached ); Vec_IntFree( vPermute ); assert( Cudd_ReadSize(dd) == Saig_ManRegNum(pAig) ); // quit reachability engine pMnn->timeTotal = Abc_Clock() - clk; Llb_MnxStop( pMnn ); // derive the network vNames = Abc_NodeGetFakeNames( Saig_ManRegNum(pAig) ); pNtk = Abc_NtkDeriveFromBdd( dd, bReached, "reached", vNames ); Abc_NodeFreeNames( vNames ); Cudd_RecursiveDeref( dd, bReached ); Cudd_Quit( dd ); // convert pNtkMuxes = Abc_NtkBddToMuxes( pNtk ); Abc_NtkDelete( pNtk ); pNtk = Abc_NtkStrash( pNtkMuxes, 0, 1, 0 ); Abc_NtkDelete( pNtkMuxes ); pAig = Abc_NtkToDar( pNtk, 0, 0 ); Abc_NtkDelete( pNtk ); return pAig; } Gia_Man_t * Llb_ReachableStatesGia( Gia_Man_t * p ) { Gia_Man_t * pNew; Aig_Man_t * pAig, * pReached; pAig = Gia_ManToAigSimple( p ); pReached = Llb_ReachableStates( pAig ); Aig_ManStop( pAig ); pNew = Gia_ManFromAigSimple( pReached ); Aig_ManStop( pReached ); return pNew; } //////////////////////////////////////////////////////////////////////// /// END OF FILE /// //////////////////////////////////////////////////////////////////////// ABC_NAMESPACE_IMPL_END