Skip to content

Commit

Permalink
Switch back to a vector for rank remapping.
Browse files Browse the repository at this point in the history
  • Loading branch information
LTLA committed Aug 23, 2024
1 parent e1934b5 commit ada64fe
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 12 deletions.
49 changes: 38 additions & 11 deletions include/singlepp/scaled_ranks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include <vector>
#include <cmath>
#include <limits>
#include <unordered_map>

namespace singlepp {

Expand Down Expand Up @@ -65,21 +64,31 @@ void scaled_ranks(const RankedVector<Stat_, Index_>& collected, Output_* outgoin
template<typename Index_>
class RankRemapper {
private:
std::unordered_map<Index_, Index_> my_mapping;
// This uses a vector instead of an unordered_map for fast remap()
// inside the inner loop of the fine-tuning iterations.
std::vector<std::pair<bool, Index_> > my_mapping;
std::vector<size_t> my_used;
Index_ my_counter = 0;

public:
void add(Index_ i) {
auto it = my_mapping.find(i);
if (it == my_mapping.end()) {
my_mapping[i] = my_counter;
void add(size_t i) {
if (i >= my_mapping.size()) {
my_mapping.resize(i + 1);
}
if (!my_mapping[i].first) {
my_mapping[i].first = true;
my_mapping[i].second = my_counter;
my_used.push_back(i);
++my_counter;
}
}

void clear() {
my_counter = 0;
my_mapping.clear();
for (auto u : my_used) {
my_mapping[u].first = false;
}
my_used.clear();
}

void reserve(size_t n) {
Expand All @@ -90,10 +99,28 @@ class RankRemapper {
template<typename Stat_>
void remap(const RankedVector<Stat_, Index_>& input, RankedVector<Stat_, Index_>& output) const {
output.clear();
for (const auto& x : input) {
auto it = my_mapping.find(x.second);
if (it != my_mapping.end()) {
output.emplace_back(x.first, it->second);

if (static_cast<size_t>(std::numeric_limits<Index_>::max()) < my_mapping.size()) {
// Avoid unnecessary check if the size is already greater than the largest possible index.
// This also avoids the need to cast to indices size_t for comparison to my_mapping.size().
for (const auto& x : input) {
const auto& target = my_mapping[x.second];
if (target.first) {
output.emplace_back(x.first, target.second);
}
}

} else {
// Otherwise, it is safe to cast the size to Index_ outside the
// loop so that we don't need to cast x.second to size_t inside the loop.
Index_ maxed = my_mapping.size();
for (const auto& x : input) {
if (maxed > x.second) {
const auto& target = my_mapping[x.second];
if (target.first) {
output.emplace_back(x.first, target.second);
}
}
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion tests/src/scaled_ranks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ TEST(RankRemapper, Subsets) {
EXPECT_EQ(output[1].second, 1);
EXPECT_EQ(output[2].first, 0.8);
EXPECT_EQ(output[2].second, 2);

// Checking that the clear() method works as expected.
auto copy = remapper;
copy.clear();
copy.remap(input, output);
EXPECT_TRUE(output.empty());
}

// Only even indices are retained.
Expand Down Expand Up @@ -209,13 +215,14 @@ TEST(RankRemapper, Subsets) {

TEST(RankRemapper, SubsetSmallType) {
// Check that the remapper behaves correctly when the index type is smaller
// than the reserved size.
// than the mapping size.
singlepp::internal::RankRemapper<uint8_t> remapper;
remapper.reserve(300);
remapper.add(200);
remapper.add(100);
remapper.add(10);
remapper.add(100); // ignoring duplicates again!
remapper.add(255); // need this to force the mapping to exceed the max index size.

singlepp::internal::RankedVector<double, uint8_t> input;
for (size_t i = 0; i < 250; i += 10) {
Expand Down

0 comments on commit ada64fe

Please sign in to comment.