Skip to content
Merged
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
24 changes: 18 additions & 6 deletions kagen/edgeweight_generators/hashing_based_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,38 @@
#include "kagen/context.h"
#include "kagen/kagen.h"

#include <array>

#ifdef KAGEN_XXHASH_FOUND
#include "xxhash.h"
#else // KAGEN_XXHASH_FOUND
#include <stdexcept>
#endif // KAGEN_XXHASH_FOUND

namespace kagen {
HashingBasedEdgeWeightGenerator::HashingBasedEdgeWeightGenerator(EdgeWeightConfig config) : config_(config) {}
HashingBasedEdgeWeightGenerator::HashingBasedEdgeWeightGenerator(EdgeWeightConfig config, VertexRange vertex_range)
: PerEdgeWeightGenerator(vertex_range),
config_(config) {}

SSInt HashingBasedEdgeWeightGenerator::GenerateEdgeWeight(SInt u, SInt v) {
#ifdef KAGEN_XXHASH_FOUND
const SInt hash1 = XXH64(&u, 1, 0);
const SInt hash2 = XXH64(&v, 1, 0);
const SSInt combined =
(hash1 ^ hash2) % (config_.weight_range_end - config_.weight_range_begin) + config_.weight_range_begin;
return combined;
if (u > v) {
std::swap(u, v);
}
std::array<SInt, 2> buf{u, v};
const SInt range = config_.weight_range_end - config_.weight_range_begin;
const SInt hash = XXH64(buf.data(), sizeof(buf), 0);
#if defined(__SIZEOF_INT128__)
const SInt hash_in_range = (static_cast<__uint128_t>(hash) * range >> 64);
#else
const SInt hash_in_range = hash % range;
#endif
return hash_in_range + config_.weight_range_begin;
#else // KAGEN_XXHASH_FOUND
((void)u);
((void)v);
throw std::runtime_error("xxHash is required for hashing based edge weights");
#endif // KAGEN_XXHASH_FOUND
return -1;
}
} // namespace kagen
2 changes: 1 addition & 1 deletion kagen/edgeweight_generators/hashing_based_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace kagen {
class HashingBasedEdgeWeightGenerator : public PerEdgeWeightGenerator<HashingBasedEdgeWeightGenerator> {
public:
HashingBasedEdgeWeightGenerator(EdgeWeightConfig config);
HashingBasedEdgeWeightGenerator(EdgeWeightConfig config, VertexRange vertex_range);

SSInt GenerateEdgeWeight(SInt u, SInt v);

Expand Down
32 changes: 19 additions & 13 deletions kagen/edgeweight_generators/per_edge_weight_generator.h
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
#pragma once

#include "kagen/context.h"
#include "kagen/edge_range.h"
#include "kagen/edgeweight_generators/edge_weight_generator.h"
#include "kagen/kagen.h"

namespace kagen {
template <typename Derived>
class PerEdgeWeightGenerator : public EdgeWeightGenerator {
public:
void GenerateEdgeWeights(const Edgelist& edgelist, EdgeWeights& weights) final {
weights.reserve(edgelist.size());
PerEdgeWeightGenerator(VertexRange vertex_range) :
vertex_range_{vertex_range} {}

for (const auto& [u, v]: edgelist) {
SSInt weight = static_cast<Derived*>(this)->GenerateEdgeWeight(u, v);
weights.push_back(weight);
}
void GenerateEdgeWeights(const Edgelist& edgelist, EdgeWeights& weights) final {
EdgeRange edge_range(edgelist);
GenerateEdgeWeightsImpl(edge_range, weights);
}

void GenerateEdgeWeights(const XadjArray& xadj, const AdjncyArray& adjncy, EdgeWeights& weights) final {
weights.reserve(adjncy.size());
EdgeRange edge_range(xadj, adjncy, vertex_range_);
GenerateEdgeWeightsImpl(edge_range, weights);
}

private:
VertexRange vertex_range_;

for (SInt u = 0; u + 1 < xadj.size(); ++u) {
for (SInt e = xadj[u]; e < xadj[u + 1]; ++e) {
SInt v = adjncy[e];
SSInt weight = static_cast<Derived*>(this)->GenerateEdgeWeight(u, v);
weights.push_back(weight);
}
void GenerateEdgeWeightsImpl(EdgeRange range, EdgeWeights& weights) {
weights.reserve(range.size());
for (auto it = range.begin(); it != range.end(); ++it) {
auto [u, v] = *it;
SSInt weight = static_cast<Derived*>(this)->GenerateEdgeWeight(u, v);
weights.push_back(weight);
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion kagen/generators/generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ CreateEdgeWeightGenerator(const EdgeWeightConfig weight_config, MPI_Comm comm, c
case EdgeWeightGeneratorType::VOIDING:
return std::make_unique<VoidingEdgeWeightGenerator>(weight_config);
case EdgeWeightGeneratorType::HASHING_BASED:
return std::make_unique<HashingBasedEdgeWeightGenerator>(weight_config);
return std::make_unique<HashingBasedEdgeWeightGenerator>(weight_config, vertex_range);
case EdgeWeightGeneratorType::EUCLIDEAN_DISTANCE:
return std::make_unique<EuclideanDistanceEdgeWeightGenerator>(weight_config);
case EdgeWeightGeneratorType::UNIFORM_RANDOM:
Expand Down
78 changes: 67 additions & 11 deletions tests/edge_weights/edge_generation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ void check_euclidean_weights(const Graph& graph, double max_distance, const Weig
}

// Test fixture for uniform random weight tests
struct UniformWeightTestFixture : public ::testing::TestWithParam<std::tuple<std::string, GeneratorFunc>> {};
struct GeneralEdgeWeightTestFixture : public ::testing::TestWithParam<std::tuple<std::string, GeneratorFunc>> {};

INSTANTIATE_TEST_SUITE_P(
UniformWeightTests, UniformWeightTestFixture,
GeneralEdgeWeightTests, GeneralEdgeWeightTestFixture,
::testing::Values(
std::make_tuple("GNM", GeneratorFunc([](KaGen& gen, SInt n, SInt m) {
return gen.GenerateUndirectedGNM(n, m);
Expand All @@ -110,10 +110,9 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple("Grid3D", GeneratorFunc([](KaGen& gen, SInt n, SInt m) {
return gen.GenerateGrid3D_NM(n, m);
}))),
[](const ::testing::TestParamInfo<UniformWeightTestFixture::ParamType>& info) { return std::get<0>(info.param); });
[](const ::testing::TestParamInfo<GeneralEdgeWeightTestFixture::ParamType>& info) { return std::get<0>(info.param); });

TEST_P(UniformWeightTestFixture, weights_in_range_edgelist_representation) {
std::string name = std::get<0>(GetParam());
TEST_P(GeneralEdgeWeightTestFixture, uniform_weights_in_range_edgelist_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
Expand All @@ -128,8 +127,7 @@ TEST_P(UniformWeightTestFixture, weights_in_range_edgelist_representation) {
check_weights_range(graph, weight_range);
}

TEST_P(UniformWeightTestFixture, weights_in_range_csr_representation) {
std::string name = std::get<0>(GetParam());
TEST_P(GeneralEdgeWeightTestFixture, uniform_weights_in_range_csr_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
Expand All @@ -144,8 +142,7 @@ TEST_P(UniformWeightTestFixture, weights_in_range_csr_representation) {
check_weights_range(graph, weight_range);
}

TEST_P(UniformWeightTestFixture, correct_backedge_weights_edgelist_representation) {
std::string name = std::get<0>(GetParam());
TEST_P(GeneralEdgeWeightTestFixture, uniform_correct_backedge_weights_edgelist_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
Expand All @@ -160,8 +157,7 @@ TEST_P(UniformWeightTestFixture, correct_backedge_weights_edgelist_representatio
check_backedge_weight(graph);
}

TEST_P(UniformWeightTestFixture, correct_backedge_weights_csr_representation) {
std::string name = std::get<0>(GetParam());
TEST_P(GeneralEdgeWeightTestFixture, uniform_correct_backedge_weights_csr_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
Expand All @@ -176,6 +172,66 @@ TEST_P(UniformWeightTestFixture, correct_backedge_weights_csr_representation) {
check_backedge_weight(graph);
}

TEST_P(GeneralEdgeWeightTestFixture, hashing_based_weights_in_range_edgelist_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
const WeightRange weight_range{1, 100};

kagen::KaGen generator(MPI_COMM_WORLD);
generator.UseEdgeListRepresentation();
generator.ConfigureEdgeWeightGeneration(
kagen::EdgeWeightGeneratorType::HASHING_BASED, weight_range.first, weight_range.second);

Graph graph = generate(generator, n, m);
check_weights_range(graph, weight_range);
}

TEST_P(GeneralEdgeWeightTestFixture, hashing_based_weights_in_range_csr_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
const WeightRange weight_range{1, 100};

kagen::KaGen generator(MPI_COMM_WORLD);
generator.UseCSRRepresentation();
generator.ConfigureEdgeWeightGeneration(
kagen::EdgeWeightGeneratorType::HASHING_BASED, weight_range.first, weight_range.second);

Graph graph = generate(generator, n, m);
check_weights_range(graph, weight_range);
}

TEST_P(GeneralEdgeWeightTestFixture, hashing_based_correct_backedge_weights_edgelist_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
const WeightRange weight_range{1, 100};

kagen::KaGen generator(MPI_COMM_WORLD);
generator.UseEdgeListRepresentation();
generator.ConfigureEdgeWeightGeneration(
kagen::EdgeWeightGeneratorType::HASHING_BASED, weight_range.first, weight_range.second);

Graph graph = generate(generator, n, m);
check_backedge_weight(graph);
}

TEST_P(GeneralEdgeWeightTestFixture, hashing_based_correct_backedge_weights_csr_representation) {
GeneratorFunc generate = std::get<1>(GetParam());
const SInt n = 1000;
const SInt m = 16 * n;
const WeightRange weight_range{1, 100};

kagen::KaGen generator(MPI_COMM_WORLD);
generator.UseCSRRepresentation();
generator.ConfigureEdgeWeightGeneration(
kagen::EdgeWeightGeneratorType::HASHING_BASED, weight_range.first, weight_range.second);

Graph graph = generate(generator, n, m);
check_backedge_weight(graph);
}

// Test fixture for Euclidean weight tests
struct EuclideanWeightTestFixture
: public ::testing::TestWithParam<
Expand Down