| /**CFile**************************************************************** |
| |
| FileName [ FxchSCHashTable.c ] |
| |
| PackageName [ Fast eXtract with Cube Hashing (FXCH) ] |
| |
| Synopsis [ Sub-cubes hash table implementation ] |
| |
| Author [ Bruno Schmitt - boschmitt at inf.ufrgs.br ] |
| |
| Affiliation [ UFRGS ] |
| |
| Date [ Ver. 1.0. Started - March 6, 2016. ] |
| |
| Revision [] |
| |
| ***********************************************************************/ |
| #include "Fxch.h" |
| |
| ABC_NAMESPACE_IMPL_START |
| |
| //////////////////////////////////////////////////////////////////////// |
| /// FUNCTION DEFINITIONS /// |
| //////////////////////////////////////////////////////////////////////// |
| static inline void MurmurHash3_x86_32 ( const void* key, |
| int len, |
| uint32_t seed, |
| void* out ) |
| { |
| const uint8_t* data = (const uint8_t*)key; |
| const int nblocks = len / 4; |
| |
| uint32_t h1 = seed; |
| |
| const uint32_t c1 = 0xcc9e2d51; |
| const uint32_t c2 = 0x1b873593; |
| |
| const uint8_t * tail; |
| uint32_t k1; |
| |
| //---------- |
| // body |
| |
| const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); |
| int i; |
| |
| for(i = -nblocks; i; i++) |
| { |
| uint32_t k1 = blocks[i]; |
| |
| k1 *= c1; |
| k1 = (k1 << 15) | (k1 >> (32 - 15)); |
| k1 *= c2; |
| |
| h1 ^= k1; |
| h1 = (h1 << 13) | (h1 >> (32 - 13)); |
| h1 = h1*5+0xe6546b64; |
| } |
| |
| //---------- |
| // tail |
| |
| tail = (const uint8_t*)(data + nblocks*4); |
| |
| k1 = 0; |
| |
| switch(len & 3) |
| { |
| case 3: k1 ^= tail[2] << 16; |
| case 2: k1 ^= tail[1] << 8; |
| case 1: k1 ^= tail[0]; |
| k1 *= c1; k1 = (k1 << 15) | (k1 >> (32 - 15)); k1 *= c2; h1 ^= k1; |
| }; |
| |
| //---------- |
| // finalization |
| |
| h1 ^= len; |
| |
| h1 ^= h1 >> 16; |
| h1 *= 0x85ebca6b; |
| h1 ^= h1 >> 13; |
| h1 *= 0xc2b2ae35; |
| h1 ^= h1 >> 16; |
| |
| *(uint32_t*)out = h1; |
| } |
| |
| Fxch_SCHashTable_t* Fxch_SCHashTableCreate( Fxch_Man_t* pFxchMan, |
| int nEntries ) |
| { |
| Fxch_SCHashTable_t* pSCHashTable = ABC_CALLOC( Fxch_SCHashTable_t, 1 ); |
| int nBits = Abc_Base2Log( nEntries + 1 ); |
| |
| |
| pSCHashTable->pFxchMan = pFxchMan; |
| pSCHashTable->SizeMask = (1 << nBits) - 1; |
| pSCHashTable->pBins = ABC_CALLOC( Fxch_SCHashTable_Entry_t, pSCHashTable->SizeMask + 1 ); |
| |
| return pSCHashTable; |
| } |
| |
| void Fxch_SCHashTableDelete( Fxch_SCHashTable_t* pSCHashTable ) |
| { |
| unsigned i; |
| for ( i = 0; i <= pSCHashTable->SizeMask; i++ ) |
| ABC_FREE( pSCHashTable->pBins[i].vSCData ); |
| Vec_IntErase( &pSCHashTable->vSubCube0 ); |
| Vec_IntErase( &pSCHashTable->vSubCube1 ); |
| ABC_FREE( pSCHashTable->pBins ); |
| ABC_FREE( pSCHashTable ); |
| } |
| |
| static inline Fxch_SCHashTable_Entry_t* Fxch_SCHashTableBin( Fxch_SCHashTable_t* pSCHashTable, |
| unsigned int SubCubeID ) |
| { |
| return pSCHashTable->pBins + (SubCubeID & pSCHashTable->SizeMask); |
| } |
| |
| static inline int Fxch_SCHashTableEntryCompare( Fxch_SCHashTable_t* pSCHashTable, |
| Vec_Wec_t* vCubes, |
| Fxch_SubCube_t* pSCData0, |
| Fxch_SubCube_t* pSCData1 ) |
| { |
| Vec_Int_t* vCube0 = Vec_WecEntry( vCubes, pSCData0->iCube ), |
| * vCube1 = Vec_WecEntry( vCubes, pSCData1->iCube ); |
| |
| int* pOutputID0 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pSCData0->iCube * pSCHashTable->pFxchMan->nSizeOutputID ), |
| * pOutputID1 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pSCData1->iCube * pSCHashTable->pFxchMan->nSizeOutputID ); |
| int i, Result = 0; |
| |
| if ( !Vec_IntSize( vCube0 ) || |
| !Vec_IntSize( vCube1 ) || |
| Vec_IntEntry( vCube0, 0 ) != Vec_IntEntry( vCube1, 0 ) || |
| pSCData0->Id != pSCData1->Id ) |
| return 0; |
| |
| for ( i = 0; i < pSCHashTable->pFxchMan->nSizeOutputID && Result == 0; i++ ) |
| Result = ( pOutputID0[i] & pOutputID1[i] ); |
| |
| if ( Result == 0 ) |
| return 0; |
| |
| Vec_IntClear( &pSCHashTable->vSubCube0 ); |
| Vec_IntClear( &pSCHashTable->vSubCube1 ); |
| |
| if ( pSCData0->iLit1 > 0 && pSCData1->iLit1 > 0 && |
| ( Vec_IntEntry( vCube0, pSCData0->iLit0 ) == Vec_IntEntry( vCube1, pSCData1->iLit0 ) || |
| Vec_IntEntry( vCube0, pSCData0->iLit0 ) == Vec_IntEntry( vCube1, pSCData1->iLit1 ) || |
| Vec_IntEntry( vCube0, pSCData0->iLit1 ) == Vec_IntEntry( vCube1, pSCData1->iLit0 ) || |
| Vec_IntEntry( vCube0, pSCData0->iLit1 ) == Vec_IntEntry( vCube1, pSCData1->iLit1 ) ) ) |
| return 0; |
| |
| if ( pSCData0->iLit0 > 0 ) |
| Vec_IntAppendSkip( &pSCHashTable->vSubCube0, vCube0, pSCData0->iLit0 ); |
| else |
| Vec_IntAppend( &pSCHashTable->vSubCube0, vCube0 ); |
| |
| if ( pSCData1->iLit0 > 0 ) |
| Vec_IntAppendSkip( &pSCHashTable->vSubCube1, vCube1, pSCData1->iLit0 ); |
| else |
| Vec_IntAppend( &pSCHashTable->vSubCube1, vCube1 ); |
| |
| if ( pSCData0->iLit1 > 0) |
| Vec_IntDrop( &pSCHashTable->vSubCube0, |
| pSCData0->iLit0 < pSCData0->iLit1 ? pSCData0->iLit1 - 1 : pSCData0->iLit1 ); |
| |
| if ( pSCData1->iLit1 > 0 ) |
| Vec_IntDrop( &pSCHashTable->vSubCube1, |
| pSCData1->iLit0 < pSCData1->iLit1 ? pSCData1->iLit1 - 1 : pSCData1->iLit1 ); |
| |
| return Vec_IntEqual( &pSCHashTable->vSubCube0, &pSCHashTable->vSubCube1 ); |
| } |
| |
| int Fxch_SCHashTableInsert( Fxch_SCHashTable_t* pSCHashTable, |
| Vec_Wec_t* vCubes, |
| uint32_t SubCubeID, |
| uint32_t iCube, |
| uint32_t iLit0, |
| uint32_t iLit1, |
| char fUpdate ) |
| { |
| int iNewEntry; |
| int Pairs = 0; |
| uint32_t BinID; |
| Fxch_SCHashTable_Entry_t* pBin; |
| Fxch_SubCube_t* pNewEntry; |
| int iEntry; |
| |
| MurmurHash3_x86_32( ( void* ) &SubCubeID, sizeof( int ), 0x9747b28c, &BinID); |
| pBin = Fxch_SCHashTableBin( pSCHashTable, BinID ); |
| |
| if ( pBin->vSCData == NULL ) |
| { |
| pBin->vSCData = ABC_CALLOC( Fxch_SubCube_t, 16 ); |
| pBin->Size = 0; |
| pBin->Cap = 16; |
| } |
| else if ( pBin->Size == pBin->Cap ) |
| { |
| assert(pBin->Cap <= 0xAAAA); |
| pBin->Cap = ( pBin->Cap >> 1 ) * 3; |
| pBin->vSCData = ABC_REALLOC( Fxch_SubCube_t, pBin->vSCData, pBin->Cap ); |
| } |
| |
| iNewEntry = pBin->Size++; |
| pBin->vSCData[iNewEntry].Id = SubCubeID; |
| pBin->vSCData[iNewEntry].iCube = iCube; |
| pBin->vSCData[iNewEntry].iLit0 = iLit0; |
| pBin->vSCData[iNewEntry].iLit1 = iLit1; |
| pSCHashTable->nEntries++; |
| |
| if ( pBin->Size == 1 ) |
| return 0; |
| |
| pNewEntry = &( pBin->vSCData[iNewEntry] ); |
| for ( iEntry = 0; iEntry < (int)pBin->Size - 1; iEntry++ ) |
| { |
| Fxch_SubCube_t* pEntry = &( pBin->vSCData[iEntry] ); |
| int* pOutputID0 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pEntry->iCube * pSCHashTable->pFxchMan->nSizeOutputID ); |
| int* pOutputID1 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pNewEntry->iCube * pSCHashTable->pFxchMan->nSizeOutputID ); |
| int Result = 0; |
| int Base; |
| int iNewDiv = -1, i, z; |
| |
| if ( (pEntry->iLit1 != 0 && pNewEntry->iLit1 == 0) || (pEntry->iLit1 == 0 && pNewEntry->iLit1 != 0) ) |
| continue; |
| |
| if ( !Fxch_SCHashTableEntryCompare( pSCHashTable, vCubes, pEntry, pNewEntry ) ) |
| continue; |
| |
| if ( ( pEntry->iLit0 == 0 ) || ( pNewEntry->iLit0 == 0 ) ) |
| { |
| Vec_Int_t* vCube0 = Fxch_ManGetCube( pSCHashTable->pFxchMan, pEntry->iCube ), |
| * vCube1 = Fxch_ManGetCube( pSCHashTable->pFxchMan, pNewEntry->iCube ); |
| |
| if ( Vec_IntSize( vCube0 ) > Vec_IntSize( vCube1 ) ) |
| { |
| Vec_IntPush( pSCHashTable->pFxchMan->vSCC, pEntry->iCube ); |
| Vec_IntPush( pSCHashTable->pFxchMan->vSCC, pNewEntry->iCube ); |
| } |
| else |
| { |
| Vec_IntPush( pSCHashTable->pFxchMan->vSCC, pNewEntry->iCube ); |
| Vec_IntPush( pSCHashTable->pFxchMan->vSCC, pEntry->iCube ); |
| } |
| |
| continue; |
| } |
| |
| Base = Fxch_DivCreate( pSCHashTable->pFxchMan, pEntry, pNewEntry ); |
| |
| if ( Base < 0 ) |
| continue; |
| |
| for ( i = 0; i < pSCHashTable->pFxchMan->nSizeOutputID; i++ ) |
| Result += Fxch_CountOnes( pOutputID0[i] & pOutputID1[i] ); |
| |
| for ( z = 0; z < Result; z++ ) |
| iNewDiv = Fxch_DivAdd( pSCHashTable->pFxchMan, fUpdate, 0, Base ); |
| |
| Vec_WecPush( pSCHashTable->pFxchMan->vDivCubePairs, iNewDiv, pEntry->iCube ); |
| Vec_WecPush( pSCHashTable->pFxchMan->vDivCubePairs, iNewDiv, pNewEntry->iCube ); |
| |
| Pairs++; |
| } |
| |
| return Pairs; |
| } |
| |
| int Fxch_SCHashTableRemove( Fxch_SCHashTable_t* pSCHashTable, |
| Vec_Wec_t* vCubes, |
| uint32_t SubCubeID, |
| uint32_t iCube, |
| uint32_t iLit0, |
| uint32_t iLit1, |
| char fUpdate ) |
| { |
| int iEntry; |
| int Pairs = 0; |
| uint32_t BinID; |
| Fxch_SCHashTable_Entry_t* pBin; |
| Fxch_SubCube_t* pEntry; |
| int idx; |
| |
| MurmurHash3_x86_32( ( void* ) &SubCubeID, sizeof( int ), 0x9747b28c, &BinID); |
| |
| pBin = Fxch_SCHashTableBin( pSCHashTable, BinID ); |
| |
| if ( pBin->Size == 1 ) |
| { |
| pBin->Size = 0; |
| return 0; |
| } |
| |
| for ( iEntry = 0; iEntry < (int)pBin->Size; iEntry++ ) |
| if ( pBin->vSCData[iEntry].iCube == iCube ) |
| break; |
| |
| assert( ( iEntry != (int)pBin->Size ) && ( pBin->Size != 0 ) ); |
| |
| pEntry = &( pBin->vSCData[iEntry] ); |
| for ( idx = 0; idx < (int)pBin->Size; idx++ ) |
| if ( idx != iEntry ) |
| { |
| int Base, |
| iDiv = -1; |
| |
| int i, z, |
| iCube0, |
| iCube1; |
| |
| Fxch_SubCube_t* pNextEntry = &( pBin->vSCData[idx] ); |
| Vec_Int_t* vDivCubePairs; |
| int* pOutputID0 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pEntry->iCube * pSCHashTable->pFxchMan->nSizeOutputID ); |
| int* pOutputID1 = Vec_IntEntryP( pSCHashTable->pFxchMan->vOutputID, pNextEntry->iCube * pSCHashTable->pFxchMan->nSizeOutputID ); |
| int Result = 0; |
| |
| if ( (pEntry->iLit1 != 0 && pNextEntry->iLit1 == 0) || (pEntry->iLit1 == 0 && pNextEntry->iLit1 != 0) ) |
| continue; |
| |
| if ( !Fxch_SCHashTableEntryCompare( pSCHashTable, vCubes, pEntry, pNextEntry ) |
| || pEntry->iLit0 == 0 |
| || pNextEntry->iLit0 == 0 ) |
| continue; |
| |
| Base = Fxch_DivCreate( pSCHashTable->pFxchMan, pNextEntry, pEntry ); |
| |
| if ( Base < 0 ) |
| continue; |
| |
| for ( i = 0; i < pSCHashTable->pFxchMan->nSizeOutputID; i++ ) |
| Result += Fxch_CountOnes( pOutputID0[i] & pOutputID1[i] ); |
| |
| for ( z = 0; z < Result; z++ ) |
| iDiv = Fxch_DivRemove( pSCHashTable->pFxchMan, fUpdate, 0, Base ); |
| |
| vDivCubePairs = Vec_WecEntry( pSCHashTable->pFxchMan->vDivCubePairs, iDiv ); |
| Vec_IntForEachEntryDouble( vDivCubePairs, iCube0, iCube1, i ) |
| if ( ( iCube0 == (int)pNextEntry->iCube && iCube1 == (int)pEntry->iCube ) || |
| ( iCube0 == (int)pEntry->iCube && iCube1 == (int)pNextEntry->iCube ) ) |
| { |
| Vec_IntDrop( vDivCubePairs, i+1 ); |
| Vec_IntDrop( vDivCubePairs, i ); |
| } |
| if ( Vec_IntSize( vDivCubePairs ) == 0 ) |
| Vec_IntErase( vDivCubePairs ); |
| |
| Pairs++; |
| } |
| |
| memmove(pBin->vSCData + iEntry, pBin->vSCData + iEntry + 1, (pBin->Size - iEntry - 1) * sizeof(*pBin->vSCData)); |
| pBin->Size -= 1; |
| |
| return Pairs; |
| } |
| |
| unsigned int Fxch_SCHashTableMemory( Fxch_SCHashTable_t* pHashTable ) |
| { |
| unsigned int Memory = sizeof ( Fxch_SCHashTable_t ); |
| |
| Memory += sizeof( Fxch_SubCube_t ) * ( pHashTable->SizeMask + 1 ); |
| |
| return Memory; |
| } |
| |
| void Fxch_SCHashTablePrint( Fxch_SCHashTable_t* pHashTable ) |
| { |
| int Memory; |
| printf( "SubCube Hash Table at %p\n", ( void* )pHashTable ); |
| printf("%20s %20s\n", "nEntries", |
| "Memory Usage (MB)" ); |
| |
| Memory = Fxch_SCHashTableMemory( pHashTable ); |
| printf("%20d %18.2f\n", pHashTable->nEntries, |
| ( ( double ) Memory / 1048576 ) ); |
| } |
| //////////////////////////////////////////////////////////////////////// |
| /// END OF FILE /// |
| //////////////////////////////////////////////////////////////////////// |
| |
| ABC_NAMESPACE_IMPL_END |