From c8421fd326a10cbbc31ce76e804598929db8b660 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:37:09 +0200 Subject: [PATCH 01/10] Switch std::string -> hashes for label resolution. --- arbor/communication/mpi_context.cpp | 12 ++-- arbor/label_resolution.cpp | 50 +++++++------ arbor/label_resolution.hpp | 19 ++--- test/unit/test_fvm_lowered.cpp | 104 ++++++++++++++++++---------- test/unit/test_label_resolution.cpp | 51 ++++++++------ 5 files changed, 135 insertions(+), 101 deletions(-) diff --git a/arbor/communication/mpi_context.cpp b/arbor/communication/mpi_context.cpp index 6019e76065..c2fcf64af7 100644 --- a/arbor/communication/mpi_context.cpp +++ b/arbor/communication/mpi_context.cpp @@ -59,13 +59,11 @@ struct mpi_context_impl { } cell_label_range gather_cell_label_range(const cell_label_range& local_ranges) const { - std::vector sizes; - std::vector labels; - std::vector ranges; - sizes = mpi::gather_all(local_ranges.sizes(), comm_); - labels = mpi::gather_all(local_ranges.labels(), comm_); - ranges = mpi::gather_all(local_ranges.ranges(), comm_); - return cell_label_range(sizes, labels, ranges); + cell_label_range res; + res.sizes = mpi::gather_all(local_ranges.sizes, comm_); + res.labels = mpi::gather_all(local_ranges.labels, comm_); + res.ranges = mpi::gather_all(local_ranges.ranges, comm_); + return res; } cell_labels_and_gids gather_cell_labels_and_gids(const cell_labels_and_gids& local_labels_and_gids) const { diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index dd928098b6..b143fc6bce 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -17,39 +17,40 @@ namespace arb { cell_label_range::cell_label_range(std::vector size_vec, std::vector label_vec, std::vector range_vec): - sizes_(std::move(size_vec)), labels_(std::move(label_vec)), ranges_(std::move(range_vec)) + sizes(std::move(size_vec)), ranges(std::move(range_vec)) { + std::transform(label_vec.begin(), label_vec.end(), + std::back_inserter(labels), + internal_hash); arb_assert(check_invariant()); }; -void cell_label_range::add_cell() { - sizes_.push_back(0); -} +void cell_label_range::add_cell() { sizes.push_back(0); } void cell_label_range::add_label(cell_tag_type label, lid_range range) { - if (sizes_.empty()) throw arbor_internal_error("adding label to cell_label_range without cell"); - ++sizes_.back(); - labels_.push_back(std::move(label)); - ranges_.push_back(std::move(range)); + if (sizes.empty()) throw arbor_internal_error("adding label to cell_label_range without cell"); + ++sizes.back(); + labels.push_back(internal_hash(label)); + ranges.push_back(std::move(range)); } void cell_label_range::append(cell_label_range other) { using std::make_move_iterator; - sizes_.insert(sizes_.end(), make_move_iterator(other.sizes_.begin()), make_move_iterator(other.sizes_.end())); - labels_.insert(labels_.end(), make_move_iterator(other.labels_.begin()), make_move_iterator(other.labels_.end())); - ranges_.insert(ranges_.end(), make_move_iterator(other.ranges_.begin()), make_move_iterator(other.ranges_.end())); + sizes.insert(sizes.end(), make_move_iterator(other.sizes.begin()), make_move_iterator(other.sizes.end())); + labels.insert(labels.end(), make_move_iterator(other.labels.begin()), make_move_iterator(other.labels.end())); + ranges.insert(ranges.end(), make_move_iterator(other.ranges.begin()), make_move_iterator(other.ranges.end())); } bool cell_label_range::check_invariant() const { - const cell_size_type count = std::accumulate(sizes_.begin(), sizes_.end(), cell_size_type(0)); - return count==labels_.size() && count==ranges_.size(); + const cell_size_type count = std::accumulate(sizes.begin(), sizes.end(), cell_size_type(0)); + return count==labels.size() && count==ranges.size(); } // cell_labels_and_gids methods cell_labels_and_gids::cell_labels_and_gids(cell_label_range lr, std::vector gid): label_range(std::move(lr)), gids(std::move(gid)) { - if (label_range.sizes().size()!=gids.size()) throw arbor_internal_error("cell_label_range and gid count mismatch"); + if (label_range.sizes.size()!=gids.size()) throw arbor_internal_error("cell_label_range and gid count mismatch"); } void cell_labels_and_gids::append(cell_labels_and_gids other) { @@ -58,7 +59,7 @@ void cell_labels_and_gids::append(cell_labels_and_gids other) { } bool cell_labels_and_gids::check_invariant() const { - return label_range.check_invariant() && label_range.sizes().size()==gids.size(); + return label_range.check_invariant() && label_range.sizes.size()==gids.size(); } // label_resolution_map methods @@ -82,34 +83,35 @@ lid_hopefully label_resolution_map::range_set::at(unsigned idx) const { } const label_resolution_map::range_set& label_resolution_map::at(cell_gid_type gid, const cell_tag_type& tag) const { - return map.at(gid).at(tag); + return map.at(gid).at(internal_hash(tag)); } std::size_t label_resolution_map::count(cell_gid_type gid, const cell_tag_type& tag) const { if (!map.count(gid)) return 0u; - return map.at(gid).count(tag); + return map.at(gid).count(internal_hash(tag)); } label_resolution_map::label_resolution_map(const cell_labels_and_gids& clg) { arb_assert(clg.label_range.check_invariant()); const auto& gids = clg.gids; - const auto& labels = clg.label_range.labels(); - const auto& ranges = clg.label_range.ranges(); - const auto& sizes = clg.label_range.sizes(); + const auto& labels = clg.label_range.labels; + const auto& ranges = clg.label_range.ranges; + const auto& sizes = clg.label_range.sizes; std::vector label_divs; auto partn = util::make_partition(label_divs, sizes); for (auto i: util::count_along(partn)) { auto gid = gids[i]; - std::unordered_map m; + std::unordered_map m; for (auto label_idx: util::make_span(partn[i])) { const auto range = ranges[label_idx]; auto size = int(range.end - range.begin); if (size < 0) { throw arb::arbor_internal_error("label_resolution_map: invalid lid_range"); } - auto& range_set = m[labels[label_idx]]; + auto& label = labels[label_idx]; + auto& range_set = m[label]; range_set.ranges.push_back(range); range_set.ranges_partition.push_back(range_set.ranges_partition.back() + size); } @@ -204,10 +206,12 @@ lid_hopefully update_state(resolver::state_variant& v, cell_lid_type resolver::resolve(cell_gid_type gid, const cell_local_label_type& label) { const auto& [tag, pol] = label; + auto hash = internal_hash(tag); + if (!label_map_->count(gid, tag)) throw arb::bad_connection_label(gid, tag, "label does not exist"); const auto& range_set = label_map_->at(gid, tag); - auto& state = state_map_[gid][tag]; + auto& state = state_map_[gid][hash]; // Policy round_robin_halt: use previous state of round_robin policy, if existent if (pol == lid_selection_policy::round_robin_halt diff --git a/arbor/label_resolution.hpp b/arbor/label_resolution.hpp index 9b30a41fa3..d8823cbfe3 100644 --- a/arbor/label_resolution.hpp +++ b/arbor/label_resolution.hpp @@ -9,6 +9,7 @@ #include #include "util/partition.hpp" +#include "util/hash.hpp" namespace arb { @@ -18,8 +19,7 @@ using lid_hopefully = arb::util::expected; // `sizes` is a partitioning vector for associating a cell with a set of // (label, range) pairs in `labels`, `ranges`. // gids of the cells are unknown. -class ARB_ARBOR_API cell_label_range { -public: +struct ARB_ARBOR_API cell_label_range { cell_label_range() = default; cell_label_range(cell_label_range&&) = default; cell_label_range(const cell_label_range&) = default; @@ -36,19 +36,14 @@ class ARB_ARBOR_API cell_label_range { bool check_invariant() const; - const auto& sizes() const { return sizes_; } - const auto& labels() const { return labels_; } - const auto& ranges() const { return ranges_; } - -private: // The number of labels associated with each cell. - std::vector sizes_; + std::vector sizes; // The labels corresponding to each cell, partitioned according to sizes_. - std::vector labels_; + std::vector labels; // The lid_range corresponding to each label. - std::vector ranges_; + std::vector ranges; }; // Struct for associating each cell of `cell_label_range` with a gid. @@ -83,7 +78,7 @@ class ARB_ARBOR_API label_resolution_map { std::size_t count(cell_gid_type gid, const cell_tag_type& tag) const; private: - std::unordered_map> map; + std::unordered_map> map; }; struct ARB_ARBOR_API round_robin_state { @@ -123,6 +118,6 @@ struct ARB_ARBOR_API resolver { state_variant construct_state(lid_selection_policy pol, cell_lid_type state); const label_resolution_map* label_map_; - map>> state_map_; + map>> state_map_; }; } // namespace arb diff --git a/test/unit/test_fvm_lowered.cpp b/test/unit/test_fvm_lowered.cpp index 61837432ff..29a88913a3 100644 --- a/test/unit/test_fvm_lowered.cpp +++ b/test/unit/test_fvm_lowered.cpp @@ -993,94 +993,122 @@ TEST(fvm_lowered, label_data) { { auto clg = cell_labels_and_gids(fvm_info.target_data, gids); std::vector expected_sizes = {2, 0, 0, 2, 0, 0, 2, 0, 0, 2}; - std::vector> expected_labeled_ranges, actual_labeled_ranges; - expected_labeled_ranges = { - {"1_synapse", {4, 5}}, {"4_synapses", {0, 4}}, - {"1_synapse", {4, 5}}, {"4_synapses", {0, 4}}, - {"1_synapse", {4, 5}}, {"4_synapses", {0, 4}}, - {"1_synapse", {4, 5}}, {"4_synapses", {0, 4}} + std::vector> expected_labeled_ranges = { + {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, + {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, + {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, + {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}} }; + std::vector> actual_labeled_ranges; + EXPECT_EQ(clg.gids, gids); - EXPECT_EQ(clg.label_range.sizes(), expected_sizes); - EXPECT_EQ(clg.label_range.labels().size(), expected_labeled_ranges.size()); - EXPECT_EQ(clg.label_range.ranges().size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.sizes, expected_sizes); + EXPECT_EQ(clg.label_range.labels.size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.ranges.size(), expected_labeled_ranges.size()); for (unsigned i = 0; i < expected_labeled_ranges.size(); ++i) { - actual_labeled_ranges.push_back({clg.label_range.labels()[i], clg.label_range.ranges()[i]}); + actual_labeled_ranges.push_back({clg.label_range.labels[i], clg.label_range.ranges[i]}); } std::vector size_partition; auto part = util::make_partition(size_partition, expected_sizes); for (const auto& r: part) { util::sort(util::subrange_view(actual_labeled_ranges, r)); + util::sort(util::subrange_view(expected_labeled_ranges, r)); } EXPECT_EQ(actual_labeled_ranges, expected_labeled_ranges); + + // Check for hash collisions; if we have one, the hash will appear twice in a given range, + // making the set of ids smaller than expected + const auto& labels = clg.label_range.labels; + for (const auto& [beg, end]: part) { + std::unordered_set unique(labels.begin() + beg, labels.begin() + end); + EXPECT_EQ(unique.size(), end - beg); + } } // detectors { auto clg = cell_labels_and_gids(fvm_info.source_data, gids); std::vector expected_sizes = {1, 2, 2, 1, 2, 2, 1, 2, 2, 1}; - std::vector> expected_labeled_ranges, actual_labeled_ranges; - expected_labeled_ranges = { - {"1_detector", {0, 1}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"1_detector", {0, 1}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"1_detector", {0, 1}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"2_detectors", {3, 5}}, {"3_detectors", {0, 3}}, - {"1_detector", {0, 1}} + std::vector> expected_labeled_ranges = { + {internal_hash("1_detector"), {0, 1}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("1_detector"), {0, 1}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("1_detector"), {0, 1}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, + {internal_hash("1_detector"), {0, 1}} }; + std::vector> actual_labeled_ranges; EXPECT_EQ(clg.gids, gids); - EXPECT_EQ(clg.label_range.sizes(), expected_sizes); - EXPECT_EQ(clg.label_range.labels().size(), expected_labeled_ranges.size()); - EXPECT_EQ(clg.label_range.ranges().size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.sizes, expected_sizes); + EXPECT_EQ(clg.label_range.labels.size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.ranges.size(), expected_labeled_ranges.size()); for (unsigned i = 0; i < expected_labeled_ranges.size(); ++i) { - actual_labeled_ranges.push_back({clg.label_range.labels()[i], clg.label_range.ranges()[i]}); + actual_labeled_ranges.push_back({clg.label_range.labels[i], clg.label_range.ranges[i]}); } std::vector size_partition; auto part = util::make_partition(size_partition, expected_sizes); for (const auto& r: part) { util::sort(util::subrange_view(actual_labeled_ranges, r)); + util::sort(util::subrange_view(expected_labeled_ranges, r)); } EXPECT_EQ(actual_labeled_ranges, expected_labeled_ranges); + + // Check for hash collisions; if we have one, the hash will appear twice in a given range, + // making the set of ids smaller than expected + const auto& labels = clg.label_range.labels; + for (const auto& [beg, end]: part) { + std::unordered_set unique(labels.begin() + beg, labels.begin() + end); + EXPECT_EQ(unique.size(), end - beg); + } } // gap_junctions { auto clg = cell_labels_and_gids(fvm_info.gap_junction_data, gids); std::vector expected_sizes = {0, 2, 2, 0, 2, 2, 0, 2, 2, 0}; - std::vector> expected_labeled_ranges, actual_labeled_ranges; - expected_labeled_ranges = { - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, - {"1_gap_junction", {2, 3}}, {"2_gap_junctions", {0, 2}}, + std::vector> expected_labeled_ranges = { + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, }; EXPECT_EQ(clg.gids, gids); - EXPECT_EQ(clg.label_range.sizes(), expected_sizes); - EXPECT_EQ(clg.label_range.labels().size(), expected_labeled_ranges.size()); - EXPECT_EQ(clg.label_range.ranges().size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.sizes, expected_sizes); + EXPECT_EQ(clg.label_range.labels.size(), expected_labeled_ranges.size()); + EXPECT_EQ(clg.label_range.ranges.size(), expected_labeled_ranges.size()); + std::vector> actual_labeled_ranges; for (unsigned i = 0; i < expected_labeled_ranges.size(); ++i) { - actual_labeled_ranges.push_back({clg.label_range.labels()[i], clg.label_range.ranges()[i]}); + actual_labeled_ranges.push_back({clg.label_range.labels[i], clg.label_range.ranges[i]}); } std::vector size_partition; auto part = util::make_partition(size_partition, expected_sizes); for (const auto& r: part) { util::sort(util::subrange_view(actual_labeled_ranges, r)); + util::sort(util::subrange_view(expected_labeled_ranges, r)); } EXPECT_EQ(actual_labeled_ranges, expected_labeled_ranges); + + // Check for hash collisions; if we have one, the hash will appear twice in a given range, + // making the set of ids smaller than expected + const auto& labels = clg.label_range.labels; + for (const auto& [beg, end]: part) { + std::unordered_set unique(labels.begin() + beg, labels.begin() + end); + EXPECT_EQ(unique.size(), end - beg); + } } } diff --git a/test/unit/test_label_resolution.cpp b/test/unit/test_label_resolution.cpp index 75adfbdae2..450428a743 100644 --- a/test/unit/test_label_resolution.cpp +++ b/test/unit/test_label_resolution.cpp @@ -8,6 +8,14 @@ using namespace arb; +std::vector make_labels(const std::vector& ls) { + std::vector res; + std::transform(ls.begin(), ls.end(), + std::back_inserter(res), + internal_hash); + return res; +} + TEST(test_cell_label_range, build) { using ivec = std::vector; using svec = std::vector; @@ -16,18 +24,18 @@ TEST(test_cell_label_range, build) { // Test add_cell and add_label auto b0 = cell_label_range(); EXPECT_THROW(b0.add_label("l0", {0u, 1u}), arb::arbor_internal_error); - EXPECT_TRUE(b0.sizes().empty()); - EXPECT_TRUE(b0.labels().empty()); - EXPECT_TRUE(b0.ranges().empty()); + EXPECT_TRUE(b0.sizes.empty()); + EXPECT_TRUE(b0.labels.empty()); + EXPECT_TRUE(b0.ranges.empty()); EXPECT_TRUE(b0.check_invariant()); auto b1 = cell_label_range(); b1.add_cell(); b1.add_cell(); b1.add_cell(); - EXPECT_EQ((ivec{0u, 0u, 0u}), b1.sizes()); - EXPECT_TRUE(b1.labels().empty()); - EXPECT_TRUE(b1.ranges().empty()); + EXPECT_EQ((ivec{0u, 0u, 0u}), b1.sizes); + EXPECT_TRUE(b1.labels.empty()); + EXPECT_TRUE(b1.ranges.empty()); EXPECT_TRUE(b1.check_invariant()); auto b2 = cell_label_range(); @@ -42,9 +50,9 @@ TEST(test_cell_label_range, build) { b2.add_label("l4", {7u, 2u}); b2.add_label("l4", {7u, 2u}); b2.add_label("l2", {7u, 2u}); - EXPECT_EQ((ivec{3u, 0u, 5u}), b2.sizes()); - EXPECT_EQ((svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b2.labels()); - EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b2.ranges()); + EXPECT_EQ((ivec{3u, 0u, 5u}), b2.sizes); + EXPECT_EQ(make_labels(svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b2.labels); + EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b2.ranges); EXPECT_TRUE(b2.check_invariant()); auto b3 = cell_label_range(); @@ -52,28 +60,29 @@ TEST(test_cell_label_range, build) { b3.add_label("r0", {0u, 9u}); b3.add_label("r1", {10u, 10u}); b3.add_cell(); - EXPECT_EQ((ivec{2u, 0u}), b3.sizes()); - EXPECT_EQ((svec{"r0", "r1"}), b3.labels()); - EXPECT_EQ((lvec{{0u, 9u}, {10u, 10u}}), b3.ranges()); + EXPECT_EQ((ivec{2u, 0u}), b3.sizes); + EXPECT_EQ(make_labels + (svec{"r0", "r1"}), b3.labels); + EXPECT_EQ((lvec{{0u, 9u}, {10u, 10u}}), b3.ranges); EXPECT_TRUE(b3.check_invariant()); // Test appending b0.append(b1); - EXPECT_EQ((ivec{0u, 0u, 0u}), b0.sizes()); - EXPECT_TRUE(b0.labels().empty()); - EXPECT_TRUE(b0.ranges().empty()); + EXPECT_EQ((ivec{0u, 0u, 0u}), b0.sizes); + EXPECT_TRUE(b0.labels.empty()); + EXPECT_TRUE(b0.ranges.empty()); EXPECT_TRUE(b0.check_invariant()); b0.append(b2); - EXPECT_EQ((ivec{0u, 0u, 0u, 3u, 0u, 5u}), b0.sizes()); - EXPECT_EQ((svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b0.labels()); - EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b0.ranges()); + EXPECT_EQ((ivec{0u, 0u, 0u, 3u, 0u, 5u}), b0.sizes); + EXPECT_EQ(make_labels(svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b0.labels); + EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b0.ranges); EXPECT_TRUE(b0.check_invariant()); b0.append(b3); - EXPECT_EQ((ivec{0u, 0u, 0u, 3u, 0u, 5u, 2u, 0u}), b0.sizes()); - EXPECT_EQ((svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2", "r0", "r1"}), b0.labels()); - EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}, {0u, 9u}, {10u, 10u}}), b0.ranges()); + EXPECT_EQ((ivec{0u, 0u, 0u, 3u, 0u, 5u, 2u, 0u}), b0.sizes); + EXPECT_EQ(make_labels(svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2", "r0", "r1"}), b0.labels); + EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}, {0u, 9u}, {10u, 10u}}), b0.ranges); EXPECT_TRUE(b0.check_invariant()); } From d13a5b1ea7f8df4b1684ef7cddab5322be5c4214 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:16:01 +0200 Subject: [PATCH 02/10] Invariant checks for hash collisions. --- arbor/fvm_lowered_cell_impl.hpp | 4 ++++ arbor/label_resolution.cpp | 12 +++++++++++ arbor/util/hash.hpp | 35 +++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 arbor/util/hash.hpp diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index 6905889510..fc10d6ff36 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -370,6 +370,10 @@ fvm_initialization_data fvm_lowered_cell_impl::initialize( } } + if (!fvm_info.target_data.check_invariant()) throw arbor_internal_error{"Building cell target data resulted in invalid state."}; + if (!fvm_info.source_data.check_invariant()) throw arbor_internal_error{"Building cell source data resulted in invalid state."}; + if (!fvm_info.gap_junction_data.check_invariant()) throw arbor_internal_error{"Building cell gj data resulted in invalid state."}; + cable_cell_global_properties global_props; try { std::any rec_props = rec.get_global_properties(cell_kind::cable); diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index b143fc6bce..aaf974c2cf 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -43,6 +44,17 @@ void cell_label_range::append(cell_label_range other) { bool cell_label_range::check_invariant() const { const cell_size_type count = std::accumulate(sizes.begin(), sizes.end(), cell_size_type(0)); + size_t beg = 0; + for (auto size: sizes) { + size_t end = beg + size; + std::unordered_set seen; + for (auto idx = beg; idx < end; ++idx) { + auto hash = labels[idx]; + if (seen.count(hash)) return false; + seen.insert(hash); + } + beg = end; + } return count==labels.size() && count==ranges.size(); } diff --git a/arbor/util/hash.hpp b/arbor/util/hash.hpp new file mode 100644 index 0000000000..416cde1a84 --- /dev/null +++ b/arbor/util/hash.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace arb { +using hash_type = uint64_t; + +// Non-cryptographic hash function for mapping strings to internal +// identifiers. Concretely, FNV-1a hash function taken from +// +// http://www.isthe.com/chongo/tech/comp/fnv/index.html +// +// NOTE: It may be worth it considering different hash functions in +// the future that have better characteristic, xxHash or Murmur +// look interesting but are more complex and likely require adding +// external dependencies. +// NOTE: this is the obligatory comment on a better hash function +// that will be here until the end of time. + +constexpr hash_type offset_basis = 0xcbf29ce484222325; +constexpr hash_type prime = 0x100000001b3; + +constexpr hash_type internal_hash(std::string_view data) { + hash_type hash = offset_basis; + + for (uint8_t byte: data) { + hash = hash ^ byte; + hash = hash * prime; + } + + return hash; +} + +} From ee037fc4f374215f1cfb1de115229274ad3f455f Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:58:22 +0200 Subject: [PATCH 03/10] Account for same keys on cell label range. --- arbor/fvm_lowered_cell_impl.hpp | 52 ++++++++++++++------------------- arbor/label_resolution.cpp | 13 +-------- 2 files changed, 23 insertions(+), 42 deletions(-) diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index fc10d6ff36..70fccf07ea 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -312,11 +312,26 @@ fvm_detector_info get_detector_info(arb_size_type max, return { max, std::move(cv), std::move(threshold), ctx }; } +inline cell_size_type +add_labels(cell_label_range& clr, const std::unordered_multimap& ranges) { + clr.add_cell(); + cell_size_type count = 0; + std::unordered_map hashes; + for (const auto& [label, range]: ranges) { + auto hash = internal_hash(label); + if (hashes.count(hash) && hashes.at(hash) != label) { + auto err = util::strprintf("Hash collision {} ~ {} = {}", label, hashes.at(hash), hash); + throw arbor_internal_error{err}; + } + clr.add_label(label, range); + count += (range.end - range.begin); + } + return count; +} + template -fvm_initialization_data fvm_lowered_cell_impl::initialize( - const std::vector& gids, - const recipe& rec) -{ +fvm_initialization_data fvm_lowered_cell_impl::initialize(const std::vector& gids, + const recipe& rec) { using std::any_cast; using util::count_along; using util::make_span; @@ -346,34 +361,11 @@ fvm_initialization_data fvm_lowered_cell_impl::initialize( for (auto i : util::make_span(ncell)) { auto gid = gids[i]; const auto& c = cells[i]; - - fvm_info.source_data.add_cell(); - fvm_info.target_data.add_cell(); - fvm_info.gap_junction_data.add_cell(); - - unsigned count = 0; - for (const auto& [label, range]: c.detector_ranges()) { - fvm_info.source_data.add_label(label, range); - count+=(range.end - range.begin); - } - fvm_info.num_sources[gid] = count; - - count = 0; - for (const auto& [label, range]: c.synapse_ranges()) { - fvm_info.target_data.add_label(label, range); - count+=(range.end - range.begin); - } - fvm_info.num_targets[gid] = count; - - for (const auto& [label, range]: c.junction_ranges()) { - fvm_info.gap_junction_data.add_label(label, range); - } + fvm_info.num_sources[gid] = add_labels(fvm_info.source_data, c.detector_ranges()); + fvm_info.num_targets[gid] = add_labels(fvm_info.target_data, c.synapse_ranges()); + add_labels(fvm_info.gap_junction_data, c.junction_ranges()); } - if (!fvm_info.target_data.check_invariant()) throw arbor_internal_error{"Building cell target data resulted in invalid state."}; - if (!fvm_info.source_data.check_invariant()) throw arbor_internal_error{"Building cell source data resulted in invalid state."}; - if (!fvm_info.gap_junction_data.check_invariant()) throw arbor_internal_error{"Building cell gj data resulted in invalid state."}; - cable_cell_global_properties global_props; try { std::any rec_props = rec.get_global_properties(cell_kind::cable); diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index aaf974c2cf..69c3b6b57f 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -37,24 +37,13 @@ void cell_label_range::add_label(cell_tag_type label, lid_range range) { void cell_label_range::append(cell_label_range other) { using std::make_move_iterator; - sizes.insert(sizes.end(), make_move_iterator(other.sizes.begin()), make_move_iterator(other.sizes.end())); + sizes.insert(sizes.end(), make_move_iterator(other.sizes.begin()), make_move_iterator(other.sizes.end())); labels.insert(labels.end(), make_move_iterator(other.labels.begin()), make_move_iterator(other.labels.end())); ranges.insert(ranges.end(), make_move_iterator(other.ranges.begin()), make_move_iterator(other.ranges.end())); } bool cell_label_range::check_invariant() const { const cell_size_type count = std::accumulate(sizes.begin(), sizes.end(), cell_size_type(0)); - size_t beg = 0; - for (auto size: sizes) { - size_t end = beg + size; - std::unordered_set seen; - for (auto idx = beg; idx < end; ++idx) { - auto hash = labels[idx]; - if (seen.count(hash)) return false; - seen.insert(hash); - } - beg = end; - } return count==labels.size() && count==ranges.size(); } From f008f72420c8daeac15e7a6f9d85847df9966a1c Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 12 Sep 2023 14:18:21 +0200 Subject: [PATCH 04/10] Push hashes up into decor. --- arbor/benchmark_cell_group.cpp | 4 ++-- arbor/cable_cell.cpp | 18 +++++++++++------ arbor/cable_cell_param.cpp | 9 ++++++++- arbor/fvm_lowered_cell_impl.hpp | 7 +------ arbor/include/arbor/cable_cell.hpp | 10 +++++----- arbor/include/arbor/cable_cell_param.hpp | 5 ++++- arbor/include/arbor/common_types.hpp | 4 ++++ arbor/include/arbor/cv_policy.hpp | 2 +- arbor/label_resolution.cpp | 13 ++++++++++-- arbor/label_resolution.hpp | 3 ++- arbor/lif_cell_group.cpp | 4 ++-- arbor/spike_source_cell_group.cpp | 2 +- arbor/util/hash.hpp | 4 ++-- arborio/cableio.cpp | 12 +++++++----- test/unit/test_cable_cell.cpp | 25 ++++++++++++------------ test/unit/test_label_resolution.cpp | 22 ++++++++++----------- 16 files changed, 86 insertions(+), 58 deletions(-) diff --git a/arbor/benchmark_cell_group.cpp b/arbor/benchmark_cell_group.cpp index bdcb1789a6..d2ac067182 100644 --- a/arbor/benchmark_cell_group.cpp +++ b/arbor/benchmark_cell_group.cpp @@ -40,8 +40,8 @@ benchmark_cell_group::benchmark_cell_group(const std::vector& gid for (const auto& c: cells_) { cg_sources.add_cell(); cg_targets.add_cell(); - cg_sources.add_label(c.source, {0, 1}); - cg_targets.add_label(c.target, {0, 1}); + cg_sources.add_label(internal_hash(c.source), {0, 1}); + cg_targets.add_label(internal_hash(c.target), {0, 1}); } benchmark_cell_group::reset(); diff --git a/arbor/cable_cell.cpp b/arbor/cable_cell.cpp index 3afbc82400..210fdd3cea 100644 --- a/arbor/cable_cell.cpp +++ b/arbor/cable_cell.cpp @@ -88,7 +88,7 @@ struct cable_cell_impl { decor decorations; // The placeable label to lid_range map - dynamic_typed_map>::type> labeled_lid_ranges; + dynamic_typed_map>::type> labeled_lid_ranges; cable_cell_impl(const arb::morphology& m, const label_dict& labels, const decor& decorations): provider(m, labels), @@ -120,7 +120,7 @@ struct cable_cell_impl { } template - void place(const locset& ls, const Item& item, const cell_tag_type& label) { + void place(const locset& ls, const Item& item, const hash_type& label) { auto& mm = get_location_map(item); cell_lid_type& lid = placed_count.get(); cell_lid_type first = lid; @@ -226,7 +226,8 @@ void cable_cell_impl::init(const decor& d) { for (const auto& p: d.placements()) { auto& where = std::get<0>(p); auto& label = std::get<2>(p); - std::visit([this, &where, &label] (auto&& what) {return this->place(where, what, label);}, std::get<1>(p)); + std::visit([this, &where, &label] (auto&& what) {return this->place(where, what, label); }, + std::get<1>(p)); } } @@ -280,16 +281,21 @@ const cable_cell_parameter_set& cable_cell::default_parameters() const { return impl_->decorations.defaults(); } -const std::unordered_multimap& cable_cell::detector_ranges() const { +const cable_cell::lid_range_map& cable_cell::detector_ranges() const { return impl_->labeled_lid_ranges.get(); } -const std::unordered_multimap& cable_cell::synapse_ranges() const { +const cable_cell::lid_range_map& cable_cell::synapse_ranges() const { return impl_->labeled_lid_ranges.get(); } -const std::unordered_multimap& cable_cell::junction_ranges() const { +const cable_cell::lid_range_map& cable_cell::junction_ranges() const { return impl_->labeled_lid_ranges.get(); } +cell_tag_type decor::tag_of(hash_type hash) const { + if (!hashes_.count(hash)) throw arbor_internal_error{util::pprintf("Unknown hash for {}.", std::to_string(hash))}; + return hashes_.at(hash); +} + } // namespace arb diff --git a/arbor/cable_cell_param.cpp b/arbor/cable_cell_param.cpp index 909ec7faba..55c4cdd079 100644 --- a/arbor/cable_cell_param.cpp +++ b/arbor/cable_cell_param.cpp @@ -10,7 +10,9 @@ #include #include +#include "util/hash.hpp" #include "util/maputil.hpp" +#include "util/strprintf.hpp" namespace arb { @@ -120,7 +122,12 @@ decor& decor::paint(region where, paintable what) { } decor& decor::place(locset where, placeable what, cell_tag_type label) { - placements_.emplace_back(std::move(where), std::move(what), std::move(label)); + auto hash = internal_hash(label); + if (hashes_.count(hash) && hashes_.at(hash) != label) { + throw arbor_internal_error{util::strprintf("Hash collision {} ./. {}", label, hashes_.at(hash))}; + } + placements_.emplace_back(std::move(where), std::move(what), hash); + hashes_.emplace(hash, label); return *this; } diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index 70fccf07ea..5206635229 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -313,16 +313,11 @@ fvm_detector_info get_detector_info(arb_size_type max, } inline cell_size_type -add_labels(cell_label_range& clr, const std::unordered_multimap& ranges) { +add_labels(cell_label_range& clr, const cable_cell::lid_range_map& ranges) { clr.add_cell(); cell_size_type count = 0; std::unordered_map hashes; for (const auto& [label, range]: ranges) { - auto hash = internal_hash(label); - if (hashes.count(hash) && hashes.at(hash) != label) { - auto err = util::strprintf("Hash collision {} ~ {} = {}", label, hashes.at(hash), hash); - throw arbor_internal_error{err}; - } clr.add_label(label, range); count += (range.end - range.begin); } diff --git a/arbor/include/arbor/cable_cell.hpp b/arbor/include/arbor/cable_cell.hpp index 221c967d14..e119508a49 100644 --- a/arbor/include/arbor/cable_cell.hpp +++ b/arbor/include/arbor/cable_cell.hpp @@ -246,8 +246,8 @@ using cable_cell_location_map = static_typed_map; // High-level abstract representation of a cell. -class ARB_SYMBOL_VISIBLE cable_cell { -public: +struct ARB_SYMBOL_VISIBLE cable_cell { + using lid_range_map = std::unordered_multimap; using index_type = cell_lid_type; using size_type = cell_local_size_type; using value_type = double; @@ -311,9 +311,9 @@ class ARB_SYMBOL_VISIBLE cable_cell { const cable_cell_parameter_set& default_parameters() const; // The labeled lid_ranges of sources, targets and gap_junctions on the cell; - const std::unordered_multimap& detector_ranges() const; - const std::unordered_multimap& synapse_ranges() const; - const std::unordered_multimap& junction_ranges() const; + const lid_range_map& detector_ranges() const; + const lid_range_map& synapse_ranges() const; + const lid_range_map& junction_ranges() const; private: std::unique_ptr impl_; diff --git a/arbor/include/arbor/cable_cell_param.hpp b/arbor/include/arbor/cable_cell_param.hpp index 46ed13e152..62ed0532ed 100644 --- a/arbor/include/arbor/cable_cell_param.hpp +++ b/arbor/include/arbor/cable_cell_param.hpp @@ -313,8 +313,9 @@ struct ARB_ARBOR_API cable_cell_parameter_set { // are to be applied to a morphology in a cable_cell. class ARB_ARBOR_API decor { std::vector> paintings_; - std::vector> placements_; + std::vector> placements_; cable_cell_parameter_set defaults_; + std::unordered_map hashes_; public: const auto& paintings() const {return paintings_; } @@ -324,6 +325,8 @@ class ARB_ARBOR_API decor { decor& paint(region, paintable); decor& place(locset, placeable, cell_tag_type); decor& set_default(defaultable); + + cell_tag_type tag_of(hash_type) const; }; ARB_ARBOR_API extern cable_cell_parameter_set neuron_parameter_defaults; diff --git a/arbor/include/arbor/common_types.hpp b/arbor/include/arbor/common_types.hpp index 34a4b2dddd..1d5fa262e8 100644 --- a/arbor/include/arbor/common_types.hpp +++ b/arbor/include/arbor/common_types.hpp @@ -19,6 +19,10 @@ namespace arb { +// Internal hashes use this 64bit id + +using hash_type = std::uint64_t; + // For identifying cells globally. using cell_gid_type = std::uint32_t; diff --git a/arbor/include/arbor/cv_policy.hpp b/arbor/include/arbor/cv_policy.hpp index a1a5077cf1..a56a5c51d9 100644 --- a/arbor/include/arbor/cv_policy.hpp +++ b/arbor/include/arbor/cv_policy.hpp @@ -59,7 +59,7 @@ namespace arb { -class cable_cell; +struct cable_cell; struct cv_policy_base { virtual locset cv_boundary_points(const cable_cell& cell) const = 0; diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index 69c3b6b57f..5506a79e6c 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -26,12 +26,21 @@ cell_label_range::cell_label_range(std::vector size_vec, arb_assert(check_invariant()); }; +cell_label_range::cell_label_range(std::vector size_vec, + std::vector label_vec, + std::vector range_vec): + sizes(std::move(size_vec)), labels(std::move(label_vec)), ranges(std::move(range_vec)) +{ + arb_assert(check_invariant()); +}; + + void cell_label_range::add_cell() { sizes.push_back(0); } -void cell_label_range::add_label(cell_tag_type label, lid_range range) { +void cell_label_range::add_label(hash_type label, lid_range range) { if (sizes.empty()) throw arbor_internal_error("adding label to cell_label_range without cell"); ++sizes.back(); - labels.push_back(internal_hash(label)); + labels.push_back(label); ranges.push_back(std::move(range)); } diff --git a/arbor/label_resolution.hpp b/arbor/label_resolution.hpp index d8823cbfe3..92d0270fe1 100644 --- a/arbor/label_resolution.hpp +++ b/arbor/label_resolution.hpp @@ -27,10 +27,11 @@ struct ARB_ARBOR_API cell_label_range { cell_label_range& operator=(cell_label_range&&) = default; cell_label_range(std::vector size_vec, std::vector label_vec, std::vector range_vec); + cell_label_range(std::vector size_vec, std::vector label_vec, std::vector range_vec); void add_cell(); - void add_label(cell_tag_type label, lid_range range); + void add_label(hash_type label, lid_range range); void append(cell_label_range other); diff --git a/arbor/lif_cell_group.cpp b/arbor/lif_cell_group.cpp index e655744483..ee4e881673 100644 --- a/arbor/lif_cell_group.cpp +++ b/arbor/lif_cell_group.cpp @@ -26,8 +26,8 @@ lif_cell_group::lif_cell_group(const std::vector& gids, // tell our caller about this cell's connections cg_sources.add_cell(); cg_targets.add_cell(); - cg_sources.add_label(cell.source, {0, 1}); - cg_targets.add_label(cell.target, {0, 1}); + cg_sources.add_label(internal_hash(cell.source), {0, 1}); + cg_targets.add_label(internal_hash(cell.target), {0, 1}); // insert probes where needed auto probes = rec.get_probes(gid); for (const auto lid: util::count_along(probes)) { diff --git a/arbor/spike_source_cell_group.cpp b/arbor/spike_source_cell_group.cpp index 92ea2799b7..41bc9705c0 100644 --- a/arbor/spike_source_cell_group.cpp +++ b/arbor/spike_source_cell_group.cpp @@ -33,7 +33,7 @@ spike_source_cell_group::spike_source_cell_group( try { auto cell = util::any_cast(rec.get_cell_description(gid)); time_sequences_.emplace_back(cell.seqs); - cg_sources.add_label(cell.source, {0, 1}); + cg_sources.add_label(internal_hash(cell.source), {0, 1}); } catch (std::bad_any_cast& e) { throw bad_cell_description(cell_kind::spike_source, gid); diff --git a/arbor/util/hash.hpp b/arbor/util/hash.hpp index 416cde1a84..988fec2a12 100644 --- a/arbor/util/hash.hpp +++ b/arbor/util/hash.hpp @@ -3,9 +3,9 @@ #include #include -namespace arb { -using hash_type = uint64_t; +#include +namespace arb { // Non-cryptographic hash function for mapping strings to internal // identifiers. Concretely, FNV-1a hash function taken from // diff --git a/arborio/cableio.cpp b/arborio/cableio.cpp index 2a15455e79..b0383b74a9 100644 --- a/arborio/cableio.cpp +++ b/arborio/cableio.cpp @@ -135,8 +135,10 @@ s_expr mksexp(const decor& d) { { return slist("paint"_symbol, round_trip(p.first), mksexp(x)); }, p.second)); } for (const auto& p: d.placements()) { - decorations.push_back(std::visit([&](auto& x) - { return slist("place"_symbol, round_trip(std::get<0>(p)), mksexp(x), s_expr(std::get<2>(p))); }, std::get<1>(p))); + decorations.push_back(std::visit([&](auto& x) { + auto lbl = d.tag_of(std::get<2>(p)); + return slist("place"_symbol, round_trip(std::get<0>(p)), mksexp(x), s_expr(lbl)); + }, std::get<1>(p))); } return {"decor"_symbol, slist_range(decorations)}; } @@ -282,9 +284,9 @@ decor make_decor(const std::vector(p), std::get<1>(p), std::get<2>(p)); }, - [&](const paint_pair & p) { d.paint(p.first, p.second); }, - [&](const defaultable & p){ d.set_default(p); }); + [&](const place_tuple& p) { d.place(std::get<0>(p), std::get<1>(p), std::get<2>(p)); }, + [&](const paint_pair& p) { d.paint(p.first, p.second); }, + [&](const defaultable& p){ d.set_default(p); }); std::visit(decor_visitor, a); } return d; diff --git a/test/unit/test_cable_cell.cpp b/test/unit/test_cable_cell.cpp index 1e59691bd2..c1066e9827 100644 --- a/test/unit/test_cable_cell.cpp +++ b/test/unit/test_cable_cell.cpp @@ -1,5 +1,6 @@ #include #include "../common_cells.hpp" +#include "util/hash.hpp" #include #include @@ -45,20 +46,20 @@ TEST(cable_cell, lid_ranges) { const auto& src_ranges = cell.detector_ranges(); const auto& tgt_ranges = cell.synapse_ranges(); - EXPECT_EQ(1u, tgt_ranges.count("t0")); - EXPECT_EQ(1u, tgt_ranges.count("t1")); - EXPECT_EQ(1u, src_ranges.count("s0")); - EXPECT_EQ(1u, tgt_ranges.count("t2")); - EXPECT_EQ(1u, src_ranges.count("s1")); - EXPECT_EQ(2u, tgt_ranges.count("t3")); + EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t0"))); + EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t1"))); + EXPECT_EQ(1u, src_ranges.count(internal_hash("s0"))); + EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t2"))); + EXPECT_EQ(1u, src_ranges.count(internal_hash("s1"))); + EXPECT_EQ(2u, tgt_ranges.count(internal_hash("t3"))); - auto r1 = tgt_ranges.equal_range("t0").first->second; - auto r2 = tgt_ranges.equal_range("t1").first->second; - auto r3 = src_ranges.equal_range("s0").first->second; - auto r4 = tgt_ranges.equal_range("t2").first->second; - auto r5 = src_ranges.equal_range("s1").first->second; + auto r1 = tgt_ranges.equal_range(internal_hash("t0")).first->second; + auto r2 = tgt_ranges.equal_range(internal_hash("t1")).first->second; + auto r3 = src_ranges.equal_range(internal_hash("s0")).first->second; + auto r4 = tgt_ranges.equal_range(internal_hash("t2")).first->second; + auto r5 = src_ranges.equal_range(internal_hash("s1")).first->second; - auto r6_range = tgt_ranges.equal_range("t3"); + auto r6_range = tgt_ranges.equal_range(internal_hash("t3")); auto r6_0 = r6_range.first; auto r6_1 = std::next(r6_range.first); if (r6_0->second.begin != 4u) { diff --git a/test/unit/test_label_resolution.cpp b/test/unit/test_label_resolution.cpp index 450428a743..2dacbdd607 100644 --- a/test/unit/test_label_resolution.cpp +++ b/test/unit/test_label_resolution.cpp @@ -23,7 +23,7 @@ TEST(test_cell_label_range, build) { // Test add_cell and add_label auto b0 = cell_label_range(); - EXPECT_THROW(b0.add_label("l0", {0u, 1u}), arb::arbor_internal_error); + EXPECT_THROW(b0.add_label(internal_hash("l0"), {0u, 1u}), arb::arbor_internal_error); EXPECT_TRUE(b0.sizes.empty()); EXPECT_TRUE(b0.labels.empty()); EXPECT_TRUE(b0.ranges.empty()); @@ -40,16 +40,16 @@ TEST(test_cell_label_range, build) { auto b2 = cell_label_range(); b2.add_cell(); - b2.add_label("l0", {0u, 1u}); - b2.add_label("l0", {3u, 13u}); - b2.add_label("l1", {0u, 5u}); + b2.add_label(internal_hash("l0"), {0u, 1u}); + b2.add_label(internal_hash("l0"), {3u, 13u}); + b2.add_label(internal_hash("l1"), {0u, 5u}); b2.add_cell(); b2.add_cell(); - b2.add_label("l2", {6u, 8u}); - b2.add_label("l3", {1u, 0u}); - b2.add_label("l4", {7u, 2u}); - b2.add_label("l4", {7u, 2u}); - b2.add_label("l2", {7u, 2u}); + b2.add_label(internal_hash("l2"), {6u, 8u}); + b2.add_label(internal_hash("l3"), {1u, 0u}); + b2.add_label(internal_hash("l4"), {7u, 2u}); + b2.add_label(internal_hash("l4"), {7u, 2u}); + b2.add_label(internal_hash("l2"), {7u, 2u}); EXPECT_EQ((ivec{3u, 0u, 5u}), b2.sizes); EXPECT_EQ(make_labels(svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b2.labels); EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b2.ranges); @@ -57,8 +57,8 @@ TEST(test_cell_label_range, build) { auto b3 = cell_label_range(); b3.add_cell(); - b3.add_label("r0", {0u, 9u}); - b3.add_label("r1", {10u, 10u}); + b3.add_label(internal_hash("r0"), {0u, 9u}); + b3.add_label(internal_hash("r1"), {10u, 10u}); b3.add_cell(); EXPECT_EQ((ivec{2u, 0u}), b3.sizes); EXPECT_EQ(make_labels From d8546fc6003629bcf6b961883fd3be2ec94c152a Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 12 Sep 2023 16:40:49 +0200 Subject: [PATCH 05/10] Map back to labels. --- python/cells.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/cells.cpp b/python/cells.cpp index f46bcf8aaf..c1c446b53c 100644 --- a/python/cells.cpp +++ b/python/cells.cpp @@ -829,7 +829,7 @@ void register_cells(pybind11::module& m) { [](arb::decor& dec) { std::vector> result; for (const auto& [k, v, t]: dec.placements()) { - result.emplace_back(to_string(k), v, t); + result.emplace_back(to_string(k), v, dec.tag_of(t)); } return result; }, From cf2a5f89e33be74bf4ce993ff1fd27dc3da3a7f5 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Tue, 17 Oct 2023 20:59:38 +0200 Subject: [PATCH 06/10] Add internal_hash to hash_def and integrate w/ hash_value. --- arbor/cable_cell_param.cpp | 2 +- arbor/include/arbor/common_types.hpp | 2 +- arbor/include/arbor/util/hash_def.hpp | 38 ++++++++++++++++++++++++--- arbor/label_resolution.cpp | 6 ++--- arbor/label_resolution.hpp | 2 +- arbor/util/hash.hpp | 35 ------------------------ test/unit/test_cable_cell.cpp | 2 +- test/unit/test_label_resolution.cpp | 2 +- 8 files changed, 42 insertions(+), 47 deletions(-) delete mode 100644 arbor/util/hash.hpp diff --git a/arbor/cable_cell_param.cpp b/arbor/cable_cell_param.cpp index 55c4cdd079..6f47a0cca8 100644 --- a/arbor/cable_cell_param.cpp +++ b/arbor/cable_cell_param.cpp @@ -10,7 +10,7 @@ #include #include -#include "util/hash.hpp" +#include #include "util/maputil.hpp" #include "util/strprintf.hpp" diff --git a/arbor/include/arbor/common_types.hpp b/arbor/include/arbor/common_types.hpp index 1d5fa262e8..529f700a3a 100644 --- a/arbor/include/arbor/common_types.hpp +++ b/arbor/include/arbor/common_types.hpp @@ -21,7 +21,7 @@ namespace arb { // Internal hashes use this 64bit id -using hash_type = std::uint64_t; +using hash_type = std::size_t; // For identifying cells globally. diff --git a/arbor/include/arbor/util/hash_def.hpp b/arbor/include/arbor/util/hash_def.hpp index fc6770cc41..304fe4c58d 100644 --- a/arbor/include/arbor/util/hash_def.hpp +++ b/arbor/include/arbor/util/hash_def.hpp @@ -17,16 +17,46 @@ */ #include -#include +#include // Helpers for forming hash values of compounds objects. namespace arb { -inline std::size_t hash_value_combine(std::size_t n) { - return n; +// Non-cryptographic hash function for mapping strings to internal +// identifiers. Concretely, FNV-1a hash function taken from +// +// http://www.isthe.com/chongo/tech/comp/fnv/index.html +// +// NOTE: It may be worth it considering different hash functions in +// the future that have better characteristic, xxHash or Murmur +// look interesting but are more complex and likely require adding +// external dependencies. +// NOTE: this is the obligatory comment on a better hash function +// that will be here until the end of time. + +template +inline constexpr std::size_t internal_hash(T&& data) { + if constexpr (std::is_convertible_v) { + constexpr std::size_t prime = 0x100000001b3; + constexpr std::size_t offset_basis=0xcbf29ce484222325; + + std::size_t hash = offset_basis; + + for (uint8_t byte: std::string_view{data}) { + hash = hash ^ byte; + hash = hash * prime; + } + + return hash; + } else { + return std::hash>{}(data); + } } +inline +std::size_t hash_value_combine(std::size_t n) { return n; } + template std::size_t hash_value_combine(std::size_t n, std::size_t m, T... tail) { constexpr std::size_t prime2 = 54517; @@ -36,7 +66,7 @@ std::size_t hash_value_combine(std::size_t n, std::size_t m, T... tail) { template std::size_t hash_value(const T&... t) { constexpr std::size_t prime1 = 93481; - return hash_value_combine(prime1, std::hash{}(t)...); + return hash_value_combine(prime1, internal_hash(t)...); } } diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index 5506a79e6c..14786144f2 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -1,15 +1,15 @@ #include #include -#include +#include #include #include #include #include +#include #include "label_resolution.hpp" #include "util/partition.hpp" -#include "util/rangeutil.hpp" #include "util/span.hpp" namespace arb { @@ -22,7 +22,7 @@ cell_label_range::cell_label_range(std::vector size_vec, { std::transform(label_vec.begin(), label_vec.end(), std::back_inserter(labels), - internal_hash); + internal_hash); arb_assert(check_invariant()); }; diff --git a/arbor/label_resolution.hpp b/arbor/label_resolution.hpp index 92d0270fe1..508c9817e9 100644 --- a/arbor/label_resolution.hpp +++ b/arbor/label_resolution.hpp @@ -9,7 +9,7 @@ #include #include "util/partition.hpp" -#include "util/hash.hpp" +#include namespace arb { diff --git a/arbor/util/hash.hpp b/arbor/util/hash.hpp deleted file mode 100644 index 988fec2a12..0000000000 --- a/arbor/util/hash.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace arb { -// Non-cryptographic hash function for mapping strings to internal -// identifiers. Concretely, FNV-1a hash function taken from -// -// http://www.isthe.com/chongo/tech/comp/fnv/index.html -// -// NOTE: It may be worth it considering different hash functions in -// the future that have better characteristic, xxHash or Murmur -// look interesting but are more complex and likely require adding -// external dependencies. -// NOTE: this is the obligatory comment on a better hash function -// that will be here until the end of time. - -constexpr hash_type offset_basis = 0xcbf29ce484222325; -constexpr hash_type prime = 0x100000001b3; - -constexpr hash_type internal_hash(std::string_view data) { - hash_type hash = offset_basis; - - for (uint8_t byte: data) { - hash = hash ^ byte; - hash = hash * prime; - } - - return hash; -} - -} diff --git a/test/unit/test_cable_cell.cpp b/test/unit/test_cable_cell.cpp index c1066e9827..2757de30df 100644 --- a/test/unit/test_cable_cell.cpp +++ b/test/unit/test_cable_cell.cpp @@ -1,6 +1,6 @@ #include #include "../common_cells.hpp" -#include "util/hash.hpp" +#include #include #include diff --git a/test/unit/test_label_resolution.cpp b/test/unit/test_label_resolution.cpp index 2dacbdd607..d4f5ade50c 100644 --- a/test/unit/test_label_resolution.cpp +++ b/test/unit/test_label_resolution.cpp @@ -12,7 +12,7 @@ std::vector make_labels(const std::vector& ls) { std::vector res; std::transform(ls.begin(), ls.end(), std::back_inserter(res), - internal_hash); + internal_hash); return res; } From 682a6aacf8812a1b0212bbb89c4f89901e4a5e59 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:20:12 +0100 Subject: [PATCH 07/10] Add some testing, treat pointers. --- arbor/include/arbor/util/hash_def.hpp | 51 +++++++++++++++++++-------- test/unit/CMakeLists.txt | 1 + 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/arbor/include/arbor/util/hash_def.hpp b/arbor/include/arbor/util/hash_def.hpp index 304fe4c58d..c321c945a9 100644 --- a/arbor/include/arbor/util/hash_def.hpp +++ b/arbor/include/arbor/util/hash_def.hpp @@ -18,6 +18,9 @@ #include #include +#include + +#include // Helpers for forming hash values of compounds objects. @@ -37,36 +40,56 @@ namespace arb { template inline constexpr std::size_t internal_hash(T&& data) { + using D = std::decay_t; + constexpr std::size_t prime = 0x100000001b3; + constexpr std::size_t offset_basis = 0xcbf29ce484222325; + static_assert(!std::is_pointer_v || std::is_same_v || std::is_convertible_v, + "Pointer types except void* will not be hashed."); if constexpr (std::is_convertible_v) { - constexpr std::size_t prime = 0x100000001b3; - constexpr std::size_t offset_basis=0xcbf29ce484222325; - std::size_t hash = offset_basis; - for (uint8_t byte: std::string_view{data}) { hash = hash ^ byte; hash = hash * prime; } - return hash; - } else { - return std::hash>{}(data); } + if constexpr (std::is_integral_v) { + unsigned long long bytes = data; + std::size_t hash = offset_basis; + for (int ix = 0; ix < sizeof(data); ++ix) { + uint8_t byte = bytes & 255; + bytes >>= 8; + hash = hash ^ byte; + hash = hash * prime; + } + return hash; + } + if constexpr (std::is_pointer_v) { + unsigned long long bytes = reinterpret_cast(data); + std::size_t hash = offset_basis; + for (int ix = 0; ix < sizeof(data); ++ix) { + uint8_t byte = bytes & 255; + bytes >>= 8; + hash = hash ^ byte; + hash = hash * prime; + } + return hash; + } + return std::hash{}(data); } inline std::size_t hash_value_combine(std::size_t n) { return n; } -template -std::size_t hash_value_combine(std::size_t n, std::size_t m, T... tail) { - constexpr std::size_t prime2 = 54517; - return hash_value_combine(prime2*n + m, tail...); +template +std::size_t hash_value_combine(std::size_t n, const T& head, const Ts&... tail) { + constexpr std::size_t prime = 54517; + return hash_value_combine(prime*n + internal_hash(head), tail...); } template -std::size_t hash_value(const T&... t) { - constexpr std::size_t prime1 = 93481; - return hash_value_combine(prime1, internal_hash(t)...); +std::size_t hash_value(const T&... ts) { + return hash_value_combine(0, ts...); } } diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1a85d77360..b68a6de6d5 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -80,6 +80,7 @@ set(unit_sources test_forest.cpp test_fvm_layout.cpp test_fvm_lowered.cpp + test_hash.cpp test_diffusion.cpp test_iexpr.cpp test_index.cpp From ef792c93e45b2eb73b7e48324fae0939de1fc174 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:43:42 +0100 Subject: [PATCH 08/10] Merge part two. --- arbor/fvm_lowered_cell_impl.hpp | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/arbor/fvm_lowered_cell_impl.hpp b/arbor/fvm_lowered_cell_impl.hpp index fdfb504784..94716b21c5 100644 --- a/arbor/fvm_lowered_cell_impl.hpp +++ b/arbor/fvm_lowered_cell_impl.hpp @@ -327,8 +327,37 @@ add_labels(cell_label_range& clr, const cable_cell::lid_range_map& ranges) { return count; } -fvm_initialization_data fvm_lowered_cell_impl::initialize(const std::vector& gids, - const recipe& rec) { +template void +fvm_lowered_cell_impl::add_probes(const std::vector& gids, + const std::vector& cells, + const recipe& rec, + const fvm_cv_discretization& D, + const std::unordered_map& mechptr_by_name, + const fvm_mechanism_data& mech_data, + const std::vector& target_handles, + probe_association_map& probe_map) { + auto ncell = gids.size(); + + std::vector probe_data; + for (auto cell_idx: util::make_span(ncell)) { + cell_gid_type gid = gids[cell_idx]; + const auto& rec_probes = rec.get_probes(gid); + for (const auto& pi: rec_probes) { + resolve_probe_address(probe_data, cells, cell_idx, pi.address, D, mech_data, target_handles, mechptr_by_name); + if (!probe_data.empty()) { + cell_address_type addr{gid, pi.tag}; + if (probe_map.count(addr)) throw dup_cell_probe(cell_kind::cable, gid, pi.tag); + for (auto& data: probe_data) { + probe_map.insert(addr, std::move(data)); + } + } + } + } +} + +template fvm_initialization_data +fvm_lowered_cell_impl::initialize(const std::vector& gids, + const recipe& rec) { using std::any_cast; using util::count_along; using util::make_span; From 97ca7a4e6ef2e15715b3812d48c4ad5abac28c3a Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:45:29 +0100 Subject: [PATCH 09/10] The missing test. --- test/unit/test_hash.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/unit/test_hash.cpp diff --git a/test/unit/test_hash.cpp b/test/unit/test_hash.cpp new file mode 100644 index 0000000000..444830cc42 --- /dev/null +++ b/test/unit/test_hash.cpp @@ -0,0 +1,24 @@ +#include + +#include + +#include + +TEST(hash, string_eq) { + ASSERT_EQ(arb::hash_value("foobar"), arb::hash_value(std::string{"foobar"})); + ASSERT_EQ(arb::hash_value("foobar"), arb::internal_hash("foobar")); + ASSERT_NE(arb::hash_value("foobar"), arb::internal_hash("barfoo")); +} + +TEST(hash, doesnt_compile) { + double foo = 42; + // Sadly we cannot check static assertions... this shoudln't compile + // EXPECT_ANY_THROW(arb::hash_value(&foo)); + // this should + arb::hash_value((void*) &foo); +} + +// check that we do not fall into the trap of the STL... +TEST(hash, integral_is_not_identity) { + ASSERT_NE(arb::hash_value(42), 42); +} From c583b2f25699e5c50fbc29075053a6b22a47f3d8 Mon Sep 17 00:00:00 2001 From: Thorsten Hater <24411438+thorstenhater@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:46:40 +0100 Subject: [PATCH 10/10] Shuffle internal hash and combine into a detail namespace. --- arbor/benchmark_cell_group.cpp | 5 ++- arbor/cable_cell_param.cpp | 5 +-- arbor/include/arbor/cable_cell_param.hpp | 2 -- arbor/include/arbor/util/hash_def.hpp | 12 +++---- arbor/label_resolution.cpp | 8 ++--- arbor/label_resolution.hpp | 3 +- arbor/lif_cell_group.cpp | 4 +-- arbor/spike_source_cell_group.cpp | 4 +-- test/unit/test_cable_cell.cpp | 27 ++++++++------- test/unit/test_fvm_lowered.cpp | 44 +++++++++++------------- test/unit/test_hash.cpp | 4 +-- test/unit/test_label_resolution.cpp | 24 ++++++------- 12 files changed, 65 insertions(+), 77 deletions(-) diff --git a/arbor/benchmark_cell_group.cpp b/arbor/benchmark_cell_group.cpp index d2ac067182..36887fc8ea 100644 --- a/arbor/benchmark_cell_group.cpp +++ b/arbor/benchmark_cell_group.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -40,8 +39,8 @@ benchmark_cell_group::benchmark_cell_group(const std::vector& gid for (const auto& c: cells_) { cg_sources.add_cell(); cg_targets.add_cell(); - cg_sources.add_label(internal_hash(c.source), {0, 1}); - cg_targets.add_label(internal_hash(c.target), {0, 1}); + cg_sources.add_label(hash_value(c.source), {0, 1}); + cg_targets.add_label(hash_value(c.target), {0, 1}); } benchmark_cell_group::reset(); diff --git a/arbor/cable_cell_param.cpp b/arbor/cable_cell_param.cpp index 6f47a0cca8..e3b425de7a 100644 --- a/arbor/cable_cell_param.cpp +++ b/arbor/cable_cell_param.cpp @@ -1,7 +1,4 @@ -#include #include -#include -#include #include #include #include @@ -122,7 +119,7 @@ decor& decor::paint(region where, paintable what) { } decor& decor::place(locset where, placeable what, cell_tag_type label) { - auto hash = internal_hash(label); + auto hash = hash_value(label); if (hashes_.count(hash) && hashes_.at(hash) != label) { throw arbor_internal_error{util::strprintf("Hash collision {} ./. {}", label, hashes_.at(hash))}; } diff --git a/arbor/include/arbor/cable_cell_param.hpp b/arbor/include/arbor/cable_cell_param.hpp index 62ed0532ed..59bb5bb014 100644 --- a/arbor/include/arbor/cable_cell_param.hpp +++ b/arbor/include/arbor/cable_cell_param.hpp @@ -1,12 +1,10 @@ #pragma once #include -#include #include #include #include #include -#include #include #include diff --git a/arbor/include/arbor/util/hash_def.hpp b/arbor/include/arbor/util/hash_def.hpp index c321c945a9..933a3237e2 100644 --- a/arbor/include/arbor/util/hash_def.hpp +++ b/arbor/include/arbor/util/hash_def.hpp @@ -20,12 +20,11 @@ #include #include -#include - // Helpers for forming hash values of compounds objects. - namespace arb { +namespace detail { + // Non-cryptographic hash function for mapping strings to internal // identifiers. Concretely, FNV-1a hash function taken from // @@ -87,10 +86,11 @@ std::size_t hash_value_combine(std::size_t n, const T& head, const Ts&... tail) return hash_value_combine(prime*n + internal_hash(head), tail...); } -template -std::size_t hash_value(const T&... ts) { - return hash_value_combine(0, ts...); } + +// User facing API +template +std::size_t hash_value(const T&... ts) { return detail::hash_value_combine(0, ts...); } } #define ARB_DEFINE_HASH(type,...)\ diff --git a/arbor/label_resolution.cpp b/arbor/label_resolution.cpp index 14786144f2..29c8b76454 100644 --- a/arbor/label_resolution.cpp +++ b/arbor/label_resolution.cpp @@ -22,7 +22,7 @@ cell_label_range::cell_label_range(std::vector size_vec, { std::transform(label_vec.begin(), label_vec.end(), std::back_inserter(labels), - internal_hash); + hash_value); arb_assert(check_invariant()); }; @@ -93,12 +93,12 @@ lid_hopefully label_resolution_map::range_set::at(unsigned idx) const { } const label_resolution_map::range_set& label_resolution_map::at(cell_gid_type gid, const cell_tag_type& tag) const { - return map.at(gid).at(internal_hash(tag)); + return map.at(gid).at(hash_value(tag)); } std::size_t label_resolution_map::count(cell_gid_type gid, const cell_tag_type& tag) const { if (!map.count(gid)) return 0u; - return map.at(gid).count(internal_hash(tag)); + return map.at(gid).count(hash_value(tag)); } label_resolution_map::label_resolution_map(const cell_labels_and_gids& clg) { @@ -216,7 +216,7 @@ lid_hopefully update_state(resolver::state_variant& v, cell_lid_type resolver::resolve(cell_gid_type gid, const cell_local_label_type& label) { const auto& [tag, pol] = label; - auto hash = internal_hash(tag); + auto hash = hash_value(tag); if (!label_map_->count(gid, tag)) throw arb::bad_connection_label(gid, tag, "label does not exist"); const auto& range_set = label_map_->at(gid, tag); diff --git a/arbor/label_resolution.hpp b/arbor/label_resolution.hpp index 508c9817e9..6f0b14d47b 100644 --- a/arbor/label_resolution.hpp +++ b/arbor/label_resolution.hpp @@ -8,7 +8,6 @@ #include #include -#include "util/partition.hpp" #include namespace arb { @@ -26,7 +25,7 @@ struct ARB_ARBOR_API cell_label_range { cell_label_range& operator=(const cell_label_range&) = default; cell_label_range& operator=(cell_label_range&&) = default; - cell_label_range(std::vector size_vec, std::vector label_vec, std::vector range_vec); + cell_label_range(std::vector size_vec, std::vector label_vec, std::vector rapfnge_vec); cell_label_range(std::vector size_vec, std::vector label_vec, std::vector range_vec); void add_cell(); diff --git a/arbor/lif_cell_group.cpp b/arbor/lif_cell_group.cpp index 8fdee746b3..6698d0edef 100644 --- a/arbor/lif_cell_group.cpp +++ b/arbor/lif_cell_group.cpp @@ -24,8 +24,8 @@ lif_cell_group::lif_cell_group(const std::vector& gids, // tell our caller about this cell's connections cg_sources.add_cell(); cg_targets.add_cell(); - cg_sources.add_label(internal_hash(cell.source), {0, 1}); - cg_targets.add_label(internal_hash(cell.target), {0, 1}); + cg_sources.add_label(hash_value(cell.source), {0, 1}); + cg_targets.add_label(hash_value(cell.target), {0, 1}); // insert probes where needed auto probes = rec.get_probes(gid); for (const auto& probe: probes) { diff --git a/arbor/spike_source_cell_group.cpp b/arbor/spike_source_cell_group.cpp index 41bc9705c0..651980aa44 100644 --- a/arbor/spike_source_cell_group.cpp +++ b/arbor/spike_source_cell_group.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -33,7 +31,7 @@ spike_source_cell_group::spike_source_cell_group( try { auto cell = util::any_cast(rec.get_cell_description(gid)); time_sequences_.emplace_back(cell.seqs); - cg_sources.add_label(internal_hash(cell.source), {0, 1}); + cg_sources.add_label(hash_value(cell.source), {0, 1}); } catch (std::bad_any_cast& e) { throw bad_cell_description(cell_kind::spike_source, gid); diff --git a/test/unit/test_cable_cell.cpp b/test/unit/test_cable_cell.cpp index 2757de30df..8b0a4d460d 100644 --- a/test/unit/test_cable_cell.cpp +++ b/test/unit/test_cable_cell.cpp @@ -1,7 +1,8 @@ #include + #include "../common_cells.hpp" -#include +#include #include #include @@ -46,20 +47,20 @@ TEST(cable_cell, lid_ranges) { const auto& src_ranges = cell.detector_ranges(); const auto& tgt_ranges = cell.synapse_ranges(); - EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t0"))); - EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t1"))); - EXPECT_EQ(1u, src_ranges.count(internal_hash("s0"))); - EXPECT_EQ(1u, tgt_ranges.count(internal_hash("t2"))); - EXPECT_EQ(1u, src_ranges.count(internal_hash("s1"))); - EXPECT_EQ(2u, tgt_ranges.count(internal_hash("t3"))); + EXPECT_EQ(1u, tgt_ranges.count(hash_value("t0"))); + EXPECT_EQ(1u, tgt_ranges.count(hash_value("t1"))); + EXPECT_EQ(1u, src_ranges.count(hash_value("s0"))); + EXPECT_EQ(1u, tgt_ranges.count(hash_value("t2"))); + EXPECT_EQ(1u, src_ranges.count(hash_value("s1"))); + EXPECT_EQ(2u, tgt_ranges.count(hash_value("t3"))); - auto r1 = tgt_ranges.equal_range(internal_hash("t0")).first->second; - auto r2 = tgt_ranges.equal_range(internal_hash("t1")).first->second; - auto r3 = src_ranges.equal_range(internal_hash("s0")).first->second; - auto r4 = tgt_ranges.equal_range(internal_hash("t2")).first->second; - auto r5 = src_ranges.equal_range(internal_hash("s1")).first->second; + auto r1 = tgt_ranges.equal_range(hash_value("t0")).first->second; + auto r2 = tgt_ranges.equal_range(hash_value("t1")).first->second; + auto r3 = src_ranges.equal_range(hash_value("s0")).first->second; + auto r4 = tgt_ranges.equal_range(hash_value("t2")).first->second; + auto r5 = src_ranges.equal_range(hash_value("s1")).first->second; - auto r6_range = tgt_ranges.equal_range(internal_hash("t3")); + auto r6_range = tgt_ranges.equal_range(hash_value("t3")); auto r6_0 = r6_range.first; auto r6_1 = std::next(r6_range.first); if (r6_0->second.begin != 4u) { diff --git a/test/unit/test_fvm_lowered.cpp b/test/unit/test_fvm_lowered.cpp index f06c22c4af..28cc19562e 100644 --- a/test/unit/test_fvm_lowered.cpp +++ b/test/unit/test_fvm_lowered.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -25,11 +24,8 @@ #include "backends/multicore/fvm.hpp" #include "fvm_lowered_cell.hpp" #include "fvm_lowered_cell_impl.hpp" -#include "util/meta.hpp" -#include "util/maputil.hpp" #include "util/rangeutil.hpp" #include "util/span.hpp" -#include "util/transform.hpp" #include "common.hpp" #include "mech_private_field_access.hpp" @@ -994,10 +990,10 @@ TEST(fvm_lowered, label_data) { auto clg = cell_labels_and_gids(fvm_info.target_data, gids); std::vector expected_sizes = {2, 0, 0, 2, 0, 0, 2, 0, 0, 2}; std::vector> expected_labeled_ranges = { - {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, - {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, - {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}}, - {internal_hash("1_synapse"), {4, 5}}, {internal_hash("4_synapses"), {0, 4}} + {hash_value("1_synapse"), {4, 5}}, {hash_value("4_synapses"), {0, 4}}, + {hash_value("1_synapse"), {4, 5}}, {hash_value("4_synapses"), {0, 4}}, + {hash_value("1_synapse"), {4, 5}}, {hash_value("4_synapses"), {0, 4}}, + {hash_value("1_synapse"), {4, 5}}, {hash_value("4_synapses"), {0, 4}} }; std::vector> actual_labeled_ranges; @@ -1033,16 +1029,16 @@ TEST(fvm_lowered, label_data) { auto clg = cell_labels_and_gids(fvm_info.source_data, gids); std::vector expected_sizes = {1, 2, 2, 1, 2, 2, 1, 2, 2, 1}; std::vector> expected_labeled_ranges = { - {internal_hash("1_detector"), {0, 1}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("1_detector"), {0, 1}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("1_detector"), {0, 1}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("2_detectors"), {3, 5}}, {internal_hash("3_detectors"), {0, 3}}, - {internal_hash("1_detector"), {0, 1}} + {hash_value("1_detector"), {0, 1}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("1_detector"), {0, 1}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("1_detector"), {0, 1}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("2_detectors"), {3, 5}}, {hash_value("3_detectors"), {0, 3}}, + {hash_value("1_detector"), {0, 1}} }; std::vector> actual_labeled_ranges; @@ -1077,12 +1073,12 @@ TEST(fvm_lowered, label_data) { auto clg = cell_labels_and_gids(fvm_info.gap_junction_data, gids); std::vector expected_sizes = {0, 2, 2, 0, 2, 2, 0, 2, 2, 0}; std::vector> expected_labeled_ranges = { - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, - {internal_hash("1_gap_junction"), {2, 3}}, {internal_hash("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, + {hash_value("1_gap_junction"), {2, 3}}, {hash_value("2_gap_junctions"), {0, 2}}, }; EXPECT_EQ(clg.gids, gids); diff --git a/test/unit/test_hash.cpp b/test/unit/test_hash.cpp index 444830cc42..bcab44a6d4 100644 --- a/test/unit/test_hash.cpp +++ b/test/unit/test_hash.cpp @@ -6,8 +6,8 @@ TEST(hash, string_eq) { ASSERT_EQ(arb::hash_value("foobar"), arb::hash_value(std::string{"foobar"})); - ASSERT_EQ(arb::hash_value("foobar"), arb::internal_hash("foobar")); - ASSERT_NE(arb::hash_value("foobar"), arb::internal_hash("barfoo")); + ASSERT_EQ(arb::hash_value("foobar"), arb::hash_value("foobar")); + ASSERT_NE(arb::hash_value("foobar"), arb::hash_value("barfoo")); } TEST(hash, doesnt_compile) { diff --git a/test/unit/test_label_resolution.cpp b/test/unit/test_label_resolution.cpp index d4f5ade50c..32c262ee3d 100644 --- a/test/unit/test_label_resolution.cpp +++ b/test/unit/test_label_resolution.cpp @@ -12,7 +12,7 @@ std::vector make_labels(const std::vector& ls) { std::vector res; std::transform(ls.begin(), ls.end(), std::back_inserter(res), - internal_hash); + hash_value); return res; } @@ -23,7 +23,7 @@ TEST(test_cell_label_range, build) { // Test add_cell and add_label auto b0 = cell_label_range(); - EXPECT_THROW(b0.add_label(internal_hash("l0"), {0u, 1u}), arb::arbor_internal_error); + EXPECT_THROW(b0.add_label(hash_value("l0"), {0u, 1u}), arb::arbor_internal_error); EXPECT_TRUE(b0.sizes.empty()); EXPECT_TRUE(b0.labels.empty()); EXPECT_TRUE(b0.ranges.empty()); @@ -40,16 +40,16 @@ TEST(test_cell_label_range, build) { auto b2 = cell_label_range(); b2.add_cell(); - b2.add_label(internal_hash("l0"), {0u, 1u}); - b2.add_label(internal_hash("l0"), {3u, 13u}); - b2.add_label(internal_hash("l1"), {0u, 5u}); + b2.add_label(hash_value("l0"), {0u, 1u}); + b2.add_label(hash_value("l0"), {3u, 13u}); + b2.add_label(hash_value("l1"), {0u, 5u}); b2.add_cell(); b2.add_cell(); - b2.add_label(internal_hash("l2"), {6u, 8u}); - b2.add_label(internal_hash("l3"), {1u, 0u}); - b2.add_label(internal_hash("l4"), {7u, 2u}); - b2.add_label(internal_hash("l4"), {7u, 2u}); - b2.add_label(internal_hash("l2"), {7u, 2u}); + b2.add_label(hash_value("l2"), {6u, 8u}); + b2.add_label(hash_value("l3"), {1u, 0u}); + b2.add_label(hash_value("l4"), {7u, 2u}); + b2.add_label(hash_value("l4"), {7u, 2u}); + b2.add_label(hash_value("l2"), {7u, 2u}); EXPECT_EQ((ivec{3u, 0u, 5u}), b2.sizes); EXPECT_EQ(make_labels(svec{"l0", "l0", "l1", "l2", "l3", "l4", "l4", "l2"}), b2.labels); EXPECT_EQ((lvec{{0u, 1u}, {3u, 13u}, {0u, 5u}, {6u, 8u}, {1u, 0u}, {7u, 2u}, {7u, 2u}, {7u, 2u}}), b2.ranges); @@ -57,8 +57,8 @@ TEST(test_cell_label_range, build) { auto b3 = cell_label_range(); b3.add_cell(); - b3.add_label(internal_hash("r0"), {0u, 9u}); - b3.add_label(internal_hash("r1"), {10u, 10u}); + b3.add_label(hash_value("r0"), {0u, 9u}); + b3.add_label(hash_value("r1"), {10u, 10u}); b3.add_cell(); EXPECT_EQ((ivec{2u, 0u}), b3.sizes); EXPECT_EQ(make_labels