| /**CFile**************************************************************** |
| |
| FileName [nwkMerge.c] |
| |
| SystemName [ABC: Logic synthesis and verification system.] |
| |
| PackageName [Netlist representation.] |
| |
| Synopsis [LUT merging algorithm.] |
| |
| Author [Alan Mishchenko] |
| |
| Affiliation [UC Berkeley] |
| |
| Date [Ver. 1.0. Started - June 20, 2005.] |
| |
| Revision [$Id: nwkMerge.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $] |
| |
| ***********************************************************************/ |
| |
| #include "nwk.h" |
| #include "nwkMerge.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// DECLARATIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| /**Function************************************************************* |
| |
| Synopsis [Allocates the graph.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Nwk_Grf_t * Nwk_ManGraphAlloc( int nVertsMax ) |
| { |
| Nwk_Grf_t * p; |
| p = ABC_ALLOC( Nwk_Grf_t, 1 ); |
| memset( p, 0, sizeof(Nwk_Grf_t) ); |
| p->nVertsMax = nVertsMax; |
| p->nEdgeHash = Abc_PrimeCudd( 3 * nVertsMax ); |
| p->pEdgeHash = ABC_CALLOC( Nwk_Edg_t *, p->nEdgeHash ); |
| p->pMemEdges = Aig_MmFixedStart( sizeof(Nwk_Edg_t), p->nEdgeHash ); |
| p->vPairs = Vec_IntAlloc( 1000 ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Deallocates the graph.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphFree( Nwk_Grf_t * p ) |
| { |
| if ( p->vPairs ) Vec_IntFree( p->vPairs ); |
| if ( p->pMemEdges ) Aig_MmFixedStop( p->pMemEdges, 0 ); |
| if ( p->pMemVerts ) Aig_MmFlexStop( p->pMemVerts, 0 ); |
| ABC_FREE( p->pVerts ); |
| ABC_FREE( p->pEdgeHash ); |
| ABC_FREE( p->pMapLut2Id ); |
| ABC_FREE( p->pMapId2Lut ); |
| ABC_FREE( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepares the graph for solving the problem.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphReportMemoryUsage( Nwk_Grf_t * p ) |
| { |
| p->nMemBytes1 = |
| sizeof(Nwk_Grf_t) + |
| sizeof(void *) * p->nEdgeHash + |
| sizeof(int) * (p->nObjs + p->nVertsMax) + |
| sizeof(Nwk_Edg_t) * p->nEdges; |
| p->nMemBytes2 = |
| sizeof(Nwk_Vrt_t) * p->nVerts + |
| sizeof(int) * 2 * p->nEdges; |
| printf( "Memory usage stats: Preprocessing = %.2f MB. Solving = %.2f MB.\n", |
| 1.0 * p->nMemBytes1 / (1<<20), 1.0 * p->nMemBytes2 / (1<<20) ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Finds or adds the edge to the graph.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphHashEdge( Nwk_Grf_t * p, int iLut1, int iLut2 ) |
| { |
| Nwk_Edg_t * pEntry; |
| unsigned Key; |
| if ( iLut1 == iLut2 ) |
| return; |
| if ( iLut1 > iLut2 ) |
| { |
| Key = iLut1; |
| iLut1 = iLut2; |
| iLut2 = Key; |
| } |
| assert( iLut1 < iLut2 ); |
| if ( p->nObjs < iLut2 ) |
| p->nObjs = iLut2; |
| Key = (unsigned)(741457 * iLut1 + 4256249 * iLut2) % p->nEdgeHash; |
| for ( pEntry = p->pEdgeHash[Key]; pEntry; pEntry = pEntry->pNext ) |
| if ( pEntry->iNode1 == iLut1 && pEntry->iNode2 == iLut2 ) |
| return; |
| pEntry = (Nwk_Edg_t *)Aig_MmFixedEntryFetch( p->pMemEdges ); |
| pEntry->iNode1 = iLut1; |
| pEntry->iNode2 = iLut2; |
| pEntry->pNext = p->pEdgeHash[Key]; |
| p->pEdgeHash[Key] = pEntry; |
| p->nEdges++; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Adds one entry to the list.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Nwk_ManGraphListAdd( Nwk_Grf_t * p, int * pList, Nwk_Vrt_t * pVertex ) |
| { |
| if ( *pList ) |
| { |
| Nwk_Vrt_t * pHead; |
| pHead = p->pVerts[*pList]; |
| pVertex->iPrev = 0; |
| pVertex->iNext = pHead->Id; |
| pHead->iPrev = pVertex->Id; |
| } |
| *pList = pVertex->Id; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Deletes one entry from the list.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Nwk_ManGraphListDelete( Nwk_Grf_t * p, int * pList, Nwk_Vrt_t * pVertex ) |
| { |
| assert( *pList ); |
| if ( pVertex->iPrev ) |
| { |
| // assert( p->pVerts[pVertex->iPrev]->iNext == pVertex->Id ); |
| p->pVerts[pVertex->iPrev]->iNext = pVertex->iNext; |
| } |
| if ( pVertex->iNext ) |
| { |
| // assert( p->pVerts[pVertex->iNext]->iPrev == pVertex->Id ); |
| p->pVerts[pVertex->iNext]->iPrev = pVertex->iPrev; |
| } |
| if ( *pList == pVertex->Id ) |
| *pList = pVertex->iNext; |
| pVertex->iPrev = pVertex->iNext = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Inserts the edge into one of the linked lists.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Nwk_ManGraphListInsert( Nwk_Grf_t * p, Nwk_Vrt_t * pVertex ) |
| { |
| Nwk_Vrt_t * pNext; |
| assert( pVertex->nEdges > 0 ); |
| |
| if ( pVertex->nEdges == 1 ) |
| { |
| pNext = p->pVerts[ pVertex->pEdges[0] ]; |
| if ( pNext->nEdges >= NWK_MAX_LIST ) |
| Nwk_ManGraphListAdd( p, p->pLists1 + NWK_MAX_LIST, pVertex ); |
| else |
| Nwk_ManGraphListAdd( p, p->pLists1 + pNext->nEdges, pVertex ); |
| } |
| else |
| { |
| if ( pVertex->nEdges >= NWK_MAX_LIST ) |
| Nwk_ManGraphListAdd( p, p->pLists2 + NWK_MAX_LIST, pVertex ); |
| else |
| Nwk_ManGraphListAdd( p, p->pLists2 + pVertex->nEdges, pVertex ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Extracts the edge from one of the linked lists.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Nwk_ManGraphListExtract( Nwk_Grf_t * p, Nwk_Vrt_t * pVertex ) |
| { |
| Nwk_Vrt_t * pNext; |
| assert( pVertex->nEdges > 0 ); |
| |
| if ( pVertex->nEdges == 1 ) |
| { |
| pNext = p->pVerts[ pVertex->pEdges[0] ]; |
| if ( pNext->nEdges >= NWK_MAX_LIST ) |
| Nwk_ManGraphListDelete( p, p->pLists1 + NWK_MAX_LIST, pVertex ); |
| else |
| Nwk_ManGraphListDelete( p, p->pLists1 + pNext->nEdges, pVertex ); |
| } |
| else |
| { |
| if ( pVertex->nEdges >= NWK_MAX_LIST ) |
| Nwk_ManGraphListDelete( p, p->pLists2 + NWK_MAX_LIST, pVertex ); |
| else |
| Nwk_ManGraphListDelete( p, p->pLists2 + pVertex->nEdges, pVertex ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Prepares the graph for solving the problem.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphPrepare( Nwk_Grf_t * p ) |
| { |
| Nwk_Edg_t * pEntry; |
| Nwk_Vrt_t * pVertex; |
| int * pnEdges, nBytes, i; |
| // allocate memory for the present objects |
| p->pMapLut2Id = ABC_ALLOC( int, p->nObjs+1 ); |
| p->pMapId2Lut = ABC_ALLOC( int, p->nVertsMax+1 ); |
| memset( p->pMapLut2Id, 0xff, sizeof(int) * (p->nObjs+1) ); |
| memset( p->pMapId2Lut, 0xff, sizeof(int) * (p->nVertsMax+1) ); |
| // mark present objects |
| Nwk_GraphForEachEdge( p, pEntry, i ) |
| { |
| assert( pEntry->iNode1 <= p->nObjs ); |
| assert( pEntry->iNode2 <= p->nObjs ); |
| p->pMapLut2Id[ pEntry->iNode1 ] = 0; |
| p->pMapLut2Id[ pEntry->iNode2 ] = 0; |
| } |
| // map objects |
| p->nVerts = 0; |
| for ( i = 0; i <= p->nObjs; i++ ) |
| { |
| if ( p->pMapLut2Id[i] == 0 ) |
| { |
| p->pMapLut2Id[i] = ++p->nVerts; |
| p->pMapId2Lut[p->nVerts] = i; |
| } |
| } |
| // count the edges and mark present objects |
| pnEdges = ABC_CALLOC( int, p->nVerts+1 ); |
| Nwk_GraphForEachEdge( p, pEntry, i ) |
| { |
| // translate into vertices |
| assert( pEntry->iNode1 <= p->nObjs ); |
| assert( pEntry->iNode2 <= p->nObjs ); |
| pEntry->iNode1 = p->pMapLut2Id[pEntry->iNode1]; |
| pEntry->iNode2 = p->pMapLut2Id[pEntry->iNode2]; |
| // count the edges |
| assert( pEntry->iNode1 <= p->nVerts ); |
| assert( pEntry->iNode2 <= p->nVerts ); |
| pnEdges[pEntry->iNode1]++; |
| pnEdges[pEntry->iNode2]++; |
| } |
| // allocate the real graph |
| p->pMemVerts = Aig_MmFlexStart(); |
| p->pVerts = ABC_ALLOC( Nwk_Vrt_t *, p->nVerts + 1 ); |
| p->pVerts[0] = NULL; |
| for ( i = 1; i <= p->nVerts; i++ ) |
| { |
| assert( pnEdges[i] > 0 ); |
| nBytes = sizeof(Nwk_Vrt_t) + sizeof(int) * pnEdges[i]; |
| p->pVerts[i] = (Nwk_Vrt_t *)Aig_MmFlexEntryFetch( p->pMemVerts, nBytes ); |
| memset( p->pVerts[i], 0, nBytes ); |
| p->pVerts[i]->Id = i; |
| } |
| // add edges to the real graph |
| Nwk_GraphForEachEdge( p, pEntry, i ) |
| { |
| pVertex = p->pVerts[pEntry->iNode1]; |
| pVertex->pEdges[ pVertex->nEdges++ ] = pEntry->iNode2; |
| pVertex = p->pVerts[pEntry->iNode2]; |
| pVertex->pEdges[ pVertex->nEdges++ ] = pEntry->iNode1; |
| } |
| // put vertices into the data structure |
| for ( i = 1; i <= p->nVerts; i++ ) |
| { |
| assert( p->pVerts[i]->nEdges == pnEdges[i] ); |
| Nwk_ManGraphListInsert( p, p->pVerts[i] ); |
| } |
| // clean up |
| Aig_MmFixedStop( p->pMemEdges, 0 ); p->pMemEdges = NULL; |
| ABC_FREE( p->pEdgeHash ); |
| // p->nEdgeHash = 0; |
| ABC_FREE( pnEdges ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Sort pairs by the first vertex in the topological order.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphSortPairs( Nwk_Grf_t * p ) |
| { |
| int nSize = Vec_IntSize(p->vPairs); |
| int * pIdToPair, i; |
| // allocate storage |
| pIdToPair = ABC_ALLOC( int, p->nObjs+1 ); |
| for ( i = 0; i <= p->nObjs; i++ ) |
| pIdToPair[i] = -1; |
| // create mapping |
| for ( i = 0; i < p->vPairs->nSize; i += 2 ) |
| { |
| assert( pIdToPair[ p->vPairs->pArray[i] ] == -1 ); |
| pIdToPair[ p->vPairs->pArray[i] ] = p->vPairs->pArray[i+1]; |
| } |
| // recreate pairs |
| Vec_IntClear( p->vPairs ); |
| for ( i = 0; i <= p->nObjs; i++ ) |
| if ( pIdToPair[i] >= 0 ) |
| { |
| assert( i < pIdToPair[i] ); |
| Vec_IntPush( p->vPairs, i ); |
| Vec_IntPush( p->vPairs, pIdToPair[i] ); |
| } |
| assert( nSize == Vec_IntSize(p->vPairs) ); |
| ABC_FREE( pIdToPair ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Updates the problem after pulling out one edge.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphCheckLists( Nwk_Grf_t * p ) |
| { |
| Nwk_Vrt_t * pVertex, * pNext; |
| int i, j; |
| assert( p->pLists1[0] == 0 ); |
| for ( i = 1; i <= NWK_MAX_LIST; i++ ) |
| if ( p->pLists1[i] ) |
| { |
| pVertex = p->pVerts[ p->pLists1[i] ]; |
| assert( pVertex->nEdges == 1 ); |
| pNext = p->pVerts[ pVertex->pEdges[0] ]; |
| assert( pNext->nEdges == i || pNext->nEdges > NWK_MAX_LIST ); |
| } |
| // find the next vertext to extract |
| assert( p->pLists2[0] == 0 ); |
| assert( p->pLists2[1] == 0 ); |
| for ( j = 2; j <= NWK_MAX_LIST; j++ ) |
| if ( p->pLists2[j] ) |
| { |
| pVertex = p->pVerts[ p->pLists2[j] ]; |
| assert( pVertex->nEdges == j || pVertex->nEdges > NWK_MAX_LIST ); |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Extracts the edge from one of the linked lists.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| static inline void Nwk_ManGraphVertexRemoveEdge( Nwk_Vrt_t * pThis, Nwk_Vrt_t * pNext ) |
| { |
| int k; |
| for ( k = 0; k < pThis->nEdges; k++ ) |
| if ( pThis->pEdges[k] == pNext->Id ) |
| break; |
| assert( k < pThis->nEdges ); |
| pThis->nEdges--; |
| for ( ; k < pThis->nEdges; k++ ) |
| pThis->pEdges[k] = pThis->pEdges[k+1]; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Updates the problem after pulling out one edge.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphUpdate( Nwk_Grf_t * p, Nwk_Vrt_t * pVertex, Nwk_Vrt_t * pNext ) |
| { |
| Nwk_Vrt_t * pChanged, * pOther; |
| int i, k; |
| // Nwk_ManGraphCheckLists( p ); |
| Nwk_ManGraphListExtract( p, pVertex ); |
| Nwk_ManGraphListExtract( p, pNext ); |
| // update neihbors of pVertex |
| Nwk_VertexForEachAdjacent( p, pVertex, pChanged, i ) |
| { |
| if ( pChanged == pNext ) |
| continue; |
| Nwk_ManGraphListExtract( p, pChanged ); |
| // move those that use this one |
| if ( pChanged->nEdges > 1 ) |
| Nwk_VertexForEachAdjacent( p, pChanged, pOther, k ) |
| { |
| if ( pOther == pVertex || pOther->nEdges > 1 ) |
| continue; |
| assert( pOther->nEdges == 1 ); |
| Nwk_ManGraphListExtract( p, pOther ); |
| pChanged->nEdges--; |
| Nwk_ManGraphListInsert( p, pOther ); |
| pChanged->nEdges++; |
| } |
| // remove the edge |
| Nwk_ManGraphVertexRemoveEdge( pChanged, pVertex ); |
| // add the changed vertex back |
| if ( pChanged->nEdges > 0 ) |
| Nwk_ManGraphListInsert( p, pChanged ); |
| } |
| // update neihbors of pNext |
| Nwk_VertexForEachAdjacent( p, pNext, pChanged, i ) |
| { |
| if ( pChanged == pVertex ) |
| continue; |
| Nwk_ManGraphListExtract( p, pChanged ); |
| // move those that use this one |
| if ( pChanged->nEdges > 1 ) |
| Nwk_VertexForEachAdjacent( p, pChanged, pOther, k ) |
| { |
| if ( pOther == pNext || pOther->nEdges > 1 ) |
| continue; |
| assert( pOther->nEdges == 1 ); |
| Nwk_ManGraphListExtract( p, pOther ); |
| pChanged->nEdges--; |
| Nwk_ManGraphListInsert( p, pOther ); |
| pChanged->nEdges++; |
| } |
| // remove the edge |
| Nwk_ManGraphVertexRemoveEdge( pChanged, pNext ); |
| // add the changed vertex back |
| if ( pChanged->nEdges > 0 ) |
| Nwk_ManGraphListInsert( p, pChanged ); |
| } |
| // add to the result |
| if ( pVertex->Id < pNext->Id ) |
| { |
| Vec_IntPush( p->vPairs, p->pMapId2Lut[pVertex->Id] ); |
| Vec_IntPush( p->vPairs, p->pMapId2Lut[pNext->Id] ); |
| } |
| else |
| { |
| Vec_IntPush( p->vPairs, p->pMapId2Lut[pNext->Id] ); |
| Vec_IntPush( p->vPairs, p->pMapId2Lut[pVertex->Id] ); |
| } |
| // Nwk_ManGraphCheckLists( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Counts the number of entries in the list.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Nwk_ManGraphListLength( Nwk_Grf_t * p, int List ) |
| { |
| Nwk_Vrt_t * pThis; |
| int fVerbose = 0; |
| int Counter = 0; |
| Nwk_ListForEachVertex( p, List, pThis ) |
| { |
| if ( fVerbose && Counter < 20 ) |
| printf( "%d ", p->pVerts[pThis->pEdges[0]]->nEdges ); |
| Counter++; |
| } |
| if ( fVerbose ) |
| printf( "\n" ); |
| return Counter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Returns the adjacent vertex with the mininum number of edges.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Nwk_Vrt_t * Nwk_ManGraphListFindMinEdge( Nwk_Grf_t * p, Nwk_Vrt_t * pVert ) |
| { |
| Nwk_Vrt_t * pThis, * pMinCost = NULL; |
| int k; |
| Nwk_VertexForEachAdjacent( p, pVert, pThis, k ) |
| { |
| if ( pMinCost == NULL || pMinCost->nEdges > pThis->nEdges ) |
| pMinCost = pThis; |
| } |
| return pMinCost; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Finds the best vertext in the list.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Nwk_Vrt_t * Nwk_ManGraphListFindMin( Nwk_Grf_t * p, int List ) |
| { |
| Nwk_Vrt_t * pThis, * pMinCost = NULL; |
| int k, Counter = 10000, BestCost = 1000000; |
| Nwk_ListForEachVertex( p, List, pThis ) |
| { |
| for ( k = 0; k < pThis->nEdges; k++ ) |
| { |
| if ( pMinCost == NULL || BestCost > p->pVerts[pThis->pEdges[k]]->nEdges ) |
| { |
| BestCost = p->pVerts[pThis->pEdges[k]]->nEdges; |
| pMinCost = pThis; |
| } |
| } |
| if ( --Counter == 0 ) |
| break; |
| } |
| return pMinCost; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Solves the problem by extracting one edge at a time.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManGraphSolve( Nwk_Grf_t * p ) |
| { |
| Nwk_Vrt_t * pVertex, * pNext; |
| int i, j; |
| Nwk_ManGraphPrepare( p ); |
| while ( 1 ) |
| { |
| // find the next vertex to extract |
| assert( p->pLists1[0] == 0 ); |
| for ( i = 1; i <= NWK_MAX_LIST; i++ ) |
| if ( p->pLists1[i] ) |
| { |
| // printf( "%d ", i ); |
| // printf( "ListA = %2d. Length = %5d.\n", i, Nwk_ManGraphListLength(p,p->pLists1[i]) ); |
| pVertex = p->pVerts[ p->pLists1[i] ]; |
| assert( pVertex->nEdges == 1 ); |
| pNext = p->pVerts[ pVertex->pEdges[0] ]; |
| Nwk_ManGraphUpdate( p, pVertex, pNext ); |
| break; |
| } |
| if ( i < NWK_MAX_LIST + 1 ) |
| continue; |
| // find the next vertex to extract |
| assert( p->pLists2[0] == 0 ); |
| assert( p->pLists2[1] == 0 ); |
| for ( j = 2; j <= NWK_MAX_LIST; j++ ) |
| if ( p->pLists2[j] ) |
| { |
| // printf( "***%d ", j ); |
| // printf( "ListB = %2d. Length = %5d.\n", j, Nwk_ManGraphListLength(p,p->pLists2[j]) ); |
| pVertex = Nwk_ManGraphListFindMin( p, p->pLists2[j] ); |
| assert( pVertex->nEdges == j || j == NWK_MAX_LIST ); |
| pNext = Nwk_ManGraphListFindMinEdge( p, pVertex ); |
| Nwk_ManGraphUpdate( p, pVertex, pNext ); |
| break; |
| } |
| if ( j == NWK_MAX_LIST + 1 ) |
| break; |
| } |
| Nwk_ManGraphSortPairs( p ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Reads graph from file.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Nwk_Grf_t * Nwk_ManLutMergeReadGraph( char * pFileName ) |
| { |
| Nwk_Grf_t * p; |
| FILE * pFile; |
| char Buffer[100]; |
| int nNodes, nEdges, iNode1, iNode2; |
| int RetValue; |
| pFile = fopen( pFileName, "r" ); |
| RetValue = fscanf( pFile, "%s %d", Buffer, &nNodes ); |
| RetValue = fscanf( pFile, "%s %d", Buffer, &nEdges ); |
| p = Nwk_ManGraphAlloc( nNodes ); |
| while ( fscanf( pFile, "%s %d %d", Buffer, &iNode1, &iNode2 ) == 3 ) |
| Nwk_ManGraphHashEdge( p, iNode1, iNode2 ); |
| assert( p->nEdges == nEdges ); |
| fclose( pFile ); |
| return p; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Solves the graph coming from file.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Nwk_ManLutMergeGraphTest( char * pFileName ) |
| { |
| int nPairs; |
| Nwk_Grf_t * p; |
| abctime clk = Abc_Clock(); |
| p = Nwk_ManLutMergeReadGraph( pFileName ); |
| ABC_PRT( "Reading", Abc_Clock() - clk ); |
| clk = Abc_Clock(); |
| Nwk_ManGraphSolve( p ); |
| printf( "GRAPH: Nodes = %6d. Edges = %6d. Pairs = %6d. ", |
| p->nVerts, p->nEdges, Vec_IntSize(p->vPairs)/2 ); |
| ABC_PRT( "Solving", Abc_Clock() - clk ); |
| nPairs = Vec_IntSize(p->vPairs)/2; |
| Nwk_ManGraphReportMemoryUsage( p ); |
| Nwk_ManGraphFree( p ); |
| return nPairs; |
| } |
| |
| |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Marks the fanins of the node with the current trav ID.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManMarkFanins_rec( Nwk_Obj_t * pLut, int nLevMin ) |
| { |
| Nwk_Obj_t * pNext; |
| int i; |
| if ( !Nwk_ObjIsNode(pLut) ) |
| return; |
| if ( Nwk_ObjIsTravIdCurrent( pLut ) ) |
| return; |
| Nwk_ObjSetTravIdCurrent( pLut ); |
| if ( Nwk_ObjLevel(pLut) < nLevMin ) |
| return; |
| Nwk_ObjForEachFanin( pLut, pNext, i ) |
| Nwk_ManMarkFanins_rec( pNext, nLevMin ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Marks the fanouts of the node with the current trav ID.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManMarkFanouts_rec( Nwk_Obj_t * pLut, int nLevMax, int nFanMax ) |
| { |
| Nwk_Obj_t * pNext; |
| int i; |
| if ( !Nwk_ObjIsNode(pLut) ) |
| return; |
| if ( Nwk_ObjIsTravIdCurrent( pLut ) ) |
| return; |
| Nwk_ObjSetTravIdCurrent( pLut ); |
| if ( Nwk_ObjLevel(pLut) > nLevMax ) |
| return; |
| if ( Nwk_ObjFanoutNum(pLut) > nFanMax ) |
| return; |
| Nwk_ObjForEachFanout( pLut, pNext, i ) |
| Nwk_ManMarkFanouts_rec( pNext, nLevMax, nFanMax ); |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects the circle of nodes around the given set.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManCollectCircle( Vec_Ptr_t * vStart, Vec_Ptr_t * vNext, int nFanMax ) |
| { |
| Nwk_Obj_t * pObj, * pNext; |
| int i, k; |
| Vec_PtrClear( vNext ); |
| Vec_PtrForEachEntry( Nwk_Obj_t *, vStart, pObj, i ) |
| { |
| Nwk_ObjForEachFanin( pObj, pNext, k ) |
| { |
| if ( !Nwk_ObjIsNode(pNext) ) |
| continue; |
| if ( Nwk_ObjIsTravIdCurrent( pNext ) ) |
| continue; |
| Nwk_ObjSetTravIdCurrent( pNext ); |
| Vec_PtrPush( vNext, pNext ); |
| } |
| Nwk_ObjForEachFanout( pObj, pNext, k ) |
| { |
| if ( !Nwk_ObjIsNode(pNext) ) |
| continue; |
| if ( Nwk_ObjIsTravIdCurrent( pNext ) ) |
| continue; |
| Nwk_ObjSetTravIdCurrent( pNext ); |
| if ( Nwk_ObjFanoutNum(pNext) > nFanMax ) |
| continue; |
| Vec_PtrPush( vNext, pNext ); |
| } |
| } |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects the circle of nodes removes from the given one.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManCollectNonOverlapCands( Nwk_Obj_t * pLut, Vec_Ptr_t * vStart, Vec_Ptr_t * vNext, Vec_Ptr_t * vCands, Nwk_LMPars_t * pPars ) |
| { |
| Vec_Ptr_t * vTemp; |
| Nwk_Obj_t * pObj; |
| int i, k; |
| Vec_PtrClear( vCands ); |
| if ( pPars->nMaxSuppSize - Nwk_ObjFaninNum(pLut) <= 1 ) |
| return; |
| |
| // collect nodes removed by this distance |
| assert( pPars->nMaxDistance > 0 ); |
| Vec_PtrClear( vStart ); |
| Vec_PtrPush( vStart, pLut ); |
| Nwk_ManIncrementTravId( pLut->pMan ); |
| Nwk_ObjSetTravIdCurrent( pLut ); |
| for ( i = 1; i <= pPars->nMaxDistance; i++ ) |
| { |
| Nwk_ManCollectCircle( vStart, vNext, pPars->nMaxFanout ); |
| vTemp = vStart; |
| vStart = vNext; |
| vNext = vTemp; |
| // collect the nodes in vStart |
| Vec_PtrForEachEntry( Nwk_Obj_t *, vStart, pObj, k ) |
| Vec_PtrPush( vCands, pObj ); |
| } |
| |
| // mark the TFI/TFO nodes |
| Nwk_ManIncrementTravId( pLut->pMan ); |
| if ( pPars->fUseTfiTfo ) |
| Nwk_ObjSetTravIdCurrent( pLut ); |
| else |
| { |
| Nwk_ObjSetTravIdPrevious( pLut ); |
| Nwk_ManMarkFanins_rec( pLut, Nwk_ObjLevel(pLut) - pPars->nMaxDistance ); |
| Nwk_ObjSetTravIdPrevious( pLut ); |
| Nwk_ManMarkFanouts_rec( pLut, Nwk_ObjLevel(pLut) + pPars->nMaxDistance, pPars->nMaxFanout ); |
| } |
| |
| // collect nodes satisfying the following conditions: |
| // - they are close enough in terms of distance |
| // - they are not in the TFI/TFO of the LUT |
| // - they have no more than the given number of fanins |
| // - they have no more than the given diff in delay |
| k = 0; |
| Vec_PtrForEachEntry( Nwk_Obj_t *, vCands, pObj, i ) |
| { |
| if ( Nwk_ObjIsTravIdCurrent(pObj) ) |
| continue; |
| if ( Nwk_ObjFaninNum(pLut) + Nwk_ObjFaninNum(pObj) > pPars->nMaxSuppSize ) |
| continue; |
| if ( Nwk_ObjLevel(pLut) - Nwk_ObjLevel(pObj) > pPars->nMaxLevelDiff || |
| Nwk_ObjLevel(pObj) - Nwk_ObjLevel(pLut) > pPars->nMaxLevelDiff ) |
| continue; |
| Vec_PtrWriteEntry( vCands, k++, pObj ); |
| } |
| Vec_PtrShrink( vCands, k ); |
| } |
| |
| |
| /**Function************************************************************* |
| |
| Synopsis [Count the total number of fanins.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| int Nwk_ManCountTotalFanins( Nwk_Obj_t * pLut, Nwk_Obj_t * pCand ) |
| { |
| Nwk_Obj_t * pFanin; |
| int i, nCounter = Nwk_ObjFaninNum(pLut); |
| Nwk_ObjForEachFanin( pCand, pFanin, i ) |
| nCounter += !pFanin->MarkC; |
| return nCounter; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Collects overlapping candidates.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| void Nwk_ManCollectOverlapCands( Nwk_Obj_t * pLut, Vec_Ptr_t * vCands, Nwk_LMPars_t * pPars ) |
| { |
| Nwk_Obj_t * pFanin, * pObj; |
| int i, k; |
| // mark fanins of pLut |
| Nwk_ObjForEachFanin( pLut, pFanin, i ) |
| pFanin->MarkC = 1; |
| // collect the matching fanouts of each fanin of the node |
| Vec_PtrClear( vCands ); |
| Nwk_ManIncrementTravId( pLut->pMan ); |
| Nwk_ObjSetTravIdCurrent( pLut ); |
| Nwk_ObjForEachFanin( pLut, pFanin, i ) |
| { |
| if ( !Nwk_ObjIsNode(pFanin) ) |
| continue; |
| if ( Nwk_ObjFanoutNum(pFanin) > pPars->nMaxFanout ) |
| continue; |
| Nwk_ObjForEachFanout( pFanin, pObj, k ) |
| { |
| if ( !Nwk_ObjIsNode(pObj) ) |
| continue; |
| if ( Nwk_ObjIsTravIdCurrent( pObj ) ) |
| continue; |
| Nwk_ObjSetTravIdCurrent( pObj ); |
| // check the difference in delay |
| if ( Nwk_ObjLevel(pLut) - Nwk_ObjLevel(pObj) > pPars->nMaxLevelDiff || |
| Nwk_ObjLevel(pObj) - Nwk_ObjLevel(pLut) > pPars->nMaxLevelDiff ) |
| continue; |
| // check the total number of fanins of the node |
| if ( Nwk_ManCountTotalFanins(pLut, pObj) > pPars->nMaxSuppSize ) |
| continue; |
| Vec_PtrPush( vCands, pObj ); |
| } |
| } |
| // unmark fanins of pLut |
| Nwk_ObjForEachFanin( pLut, pFanin, i ) |
| pFanin->MarkC = 0; |
| } |
| |
| /**Function************************************************************* |
| |
| Synopsis [Performs LUT merging with parameters.] |
| |
| Description [] |
| |
| SideEffects [] |
| |
| SeeAlso [] |
| |
| ***********************************************************************/ |
| Vec_Int_t * Nwk_ManLutMerge( Nwk_Man_t * pNtk, void * pParsInit ) |
| { |
| Nwk_LMPars_t * pPars = (Nwk_LMPars_t *)pParsInit; |
| Nwk_Grf_t * p; |
| Vec_Int_t * vResult; |
| Vec_Ptr_t * vStart, * vNext, * vCands1, * vCands2; |
| Nwk_Obj_t * pLut, * pCand; |
| int i, k, nVertsMax, nCands; |
| abctime clk = Abc_Clock(); |
| // count the number of vertices |
| nVertsMax = 0; |
| Nwk_ManForEachNode( pNtk, pLut, i ) |
| nVertsMax += (int)(Nwk_ObjFaninNum(pLut) <= pPars->nMaxLutSize); |
| p = Nwk_ManGraphAlloc( nVertsMax ); |
| // create graph |
| vStart = Vec_PtrAlloc( 1000 ); |
| vNext = Vec_PtrAlloc( 1000 ); |
| vCands1 = Vec_PtrAlloc( 1000 ); |
| vCands2 = Vec_PtrAlloc( 1000 ); |
| nCands = 0; |
| Nwk_ManForEachNode( pNtk, pLut, i ) |
| { |
| if ( Nwk_ObjFaninNum(pLut) > pPars->nMaxLutSize ) |
| continue; |
| Nwk_ManCollectOverlapCands( pLut, vCands1, pPars ); |
| if ( pPars->fUseDiffSupp ) |
| Nwk_ManCollectNonOverlapCands( pLut, vStart, vNext, vCands2, pPars ); |
| if ( Vec_PtrSize(vCands1) == 0 && Vec_PtrSize(vCands2) == 0 ) |
| continue; |
| nCands += Vec_PtrSize(vCands1) + Vec_PtrSize(vCands2); |
| // save candidates |
| Vec_PtrForEachEntry( Nwk_Obj_t *, vCands1, pCand, k ) |
| Nwk_ManGraphHashEdge( p, Nwk_ObjId(pLut), Nwk_ObjId(pCand) ); |
| Vec_PtrForEachEntry( Nwk_Obj_t *, vCands2, pCand, k ) |
| Nwk_ManGraphHashEdge( p, Nwk_ObjId(pLut), Nwk_ObjId(pCand) ); |
| // print statistics about this node |
| if ( pPars->fVeryVerbose ) |
| printf( "Node %6d : Fanins = %d. Fanouts = %3d. Cand1 = %3d. Cand2 = %3d.\n", |
| Nwk_ObjId(pLut), Nwk_ObjFaninNum(pLut), Nwk_ObjFaninNum(pLut), |
| Vec_PtrSize(vCands1), Vec_PtrSize(vCands2) ); |
| } |
| Vec_PtrFree( vStart ); |
| Vec_PtrFree( vNext ); |
| Vec_PtrFree( vCands1 ); |
| Vec_PtrFree( vCands2 ); |
| if ( pPars->fVerbose ) |
| { |
| printf( "Mergable LUTs = %6d. Total cands = %6d. ", p->nVertsMax, nCands ); |
| ABC_PRT( "Deriving graph", Abc_Clock() - clk ); |
| } |
| // solve the graph problem |
| clk = Abc_Clock(); |
| Nwk_ManGraphSolve( p ); |
| if ( pPars->fVerbose ) |
| { |
| printf( "GRAPH: Nodes = %6d. Edges = %6d. Pairs = %6d. ", |
| p->nVerts, p->nEdges, Vec_IntSize(p->vPairs)/2 ); |
| ABC_PRT( "Solving", Abc_Clock() - clk ); |
| Nwk_ManGraphReportMemoryUsage( p ); |
| } |
| vResult = p->vPairs; p->vPairs = NULL; |
| /* |
| for ( i = 0; i < vResult->nSize; i += 2 ) |
| printf( "(%d,%d) ", vResult->pArray[i], vResult->pArray[i+1] ); |
| printf( "\n" ); |
| */ |
| Nwk_ManGraphFree( p ); |
| return vResult; |
| } |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| |
| ABC_NAMESPACE_IMPL_END |
| |