| /**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 |