/// <summary> /// Hash the given name using the given hash functions. /// </summary> /// <param name="name">The name to hash.</param> /// <param name="phf1">PearsonHashFunction to use for the upper /// eight bits of the hash.</param> /// <param name="phf2">PearsonHashFunction to use for the lower /// eight bits of the hash.</param> /// <param name="hashMask">The mask value to be applied to the /// hash.</param> /// <returns>The hash value, masked by hashMask.</returns> private static int HashName(string name, PearsonHashFunction phf1, PearsonHashFunction phf2, int hashMask) { // Get the word name as an array of uppercase ASCII bytes. string upperName = name.ToUpperInvariant(); byte[] upperNameBytes = Encoding.ASCII.GetBytes(upperName); // Hash the name. Use phf1 for the upper eight bits and // phf2 for the lower eight bits. Then mask off the hash // value to keep it within range of our hash table. return(((phf1.Hash(upperNameBytes) << 8) | phf2.Hash(upperNameBytes)) & hashMask); }
/// <summary> /// Hash the given name using the given hash functions. /// </summary> /// <param name="name">The name to hash.</param> /// <param name="phf1">PearsonHashFunction to use for the upper /// eight bits of the hash.</param> /// <param name="phf2">PearsonHashFunction to use for the lower /// eight bits of the hash.</param> /// <param name="hashMask">The mask value to be applied to the /// hash.</param> /// <returns>The hash value, masked by hashMask.</returns> private static int HashName(string name, PearsonHashFunction phf1, PearsonHashFunction phf2, int hashMask) { // Get the word name as an array of uppercase ASCII bytes. string upperName = name.ToUpperInvariant(); byte[] upperNameBytes = Encoding.ASCII.GetBytes(upperName); // Hash the name. Use phf1 for the upper eight bits and // phf2 for the lower eight bits. Then mask off the hash // value to keep it within range of our hash table. return ((phf1.Hash(upperNameBytes) << 8) | phf2.Hash(upperNameBytes)) & hashMask; }
/// <summary> /// Generate the MFORTH hash table. /// </summary> /// <param name="rom">MFORTH ROM.</param> /// <param name="phf1">Upon return, will contain the first /// PearsonHashFunction used by the hash table.</param> /// <param name="phf2">Upon return, will contain the second /// PearsonHashFunction used by the hash table.</param> /// <returns>The MFORTH hash table.</returns> private static CuckooHashTable<Word> GenerateHashTable(ROM rom, out PearsonHashFunction phf1, out PearsonHashFunction phf2) { // Initialize our random number generator. var random = new Random(HashTableRandomSeed); // Initialize our hash functions and the hash table. var hashFunc1 = phf1 = new PearsonHashFunction(random); var hashFunc2 = phf2 = new PearsonHashFunction(random); var hashTable = new CuckooHashTable<Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); // Generate the hash table. #if FINDING_OPTIMAL_HASH_SEED int minValuesAtSecondLocation = int.MaxValue; #endif for (;;) { #if !FINDING_OPTIMAL_HASH_SEED // Display a progress dot. Console.Write("."); #endif // Add all of the words to our hash table; assume that // we will be successful. bool haveCompleteTable = true; foreach (var word in rom.Words) { if (!hashTable.TryAddValue(word)) { haveCompleteTable = false; break; } } #if !FINDING_OPTIMAL_HASH_SEED // We're done if all of the words were added to the // table. if (haveCompleteTable) { break; } // We failed to generate a complete hash table; shuffle // the hash functions, clear the table, and try again. phf1.ShuffleAuxilliaryTable(random); phf2.ShuffleAuxilliaryTable(random); hashTable.Clear(); #else // Print out the results if this seed produced better // results than the previous best seed. if (haveCompleteTable && hashTable.NumValuesStoredAtSecondHash < minValuesAtSecondLocation) { Console.WriteLine( "Seed: {0}; 1st: {1}; 2nd: {2}", HashTableRandomSeed, hashTable.NumValuesStoredAtFirstHash, hashTable.NumValuesStoredAtSecondHash); minValuesAtSecondLocation = hashTable.NumValuesStoredAtSecondHash; } // Generate a new seed and re-create all of the hash // functions and tables. random = new Random(++HashTableRandomSeed); hashFunc1 = phf1 = new PearsonHashFunction(random); hashFunc2 = phf2 = new PearsonHashFunction(random); hashTable = new CuckooHashTable<Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); #endif } // Ensure that all of the words in the ROM were added to the // hash table. if (rom.NumWords != hashTable.Count) { throw new InvalidDataException( string.Format( "Hash table only has {0} words; expected {1} words.", hashTable.Count, rom.NumWords)); } // Return the hash table. return hashTable; }
/// <summary> /// Generate the MFORTH hash table. /// </summary> /// <param name="rom">MFORTH ROM.</param> /// <param name="phf1">Upon return, will contain the first /// PearsonHashFunction used by the hash table.</param> /// <param name="phf2">Upon return, will contain the second /// PearsonHashFunction used by the hash table.</param> /// <returns>The MFORTH hash table.</returns> private static CuckooHashTable <Word> GenerateHashTable(ROM rom, out PearsonHashFunction phf1, out PearsonHashFunction phf2) { // Initialize our random number generator. var random = new Random(HashTableRandomSeed); // Initialize our hash functions and the hash table. var hashFunc1 = phf1 = new PearsonHashFunction(random); var hashFunc2 = phf2 = new PearsonHashFunction(random); var hashTable = new CuckooHashTable <Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); // Generate the hash table. #if FINDING_OPTIMAL_HASH_SEED int minValuesAtSecondLocation = int.MaxValue; #endif for (;;) { #if !FINDING_OPTIMAL_HASH_SEED // Display a progress dot. Console.Write("."); #endif // Add all of the words to our hash table; assume that // we will be successful. bool haveCompleteTable = true; foreach (var word in rom.Words) { if (!hashTable.TryAddValue(word)) { haveCompleteTable = false; break; } } #if !FINDING_OPTIMAL_HASH_SEED // We're done if all of the words were added to the // table. if (haveCompleteTable) { break; } // We failed to generate a complete hash table; shuffle // the hash functions, clear the table, and try again. phf1.ShuffleAuxilliaryTable(random); phf2.ShuffleAuxilliaryTable(random); hashTable.Clear(); #else // Print out the results if this seed produced better // results than the previous best seed. if (haveCompleteTable && hashTable.NumValuesStoredAtSecondHash < minValuesAtSecondLocation) { Console.WriteLine( "Seed: {0}; 1st: {1}; 2nd: {2}", HashTableRandomSeed, hashTable.NumValuesStoredAtFirstHash, hashTable.NumValuesStoredAtSecondHash); minValuesAtSecondLocation = hashTable.NumValuesStoredAtSecondHash; } // Generate a new seed and re-create all of the hash // functions and tables. random = new Random(++HashTableRandomSeed); hashFunc1 = phf1 = new PearsonHashFunction(random); hashFunc2 = phf2 = new PearsonHashFunction(random); hashTable = new CuckooHashTable <Word>( (w) => HashName(w.Name, hashFunc1, hashFunc2, HashMask), (w) => HashName(w.Name, hashFunc2, hashFunc1, HashMask)); #endif } // Ensure that all of the words in the ROM were added to the // hash table. if (rom.NumWords != hashTable.Count) { throw new InvalidDataException( string.Format( "Hash table only has {0} words; expected {1} words.", hashTable.Count, rom.NumWords)); } // Return the hash table. return(hashTable); }