Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move combine_hash function to tools/hash_utils #205

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ files at lower levels.
| Level | Folders
| ---- | ----
| 0 | base/
| 1 | meta/
| 2 | tools/
| 1 | tools/
| 2 | meta/
| 3 | config/ control/ data/ games/ geometry/ hardware/ scholar/
| 4 | Evolve/ (data, control) web/ (config, control)
6 changes: 4 additions & 2 deletions source/meta/meta.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <tuple>
#include <utility>

#include "tools/hash_utils.h"

namespace emp {

// A function that will take any number of argument and do nothing with them.
Expand Down Expand Up @@ -212,8 +214,8 @@ namespace emp {
template<typename T1, typename T2, typename... EXTRA>
std::size_t CombineHash(const T1 & x1, const T2 & x2, const EXTRA &... x_extra) {
const std::size_t hash2 = CombineHash(x2, x_extra...);
//return std::hash<T1>()(x1) + 0x9e3779b9 + (hash2 << 19) + (hash2 >> 13);
return Hash<T1>(x1) + 0x9e3779b9 + (hash2 << 19) + (hash2 >> 13);

return combine_hash(Hash<T1>(x1), hash2);
}


Expand Down
8 changes: 8 additions & 0 deletions source/tools/hash_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@

namespace emp {

/// mixin: the additional value to mix in to the hash soup
/// acc: the accumulated value
/// RE implementation see, e.g.,
/// https://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
size_t combine_hash(size_t mixin, size_t acc) {
return mixin + 0x9e3779b9 + (acc << 19) + (acc >> 13);
}

/// generate a unique long from a pair of ints
uint64_t szudzik_hash(uint32_t a_, uint32_t b_)
{
Expand Down
61 changes: 61 additions & 0 deletions tests/test_tools.cc
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,67 @@ TEST_CASE("Test Graph utils", "[tools]")
TEST_CASE("Test hash_utils", "[tools]")
{

// combine_hash
emp::vector<size_t> v1 = {0,0,0,1,1,1};
emp::vector<size_t> v2 = {1,1,1,42,53,101,1,0,0,0,};
emp::vector<size_t> v3 = {42,42,42,1,1,1};
emp::vector<size_t> v4 = {11};

emp::Random r(1);
size_t target_len = 25;
while (v1.size() < target_len) { v1.push_back(r.GetUInt()); }
while (v2.size() < target_len) { v2.push_back(r.GetUInt()); }
while (v3.size() < target_len) { v3.push_back(r.GetUInt()); }
while (v4.size() < target_len) { v4.push_back(r.GetUInt()); }

emp::vector<size_t> h1, h2, h3, h4;
h1.push_back(0);
for (size_t v : v1) h1.push_back(emp::combine_hash(v,h1.back()));
h1.erase(h1.begin());
h2.push_back(1);
for (size_t v : v2) h2.push_back(emp::combine_hash(v,h2.back()));
h2.erase(h2.begin());
h3.push_back(1);
for (size_t v : v3) h3.push_back(emp::combine_hash(v,h3.back()));
h3.erase(h3.begin());
h4.push_back(1);
for (size_t v : v4) h4.push_back(emp::combine_hash(v,h4.back()));
h4.erase(h4.begin());

auto s1 = std::unordered_set<size_t>(h1.begin(),h1.end());
REQUIRE(s1.size() == target_len);
auto s2 = std::unordered_set<size_t>(h2.begin(),h2.end());
REQUIRE(s2.size() == target_len);
auto s3 = std::unordered_set<size_t>(h3.begin(),h3.end());
REQUIRE(s3.size() == target_len);
auto s4 = std::unordered_set<size_t>(h4.begin(),h4.end());
REQUIRE(s4.size() == target_len);

auto vs1 = std::unordered_set<size_t>(v1.begin(),v1.end());
auto vs2 = std::unordered_set<size_t>(v2.begin(),v2.end());
auto vs3 = std::unordered_set<size_t>(v3.begin(),v3.end());
auto vs4 = std::unordered_set<size_t>(v4.begin(),v4.end());

s1.insert(vs1.begin(),vs1.end());
s2.insert(vs2.begin(),vs2.end());
s3.insert(vs3.begin(),vs3.end());
s4.insert(vs4.begin(),vs4.end());

REQUIRE(s1.size() == target_len + vs1.size());
REQUIRE(s2.size() == target_len + vs2.size());
REQUIRE(s3.size() == target_len + vs3.size());
REQUIRE(s4.size() == target_len + vs4.size());

s1.insert(s2.begin(),s2.end());
s1.insert(s3.begin(),s3.end());
s1.insert(s4.begin(),s4.end());
vs1.insert(vs2.begin(), vs2.end());
vs1.insert(vs3.begin(), vs3.end());
vs1.insert(vs4.begin(), vs4.end());

REQUIRE(s1.size() == 4*target_len + vs1.size());

// szudzik_hash
REQUIRE(emp::szudzik_hash((uint32_t)0, (uint32_t)0) == (uint64_t)0);

REQUIRE(emp::szudzik_hash((uint32_t)0, (uint32_t)1) == (uint64_t)1);
Expand Down