| /**CFile**************************************************************** |
| |
| FileName [llb3Image.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [BDD based reachability.] |
| |
| Synopsis [Computes image using partitioned structure.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: llb3Image.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "llbInt.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| typedef struct Llb_Var_t_ Llb_Var_t; |
| struct Llb_Var_t_ |
| { |
| int iVar; // variable number |
| int nScore; // variable score |
| Vec_Int_t * vParts; // partitions |
| }; |
| |
| typedef struct Llb_Prt_t_ Llb_Prt_t; |
| struct Llb_Prt_t_ |
| { |
| int iPart; // partition number |
| int nSize; // the number of BDD nodes |
| DdNode * bFunc; // the partition |
| Vec_Int_t * vVars; // support |
| }; |
| |
| typedef struct Llb_Mgr_t_ Llb_Mgr_t; |
| struct Llb_Mgr_t_ |
| { |
| Aig_Man_t * pAig; // AIG manager |
| Vec_Ptr_t * vLeaves; // leaves in the AIG manager |
| Vec_Ptr_t * vRoots; // roots in the AIG manager |
| DdManager * dd; // working BDD manager |
| int * pVars2Q; // variables to quantify |
| // internal |
| Llb_Prt_t ** pParts; // partitions |
| Llb_Var_t ** pVars; // variables |
| int iPartFree; // next free partition |
| int nVars; // the number of BDD variables |
| int nSuppMax; // maximum support size |
| // temporary |
| int * pSupp; // temporary support storage |
| }; |
| |
| static inline Llb_Var_t * Llb_MgrVar( Llb_Mgr_t * p, int i ) { return p->pVars[i]; } |
| static inline Llb_Prt_t * Llb_MgrPart( Llb_Mgr_t * p, int i ) { return p->pParts[i]; } |
| |
| // iterator over vars |
| #define Llb_MgrForEachVar( p, pVar, i ) \ |
| for ( i = 0; (i < p->nVars) && (((pVar) = Llb_MgrVar(p, i)), 1); i++ ) if ( pVar == NULL ) {} else |
| // iterator over parts |
| #define Llb_MgrForEachPart( p, pPart, i ) \ |
| for ( i = 0; (i < p->iPartFree) && (((pPart) = Llb_MgrPart(p, i)), 1); i++ ) if ( pPart == NULL ) {} else |
| |
| // iterator over vars of one partition |
| #define Llb_PartForEachVar( p, pPart, pVar, i ) \ |
| for ( i = 0; (i < Vec_IntSize(pPart->vVars)) && (((pVar) = Llb_MgrVar(p, Vec_IntEntry(pPart->vVars,i))), 1); i++ ) |
| // iterator over parts of one variable |
| #define Llb_VarForEachPart( p, pVar, pPart, i ) \ |
| for ( i = 0; (i < Vec_IntSize(pVar->vParts)) && (((pPart) = Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,i))), 1); i++ ) |
| |
| // statistics |
| abctime timeBuild, timeAndEx, timeOther; |
| int nSuppMax; |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes one variable.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinRemoveVar( Llb_Mgr_t * p, Llb_Var_t * pVar ) |
| { |
| assert( p->pVars[pVar->iVar] == pVar ); |
| p->pVars[pVar->iVar] = NULL; |
| Vec_IntFree( pVar->vParts ); |
| ABC_FREE( pVar ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Removes one partition.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinRemovePart( Llb_Mgr_t * p, Llb_Prt_t * pPart ) |
| { |
| assert( p->pParts[pPart->iPart] == pPart ); |
| p->pParts[pPart->iPart] = NULL; |
| Vec_IntFree( pPart->vVars ); |
| Cudd_RecursiveDeref( p->dd, pPart->bFunc ); |
| ABC_FREE( pPart ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Create cube with singleton variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Llb_NonlinCreateCube1( Llb_Mgr_t * p, Llb_Prt_t * pPart ) |
| { |
| DdNode * bCube, * bTemp; |
| Llb_Var_t * pVar; |
| int i; |
| abctime TimeStop; |
| TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; |
| bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); |
| Llb_PartForEachVar( p, pPart, pVar, i ) |
| { |
| assert( Vec_IntSize(pVar->vParts) > 0 ); |
| if ( Vec_IntSize(pVar->vParts) != 1 ) |
| continue; |
| assert( Vec_IntEntry(pVar->vParts, 0) == pPart->iPart ); |
| bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| } |
| Cudd_Deref( bCube ); |
| p->dd->TimeStop = TimeStop; |
| return bCube; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Create cube of variables appearing only in two partitions.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Llb_NonlinCreateCube2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) |
| { |
| DdNode * bCube, * bTemp; |
| Llb_Var_t * pVar; |
| int i; |
| abctime TimeStop; |
| TimeStop = p->dd->TimeStop; p->dd->TimeStop = 0; |
| bCube = Cudd_ReadOne(p->dd); Cudd_Ref( bCube ); |
| Llb_PartForEachVar( p, pPart1, pVar, i ) |
| { |
| assert( Vec_IntSize(pVar->vParts) > 0 ); |
| if ( Vec_IntSize(pVar->vParts) != 2 ) |
| continue; |
| if ( (Vec_IntEntry(pVar->vParts, 0) == pPart1->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart2->iPart) || |
| (Vec_IntEntry(pVar->vParts, 0) == pPart2->iPart && Vec_IntEntry(pVar->vParts, 1) == pPart1->iPart) ) |
| { |
| bCube = Cudd_bddAnd( p->dd, bTemp = bCube, Cudd_bddIthVar(p->dd, pVar->iVar) ); Cudd_Ref( bCube ); |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| } |
| } |
| Cudd_Deref( bCube ); |
| p->dd->TimeStop = TimeStop; |
| return bCube; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if partition has singleton variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Llb_NonlinHasSingletonVars( Llb_Mgr_t * p, Llb_Prt_t * pPart ) |
| { |
| Llb_Var_t * pVar; |
| int i; |
| Llb_PartForEachVar( p, pPart, pVar, i ) |
| if ( Vec_IntSize(pVar->vParts) == 1 ) |
| return 1; |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns 1 if partition has singleton variables.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinPrint( Llb_Mgr_t * p ) |
| { |
| Llb_Prt_t * pPart; |
| Llb_Var_t * pVar; |
| int i, k; |
| printf( "\n" ); |
| Llb_MgrForEachVar( p, pVar, i ) |
| { |
| printf( "Var %3d : ", i ); |
| Llb_VarForEachPart( p, pVar, pPart, k ) |
| printf( "%d ", pPart->iPart ); |
| printf( "\n" ); |
| } |
| Llb_MgrForEachPart( p, pPart, i ) |
| { |
| printf( "Part %3d : ", i ); |
| Llb_PartForEachVar( p, pPart, pVar, k ) |
| printf( "%d ", pVar->iVar ); |
| printf( "\n" ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Quantifies singles belonging to one partition.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Llb_NonlinQuantify1( Llb_Mgr_t * p, Llb_Prt_t * pPart, int fSubset ) |
| { |
| Llb_Var_t * pVar; |
| Llb_Prt_t * pTemp; |
| Vec_Ptr_t * vSingles; |
| DdNode * bCube, * bTemp; |
| int i, RetValue, nSizeNew; |
| if ( fSubset ) |
| { |
| int Length; |
| // int nSuppSize = Cudd_SupportSize( p->dd, pPart->bFunc ); |
| // pPart->bFunc = Cudd_SubsetHeavyBranch( p->dd, bTemp = pPart->bFunc, nSuppSize, 3*pPart->nSize/4 ); Cudd_Ref( pPart->bFunc ); |
| pPart->bFunc = Cudd_LargestCube( p->dd, bTemp = pPart->bFunc, &Length ); Cudd_Ref( pPart->bFunc ); |
| |
| printf( "Subsetting %3d : ", pPart->iPart ); |
| printf( "(Supp =%3d Node =%5d) -> ", Cudd_SupportSize(p->dd, bTemp), Cudd_DagSize(bTemp) ); |
| printf( "(Supp =%3d Node =%5d)\n", Cudd_SupportSize(p->dd, pPart->bFunc), Cudd_DagSize(pPart->bFunc) ); |
| |
| RetValue = (Cudd_DagSize(bTemp) == Cudd_DagSize(pPart->bFunc)); |
| |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| |
| if ( RetValue ) |
| return 1; |
| } |
| else |
| { |
| // create cube to be quantified |
| bCube = Llb_NonlinCreateCube1( p, pPart ); Cudd_Ref( bCube ); |
| // assert( !Cudd_IsConstant(bCube) ); |
| // derive new function |
| pPart->bFunc = Cudd_bddExistAbstract( p->dd, bTemp = pPart->bFunc, bCube ); Cudd_Ref( pPart->bFunc ); |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| Cudd_RecursiveDeref( p->dd, bCube ); |
| } |
| // get support |
| vSingles = Vec_PtrAlloc( 0 ); |
| nSizeNew = Cudd_DagSize(pPart->bFunc); |
| Extra_SupportArray( p->dd, pPart->bFunc, p->pSupp ); |
| Llb_PartForEachVar( p, pPart, pVar, i ) |
| if ( p->pSupp[pVar->iVar] ) |
| { |
| assert( Vec_IntSize(pVar->vParts) > 1 ); |
| pVar->nScore -= pPart->nSize - nSizeNew; |
| } |
| else |
| { |
| RetValue = Vec_IntRemove( pVar->vParts, pPart->iPart ); |
| assert( RetValue ); |
| pVar->nScore -= pPart->nSize; |
| if ( Vec_IntSize(pVar->vParts) == 0 ) |
| Llb_NonlinRemoveVar( p, pVar ); |
| else if ( Vec_IntSize(pVar->vParts) == 1 ) |
| Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); |
| } |
| |
| // update partition |
| pPart->nSize = nSizeNew; |
| Vec_IntClear( pPart->vVars ); |
| for ( i = 0; i < p->nVars; i++ ) |
| if ( p->pSupp[i] && p->pVars2Q[i] ) |
| Vec_IntPush( pPart->vVars, i ); |
| // remove other variables |
| Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) |
| Llb_NonlinQuantify1( p, pTemp, 0 ); |
| Vec_PtrFree( vSingles ); |
| return 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Quantifies singles belonging to one partition.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Llb_NonlinQuantify2( Llb_Mgr_t * p, Llb_Prt_t * pPart1, Llb_Prt_t * pPart2 ) |
| { |
| int fVerbose = 0; |
| Llb_Var_t * pVar; |
| Llb_Prt_t * pTemp; |
| Vec_Ptr_t * vSingles; |
| DdNode * bCube, * bFunc; |
| int i, RetValue, nSuppSize; |
| // int iPart1 = pPart1->iPart; |
| // int iPart2 = pPart2->iPart; |
| |
| // create cube to be quantified |
| bCube = Llb_NonlinCreateCube2( p, pPart1, pPart2 ); Cudd_Ref( bCube ); |
| if ( fVerbose ) |
| { |
| printf( "\n" ); |
| printf( "\n" ); |
| Llb_NonlinPrint( p ); |
| printf( "Conjoining partitions %d and %d.\n", pPart1->iPart, pPart2->iPart ); |
| Extra_bddPrintSupport( p->dd, bCube ); printf( "\n" ); |
| } |
| |
| // derive new function |
| // bFunc = Cudd_bddAndAbstract( p->dd, pPart1->bFunc, pPart2->bFunc, bCube ); Cudd_Ref( bFunc ); |
| /* |
| bFunc = Cudd_bddAndAbstractLimit( p->dd, pPart1->bFunc, pPart2->bFunc, bCube, Limit ); |
| if ( bFunc == NULL ) |
| { |
| int RetValue; |
| Cudd_RecursiveDeref( p->dd, bCube ); |
| if ( pPart1->nSize < pPart2->nSize ) |
| RetValue = Llb_NonlinQuantify1( p, pPart1, 1 ); |
| else |
| RetValue = Llb_NonlinQuantify1( p, pPart2, 1 ); |
| if ( RetValue ) |
| Limit = Limit + 1000; |
| Llb_NonlinQuantify2( p, pPart1, pPart2 ); |
| return 0; |
| } |
| Cudd_Ref( bFunc ); |
| */ |
| |
| // bFunc = Extra_bddAndAbstractTime( p->dd, pPart1->bFunc, pPart2->bFunc, bCube, TimeOut ); |
| bFunc = Cudd_bddAndAbstract( p->dd, pPart1->bFunc, pPart2->bFunc, bCube ); |
| if ( bFunc == NULL ) |
| { |
| Cudd_RecursiveDeref( p->dd, bCube ); |
| return 0; |
| } |
| Cudd_Ref( bFunc ); |
| Cudd_RecursiveDeref( p->dd, bCube ); |
| |
| // create new partition |
| pTemp = p->pParts[p->iPartFree] = ABC_CALLOC( Llb_Prt_t, 1 ); |
| pTemp->iPart = p->iPartFree++; |
| pTemp->nSize = Cudd_DagSize(bFunc); |
| pTemp->bFunc = bFunc; |
| pTemp->vVars = Vec_IntAlloc( 8 ); |
| // update variables |
| Llb_PartForEachVar( p, pPart1, pVar, i ) |
| { |
| RetValue = Vec_IntRemove( pVar->vParts, pPart1->iPart ); |
| assert( RetValue ); |
| pVar->nScore -= pPart1->nSize; |
| } |
| // update variables |
| Llb_PartForEachVar( p, pPart2, pVar, i ) |
| { |
| RetValue = Vec_IntRemove( pVar->vParts, pPart2->iPart ); |
| assert( RetValue ); |
| pVar->nScore -= pPart2->nSize; |
| } |
| // add variables to the new partition |
| nSuppSize = 0; |
| Extra_SupportArray( p->dd, bFunc, p->pSupp ); |
| for ( i = 0; i < p->nVars; i++ ) |
| { |
| nSuppSize += p->pSupp[i]; |
| if ( p->pSupp[i] && p->pVars2Q[i] ) |
| { |
| pVar = Llb_MgrVar( p, i ); |
| pVar->nScore += pTemp->nSize; |
| Vec_IntPush( pVar->vParts, pTemp->iPart ); |
| Vec_IntPush( pTemp->vVars, i ); |
| } |
| } |
| p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); |
| // remove variables and collect partitions with singleton variables |
| vSingles = Vec_PtrAlloc( 0 ); |
| Llb_PartForEachVar( p, pPart1, pVar, i ) |
| { |
| if ( Vec_IntSize(pVar->vParts) == 0 ) |
| Llb_NonlinRemoveVar( p, pVar ); |
| else if ( Vec_IntSize(pVar->vParts) == 1 ) |
| { |
| if ( fVerbose ) |
| printf( "Adding partition %d because of var %d.\n", |
| Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); |
| Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); |
| } |
| } |
| Llb_PartForEachVar( p, pPart2, pVar, i ) |
| { |
| if ( pVar == NULL ) |
| continue; |
| if ( Vec_IntSize(pVar->vParts) == 0 ) |
| Llb_NonlinRemoveVar( p, pVar ); |
| else if ( Vec_IntSize(pVar->vParts) == 1 ) |
| { |
| if ( fVerbose ) |
| printf( "Adding partition %d because of var %d.\n", |
| Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0))->iPart, pVar->iVar ); |
| Vec_PtrPushUnique( vSingles, Llb_MgrPart(p, Vec_IntEntry(pVar->vParts,0)) ); |
| } |
| } |
| // remove partitions |
| Llb_NonlinRemovePart( p, pPart1 ); |
| Llb_NonlinRemovePart( p, pPart2 ); |
| // remove other variables |
| if ( fVerbose ) |
| Llb_NonlinPrint( p ); |
| Vec_PtrForEachEntry( Llb_Prt_t *, vSingles, pTemp, i ) |
| { |
| if ( fVerbose ) |
| printf( "Updating partitiong %d with singlton vars.\n", pTemp->iPart ); |
| Llb_NonlinQuantify1( p, pTemp, 0 ); |
| } |
| if ( fVerbose ) |
| Llb_NonlinPrint( p ); |
| Vec_PtrFree( vSingles ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes volume of the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinCutNodes_rec( Aig_Man_t * p, Aig_Obj_t * pObj, Vec_Ptr_t * vNodes ) |
| { |
| if ( Aig_ObjIsTravIdCurrent(p, pObj) ) |
| return; |
| Aig_ObjSetTravIdCurrent(p, pObj); |
| if ( Saig_ObjIsLi(p, pObj) ) |
| { |
| Llb_NonlinCutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); |
| return; |
| } |
| if ( Aig_ObjIsConst1(pObj) ) |
| return; |
| assert( Aig_ObjIsNode(pObj) ); |
| Llb_NonlinCutNodes_rec(p, Aig_ObjFanin0(pObj), vNodes); |
| Llb_NonlinCutNodes_rec(p, Aig_ObjFanin1(pObj), vNodes); |
| Vec_PtrPush( vNodes, pObj ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Computes volume of the cut.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Llb_NonlinCutNodes( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper ) |
| { |
| Vec_Ptr_t * vNodes; |
| Aig_Obj_t * pObj; |
| int i; |
| // mark the lower cut with the traversal ID |
| Aig_ManIncrementTravId(p); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) |
| Aig_ObjSetTravIdCurrent( p, pObj ); |
| // count the upper cut |
| vNodes = Vec_PtrAlloc( 100 ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) |
| Llb_NonlinCutNodes_rec( p, pObj, vNodes ); |
| return vNodes; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns array of BDDs for the roots in terms of the leaves.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Ptr_t * Llb_NonlinBuildBdds( Aig_Man_t * p, Vec_Ptr_t * vLower, Vec_Ptr_t * vUpper, DdManager * dd ) |
| { |
| Vec_Ptr_t * vNodes, * vResult; |
| Aig_Obj_t * pObj; |
| DdNode * bBdd0, * bBdd1, * bProd; |
| int i, k; |
| |
| Aig_ManConst1(p)->pData = Cudd_ReadOne( dd ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vLower, pObj, i ) |
| pObj->pData = Cudd_bddIthVar( dd, Aig_ObjId(pObj) ); |
| |
| vNodes = Llb_NonlinCutNodes( p, vLower, vUpper ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) |
| { |
| bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); |
| bBdd1 = Cudd_NotCond( (DdNode *)Aig_ObjFanin1(pObj)->pData, Aig_ObjFaninC1(pObj) ); |
| // pObj->pData = Extra_bddAndTime( dd, bBdd0, bBdd1, TimeOut ); |
| pObj->pData = Cudd_bddAnd( dd, bBdd0, bBdd1 ); |
| if ( pObj->pData == NULL ) |
| { |
| Vec_PtrForEachEntryStop( Aig_Obj_t *, vNodes, pObj, k, i ) |
| if ( pObj->pData ) |
| Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); |
| Vec_PtrFree( vNodes ); |
| return NULL; |
| } |
| Cudd_Ref( (DdNode *)pObj->pData ); |
| } |
| |
| vResult = Vec_PtrAlloc( 100 ); |
| Vec_PtrForEachEntry( Aig_Obj_t *, vUpper, pObj, i ) |
| { |
| if ( Aig_ObjIsNode(pObj) ) |
| { |
| bProd = Cudd_bddXnor( dd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)), (DdNode *)pObj->pData ); Cudd_Ref( bProd ); |
| } |
| else |
| { |
| assert( Saig_ObjIsLi(p, pObj) ); |
| bBdd0 = Cudd_NotCond( (DdNode *)Aig_ObjFanin0(pObj)->pData, Aig_ObjFaninC0(pObj) ); |
| bProd = Cudd_bddXnor( dd, Cudd_bddIthVar(dd, Aig_ObjId(pObj)), bBdd0 ); Cudd_Ref( bProd ); |
| } |
| Vec_PtrPush( vResult, bProd ); |
| } |
| Vec_PtrForEachEntry( Aig_Obj_t *, vNodes, pObj, i ) |
| Cudd_RecursiveDeref( dd, (DdNode *)pObj->pData ); |
| |
| Vec_PtrFree( vNodes ); |
| return vResult; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts non-linear quantification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinAddPair( Llb_Mgr_t * p, DdNode * bFunc, int iPart, int iVar ) |
| { |
| if ( p->pVars[iVar] == NULL ) |
| { |
| p->pVars[iVar] = ABC_CALLOC( Llb_Var_t, 1 ); |
| p->pVars[iVar]->iVar = iVar; |
| p->pVars[iVar]->nScore = 0; |
| p->pVars[iVar]->vParts = Vec_IntAlloc( 8 ); |
| } |
| Vec_IntPush( p->pVars[iVar]->vParts, iPart ); |
| Vec_IntPush( p->pParts[iPart]->vVars, iVar ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts non-linear quantification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinAddPartition( Llb_Mgr_t * p, int i, DdNode * bFunc ) |
| { |
| int k, nSuppSize; |
| assert( !Cudd_IsConstant(bFunc) ); |
| // create partition |
| p->pParts[i] = ABC_CALLOC( Llb_Prt_t, 1 ); |
| p->pParts[i]->iPart = i; |
| p->pParts[i]->bFunc = bFunc; |
| p->pParts[i]->vVars = Vec_IntAlloc( 8 ); |
| // add support dependencies |
| nSuppSize = 0; |
| Extra_SupportArray( p->dd, bFunc, p->pSupp ); |
| for ( k = 0; k < p->nVars; k++ ) |
| { |
| nSuppSize += p->pSupp[k]; |
| if ( p->pSupp[k] && p->pVars2Q[k] ) |
| Llb_NonlinAddPair( p, bFunc, i, k ); |
| } |
| p->nSuppMax = Abc_MaxInt( p->nSuppMax, nSuppSize ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts non-linear quantification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Llb_NonlinStart( Llb_Mgr_t * p ) |
| { |
| Vec_Ptr_t * vRootBdds; |
| DdNode * bFunc; |
| int i; |
| // create and collect BDDs |
| vRootBdds = Llb_NonlinBuildBdds( p->pAig, p->vLeaves, p->vRoots, p->dd ); // come referenced |
| if ( vRootBdds == NULL ) |
| return 0; |
| // add pairs (refs are consumed inside) |
| Vec_PtrForEachEntry( DdNode *, vRootBdds, bFunc, i ) |
| Llb_NonlinAddPartition( p, i, bFunc ); |
| Vec_PtrFree( vRootBdds ); |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Checks that each var appears in at least one partition.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| **********************************************************************/ |
| void Llb_NonlinCheckVars( Llb_Mgr_t * p ) |
| { |
| Llb_Var_t * pVar; |
| int i; |
| Llb_MgrForEachVar( p, pVar, i ) |
| assert( Vec_IntSize(pVar->vParts) > 1 ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Find next partition to quantify] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Llb_NonlinNextPartitions( Llb_Mgr_t * p, Llb_Prt_t ** ppPart1, Llb_Prt_t ** ppPart2 ) |
| { |
| Llb_Var_t * pVar, * pVarBest = NULL; |
| Llb_Prt_t * pPart, * pPart1Best = NULL, * pPart2Best = NULL; |
| int i; |
| Llb_NonlinCheckVars( p ); |
| // find variable with minimum score |
| Llb_MgrForEachVar( p, pVar, i ) |
| if ( pVarBest == NULL || pVarBest->nScore > pVar->nScore ) |
| pVarBest = pVar; |
| if ( pVarBest == NULL ) |
| return 0; |
| // find two partitions with minimum size |
| Llb_VarForEachPart( p, pVarBest, pPart, i ) |
| { |
| if ( pPart1Best == NULL ) |
| pPart1Best = pPart; |
| else if ( pPart2Best == NULL ) |
| pPart2Best = pPart; |
| else if ( pPart1Best->nSize > pPart->nSize || pPart2Best->nSize > pPart->nSize ) |
| { |
| if ( pPart1Best->nSize > pPart2Best->nSize ) |
| pPart1Best = pPart; |
| else |
| pPart2Best = pPart; |
| } |
| } |
| *ppPart1 = pPart1Best; |
| *ppPart2 = pPart2Best; |
| return 1; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reorders BDDs in the working manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinReorder( 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 [Recomputes scores after variable reordering.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinRecomputeScores( Llb_Mgr_t * p ) |
| { |
| Llb_Prt_t * pPart; |
| Llb_Var_t * pVar; |
| int i, k; |
| Llb_MgrForEachPart( p, pPart, i ) |
| pPart->nSize = Cudd_DagSize(pPart->bFunc); |
| Llb_MgrForEachVar( p, pVar, i ) |
| { |
| pVar->nScore = 0; |
| Llb_VarForEachPart( p, pVar, pPart, k ) |
| pVar->nScore += pPart->nSize; |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Recomputes scores after variable reordering.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinVerifyScores( Llb_Mgr_t * p ) |
| { |
| Llb_Prt_t * pPart; |
| Llb_Var_t * pVar; |
| int i, k, nScore; |
| Llb_MgrForEachPart( p, pPart, i ) |
| assert( pPart->nSize == Cudd_DagSize(pPart->bFunc) ); |
| Llb_MgrForEachVar( p, pVar, i ) |
| { |
| nScore = 0; |
| Llb_VarForEachPart( p, pVar, pPart, k ) |
| nScore += pPart->nSize; |
| assert( nScore == pVar->nScore ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts non-linear quantification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Llb_Mgr_t * Llb_NonlinAlloc( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, DdManager * dd ) |
| { |
| Llb_Mgr_t * p; |
| p = ABC_CALLOC( Llb_Mgr_t, 1 ); |
| p->pAig = pAig; |
| p->vLeaves = vLeaves; |
| p->vRoots = vRoots; |
| p->dd = dd; |
| p->pVars2Q = pVars2Q; |
| p->nVars = Cudd_ReadSize(dd); |
| p->iPartFree = Vec_PtrSize(vRoots); |
| p->pVars = ABC_CALLOC( Llb_Var_t *, p->nVars ); |
| p->pParts = ABC_CALLOC( Llb_Prt_t *, 2 * p->iPartFree + 2 ); |
| p->pSupp = ABC_ALLOC( int, Cudd_ReadSize(dd) ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Stops non-linear quantification scheduling.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinFree( Llb_Mgr_t * p ) |
| { |
| Llb_Prt_t * pPart; |
| Llb_Var_t * pVar; |
| int i; |
| Llb_MgrForEachVar( p, pVar, i ) |
| Llb_NonlinRemoveVar( p, pVar ); |
| Llb_MgrForEachPart( p, pPart, i ) |
| Llb_NonlinRemovePart( p, pPart ); |
| ABC_FREE( p->pVars ); |
| ABC_FREE( p->pParts ); |
| ABC_FREE( p->pSupp ); |
| ABC_FREE( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs image computation.] |
| |
| Description [Computes image of BDDs (vFuncs).] |
| |
| SideEffects [BDDs in vFuncs are derefed inside. The result is refed.] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Llb_NonlinImage( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, |
| DdManager * dd, DdNode * bCurrent, int fReorder, int fVerbose, int * pOrder ) |
| { |
| Llb_Prt_t * pPart, * pPart1, * pPart2; |
| Llb_Mgr_t * p; |
| DdNode * bFunc, * bTemp; |
| int i, nReorders, timeInside; |
| abctime clk = Abc_Clock(), clk2; |
| // start the manager |
| clk2 = Abc_Clock(); |
| p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd ); |
| if ( !Llb_NonlinStart( p ) ) |
| { |
| Llb_NonlinFree( p ); |
| return NULL; |
| } |
| // add partition |
| Llb_NonlinAddPartition( p, p->iPartFree++, bCurrent ); |
| // remove singles |
| Llb_MgrForEachPart( p, pPart, i ) |
| if ( Llb_NonlinHasSingletonVars(p, pPart) ) |
| Llb_NonlinQuantify1( p, pPart, 0 ); |
| timeBuild += Abc_Clock() - clk2; |
| timeInside = Abc_Clock() - clk2; |
| // compute scores |
| Llb_NonlinRecomputeScores( p ); |
| // save permutation |
| if ( pOrder ) |
| memcpy( pOrder, dd->invperm, sizeof(int) * dd->size ); |
| // iteratively quantify variables |
| while ( Llb_NonlinNextPartitions(p, &pPart1, &pPart2) ) |
| { |
| clk2 = Abc_Clock(); |
| nReorders = Cudd_ReadReorderings(dd); |
| if ( !Llb_NonlinQuantify2( p, pPart1, pPart2 ) ) |
| { |
| Llb_NonlinFree( p ); |
| return NULL; |
| } |
| timeAndEx += Abc_Clock() - clk2; |
| timeInside += Abc_Clock() - clk2; |
| if ( nReorders < Cudd_ReadReorderings(dd) ) |
| Llb_NonlinRecomputeScores( p ); |
| // else |
| // Llb_NonlinVerifyScores( p ); |
| } |
| // load partitions |
| bFunc = Cudd_ReadOne(p->dd); Cudd_Ref( bFunc ); |
| Llb_MgrForEachPart( p, pPart, i ) |
| { |
| bFunc = Cudd_bddAnd( p->dd, bTemp = bFunc, pPart->bFunc ); Cudd_Ref( bFunc ); |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| } |
| nSuppMax = p->nSuppMax; |
| Llb_NonlinFree( p ); |
| // reorder variables |
| if ( fReorder ) |
| Llb_NonlinReorder( dd, 0, fVerbose ); |
| timeOther += Abc_Clock() - clk - timeInside; |
| // return |
| Cudd_Deref( bFunc ); |
| return bFunc; |
| } |
| |
| |
| |
| static Llb_Mgr_t * p = NULL; |
| |
| /**Function************************************************************* |
| |
| Synopsis [Starts image computation manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdManager * Llb_NonlinImageStart( Aig_Man_t * pAig, Vec_Ptr_t * vLeaves, Vec_Ptr_t * vRoots, int * pVars2Q, int * pOrder, int fFirst, abctime TimeTarget ) |
| { |
| DdManager * dd; |
| abctime clk = Abc_Clock(); |
| assert( p == NULL ); |
| // start a new manager (disable reordering) |
| dd = Cudd_Init( Aig_ManObjNumMax(pAig), 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0 ); |
| dd->TimeStop = TimeTarget; |
| Cudd_ShuffleHeap( dd, pOrder ); |
| // if ( fFirst ) |
| Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); |
| // start the manager |
| p = Llb_NonlinAlloc( pAig, vLeaves, vRoots, pVars2Q, dd ); |
| if ( !Llb_NonlinStart( p ) ) |
| { |
| Llb_NonlinFree( p ); |
| p = NULL; |
| return NULL; |
| } |
| timeBuild += Abc_Clock() - clk; |
| // if ( !fFirst ) |
| // Cudd_AutodynEnable( dd, CUDD_REORDER_SYMM_SIFT ); |
| return dd; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs image computation.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| DdNode * Llb_NonlinImageCompute( DdNode * bCurrent, int fReorder, int fDrop, int fVerbose, int * pOrder ) |
| { |
| Llb_Prt_t * pPart, * pPart1, * pPart2; |
| DdNode * bFunc, * bTemp; |
| int i, nReorders, timeInside = 0; |
| abctime clk = Abc_Clock(), clk2; |
| |
| // add partition |
| Llb_NonlinAddPartition( p, p->iPartFree++, bCurrent ); |
| // remove singles |
| Llb_MgrForEachPart( p, pPart, i ) |
| if ( Llb_NonlinHasSingletonVars(p, pPart) ) |
| Llb_NonlinQuantify1( p, pPart, 0 ); |
| // reorder |
| if ( fReorder ) |
| Llb_NonlinReorder( p->dd, 0, 0 ); |
| // save permutation |
| memcpy( pOrder, p->dd->invperm, sizeof(int) * p->dd->size ); |
| |
| // compute scores |
| Llb_NonlinRecomputeScores( p ); |
| // iteratively quantify variables |
| while ( Llb_NonlinNextPartitions(p, &pPart1, &pPart2) ) |
| { |
| clk2 = Abc_Clock(); |
| nReorders = Cudd_ReadReorderings(p->dd); |
| if ( !Llb_NonlinQuantify2( p, pPart1, pPart2 ) ) |
| { |
| Llb_NonlinFree( p ); |
| return NULL; |
| } |
| timeAndEx += Abc_Clock() - clk2; |
| timeInside += Abc_Clock() - clk2; |
| if ( nReorders < Cudd_ReadReorderings(p->dd) ) |
| Llb_NonlinRecomputeScores( p ); |
| // else |
| // Llb_NonlinVerifyScores( p ); |
| } |
| // load partitions |
| bFunc = Cudd_ReadOne(p->dd); Cudd_Ref( bFunc ); |
| Llb_MgrForEachPart( p, pPart, i ) |
| { |
| bFunc = Cudd_bddAnd( p->dd, bTemp = bFunc, pPart->bFunc ); |
| if ( bFunc == NULL ) |
| { |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| Llb_NonlinFree( p ); |
| return NULL; |
| } |
| Cudd_Ref( bFunc ); |
| Cudd_RecursiveDeref( p->dd, bTemp ); |
| } |
| nSuppMax = p->nSuppMax; |
| // reorder variables |
| // if ( fReorder ) |
| // Llb_NonlinReorder( p->dd, 0, fVerbose ); |
| // save permutation |
| // memcpy( pOrder, p->dd->invperm, sizeof(int) * Cudd_ReadSize(p->dd) ); |
| |
| timeOther += Abc_Clock() - clk - timeInside; |
| // return |
| Cudd_Deref( bFunc ); |
| return bFunc; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Quits image computation manager.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Llb_NonlinImageQuit() |
| { |
| DdManager * dd; |
| if ( p == NULL ) |
| return; |
| dd = p->dd; |
| Llb_NonlinFree( p ); |
| if ( dd->bFunc ) |
| Cudd_RecursiveDeref( dd, dd->bFunc ); |
| Extra_StopManager( dd ); |
| // Cudd_Quit ( dd ); |
| p = NULL; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |