-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Dominik Rosch
committed
May 8, 2024
1 parent
c31a63f
commit 88982c8
Showing
11 changed files
with
346 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// Created by badger on 5/6/24. | ||
// | ||
|
||
#ifndef SAMPLER_H | ||
#define SAMPLER_H | ||
#include "kaminpar-shm/datastructures/csr_graph.h" | ||
#include "kaminpar-shm/kaminpar.h" | ||
|
||
#include "kaminpar-common/datastructures/static_array.h" | ||
|
||
namespace kaminpar::shm::sparsification { | ||
|
||
class Sampler { | ||
public: | ||
virtual StaticArray<EdgeWeight> sample(const CSRGraph &g) = 0; | ||
}; | ||
|
||
} // kaminpar::shm | ||
|
||
#endif //SAMPLER_H |
30 changes: 30 additions & 0 deletions
30
kaminpar-shm/coarsening/sparsification/UniformRandomSampler.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// | ||
// Created by badger on 5/6/24. | ||
// | ||
|
||
#include "UniformRandomSampler.h" | ||
|
||
#include "kaminpar-common/random.h" | ||
|
||
namespace kaminpar::shm::sparsification { | ||
|
||
StaticArray<EdgeWeight> UniformRandomSampler::sample(const CSRGraph &g) { | ||
unsigned int backedges_deleted = 0; | ||
unsigned int backedges = 0; | ||
unsigned int frontedges = 0; | ||
StaticArray<EdgeWeight> sample = StaticArray<EdgeWeight>(g.m()); | ||
unsigned int edges_deleted = 0; | ||
for (int v = 0; v < g.n(); ++v) { | ||
for (EdgeID e : g.incident_edges(v)) { | ||
KASSERT(v != g.edge_target(e), "no loops allowed", assert::always); | ||
if (v < g.edge_target(e)) { | ||
frontedges++; | ||
sample[e] = Random::instance().random_bool(_probability) ? g.edge_weight(e) : 0; | ||
if (!sample[e]) | ||
edges_deleted++; | ||
} | ||
} | ||
} | ||
return sample; | ||
} | ||
} // namespace kaminpar::shm::sparsification |
20 changes: 20 additions & 0 deletions
20
kaminpar-shm/coarsening/sparsification/UniformRandomSampler.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// | ||
// Created by badger on 5/6/24. | ||
// | ||
|
||
#ifndef UNIFORMRANDOMSAMPLER_H | ||
#define UNIFORMRANDOMSAMPLER_H | ||
#include "Sampler.h" | ||
|
||
namespace kaminpar::shm::sparsification { | ||
class UniformRandomSampler : public Sampler { | ||
private: | ||
float _probability; | ||
|
||
public: | ||
UniformRandomSampler(float probability) : _probability(probability) {} | ||
StaticArray<EdgeWeight> sample(const CSRGraph &g) override; | ||
}; | ||
} // namespace kaminpar::shm::sparsification | ||
|
||
#endif // UNIFORMRANDOMSAMPLER_H |
190 changes: 190 additions & 0 deletions
190
kaminpar-shm/coarsening/sparsifing_cluster_coarsener.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/******************************************************************************* | ||
* cluster corsener with included sparsification | ||
* | ||
* @file: cluster_coarsener.cc | ||
* @author: Dominik Rosch | ||
* @date: 29.09.2021 | ||
******************************************************************************/ | ||
#include "kaminpar-shm/coarsening/sparsifing_cluster_coarsener.h" | ||
|
||
#include "contraction/cluster_contraction_preprocessing.h" | ||
#include "sparsification/UniformRandomSampler.h" | ||
|
||
#include "kaminpar-shm/coarsening/contraction/cluster_contraction.h" | ||
#include "kaminpar-shm/coarsening/max_cluster_weights.h" | ||
#include "kaminpar-shm/context_io.h" | ||
#include "kaminpar-shm/factories.h" | ||
#include "kaminpar-shm/kaminpar.h" | ||
|
||
#include "kaminpar-common/assert.h" | ||
#include "kaminpar-common/heap_profiler.h" | ||
#include "kaminpar-common/random.h" | ||
#include "kaminpar-common/timer.h" | ||
|
||
namespace kaminpar::shm { | ||
SparsifingClusteringCoarsener::SparsifingClusteringCoarsener( | ||
const Context &ctx, const PartitionContext &p_ctx | ||
) | ||
: _clustering_algorithm(factory::create_clusterer(ctx)), | ||
_sampling_algorithm(std::make_unique<sparsification::UniformRandomSampler>( | ||
sparsification::UniformRandomSampler(0.3) | ||
)), | ||
_c_ctx(ctx.coarsening), | ||
_p_ctx(p_ctx) {} | ||
|
||
void SparsifingClusteringCoarsener::initialize(const Graph *graph) { | ||
_hierarchy.clear(); | ||
_input_graph = graph; | ||
} | ||
|
||
/** | ||
* Deletes all edges with weight 0 in the sample and reweights the rest | ||
* Only the sample entries for an edge (v, u) with v < u are considered | ||
* @param csr Graph in csr format | ||
* @param sample for every edge 0, if it should be removed, its (new) weight otherwise | ||
* @param edges_kept how many edges are samples, i.e., how many entries in sample are not 0 | ||
*/ | ||
CSRGraph | ||
SparsifingClusteringCoarsener::sparsify(const CSRGraph *g, StaticArray<EdgeWeight> sample) { | ||
auto nodes = StaticArray<EdgeID>(g->n() + 1); | ||
for (NodeID v : g->nodes()) { | ||
for (EdgeID e : g->incident_edges(v)) { | ||
NodeID u = g->edge_target(e); | ||
if (v < u && sample[e]) { | ||
nodes[v + 1]++; | ||
nodes[u + 1]++; | ||
} | ||
} | ||
} | ||
parallel::prefix_sum(nodes.begin(), nodes.end(), nodes.begin()); | ||
|
||
auto edges_added = StaticArray<EdgeID>(g->n(), 0); | ||
auto edges = StaticArray<NodeID>(nodes[g->n()]); | ||
auto edge_weights = StaticArray<EdgeWeight>(nodes[g->n()]); | ||
|
||
for (NodeID v : g->nodes()) { | ||
for (EdgeID e : g->incident_edges(v)) { | ||
NodeID u = g->edge_target(e); | ||
if (v < u && sample[e]) { | ||
edges[nodes[v] + edges_added[v]] = u; | ||
edges[nodes[u] + edges_added[u]] = v; | ||
edge_weights[nodes[v] + edges_added[v]] = sample[e]; | ||
edge_weights[nodes[u] + edges_added[u]] = sample[e]; | ||
edges_added[v]++; | ||
edges_added[u]++; | ||
} | ||
} | ||
} | ||
|
||
return CSRGraph( | ||
std::move(nodes), | ||
std::move(edges), | ||
std::move(StaticArray<NodeWeight>(g->raw_node_weights().begin(), g->raw_node_weights().end()) | ||
), | ||
std::move(edge_weights) | ||
); | ||
} | ||
|
||
bool SparsifingClusteringCoarsener::coarsen() { | ||
SCOPED_HEAP_PROFILER("Level", std::to_string(_hierarchy.size())); | ||
SCOPED_TIMER("Level", std::to_string(_hierarchy.size())); | ||
|
||
START_HEAP_PROFILER("Allocation"); | ||
RECORD("clustering") StaticArray<NodeID> clustering(current().n(), static_array::noinit); | ||
STOP_HEAP_PROFILER(); | ||
|
||
const bool free_allocated_memory = !keep_allocated_memory(); | ||
const NodeWeight total_node_weight = current().total_node_weight(); | ||
const NodeID prev_n = current().n(); | ||
|
||
START_HEAP_PROFILER("Label Propagation"); | ||
START_TIMER("Label Propagation"); | ||
_clustering_algorithm->set_max_cluster_weight( | ||
compute_max_cluster_weight<NodeWeight>(_c_ctx, _p_ctx, prev_n, total_node_weight) | ||
); | ||
_clustering_algorithm->set_desired_cluster_count(0); | ||
_clustering_algorithm->compute_clustering(clustering, current(), free_allocated_memory); | ||
STOP_TIMER(); | ||
STOP_HEAP_PROFILER(); | ||
|
||
START_HEAP_PROFILER("Contract graph"); | ||
auto coarsened = TIMED_SCOPE("Contract graph") { | ||
return contract_clustering( | ||
current(), std::move(clustering), _c_ctx.contraction, _contraction_m_ctx | ||
); | ||
}; | ||
|
||
KASSERT(coarsened->get().m() % 2 == 0, "graph should be undirected", assert::always); | ||
const CSRGraph *csr = dynamic_cast<const CSRGraph *>(coarsened->get().underlying_graph()); | ||
KASSERT(csr != nullptr, "can only be used with a CSRGraph", assert::always); | ||
|
||
auto sample = _sampling_algorithm->sample(*csr); | ||
CSRGraph sparsified = sparsify(csr, std::move(sample)); | ||
|
||
_hierarchy.push_back(std::make_unique<contraction::CoarseGraphImpl<StaticArray>>( | ||
Graph(std::make_unique<CSRGraph>(std::move(sparsified))), | ||
std::move( | ||
dynamic_cast<contraction::CoarseGraphImpl<StaticArray> *>(coarsened.get())->get_mapping() | ||
) | ||
)); | ||
STOP_HEAP_PROFILER(); | ||
|
||
const NodeID next_n = current().n(); | ||
const bool converged = (1.0 - 1.0 * next_n / prev_n) <= _c_ctx.convergence_threshold; | ||
|
||
if (free_allocated_memory) { | ||
_contraction_m_ctx.buckets.free(); | ||
_contraction_m_ctx.buckets_index.free(); | ||
_contraction_m_ctx.all_buffered_nodes.free(); | ||
} | ||
|
||
return !converged; | ||
} | ||
|
||
PartitionedGraph SparsifingClusteringCoarsener::uncoarsen(PartitionedGraph &&p_graph) { | ||
SCOPED_HEAP_PROFILER("Level", std::to_string(_hierarchy.size())); | ||
SCOPED_TIMER("Level", std::to_string(_hierarchy.size())); | ||
|
||
const BlockID p_graph_k = p_graph.k(); | ||
const auto p_graph_partition = p_graph.take_raw_partition(); | ||
|
||
auto coarsened = pop_hierarchy(std::move(p_graph)); | ||
const NodeID next_n = current().n(); | ||
|
||
START_HEAP_PROFILER("Allocation"); | ||
START_TIMER("Allocation"); | ||
RECORD("partition") StaticArray<BlockID> partition(next_n); | ||
STOP_TIMER(); | ||
STOP_HEAP_PROFILER(); | ||
|
||
START_TIMER("Project partition"); | ||
coarsened->project(p_graph_partition, partition); | ||
STOP_TIMER(); | ||
|
||
SCOPED_HEAP_PROFILER("Create graph"); | ||
SCOPED_TIMER("Create graph"); | ||
return {current(), p_graph_k, std::move(partition)}; | ||
} | ||
|
||
std::unique_ptr<CoarseGraph> SparsifingClusteringCoarsener::pop_hierarchy(PartitionedGraph &&p_graph | ||
) { | ||
KASSERT(!empty(), "cannot pop from an empty graph hierarchy", assert::light); | ||
|
||
auto coarsened = std::move(_hierarchy.back()); | ||
_hierarchy.pop_back(); | ||
|
||
KASSERT( | ||
&coarsened->get() == &p_graph.graph(), | ||
"p_graph wraps a different graph (ptr=" | ||
<< &p_graph.graph() << ") than the one that was coarsened (ptr=" << &coarsened->get() | ||
<< ")", | ||
assert::light | ||
); | ||
|
||
return coarsened; | ||
} | ||
|
||
bool SparsifingClusteringCoarsener::keep_allocated_memory() const { | ||
return level() >= _c_ctx.clustering.max_mem_free_coarsening_level; | ||
} | ||
} // namespace kaminpar::shm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/******************************************************************************* | ||
* Coarsener that is optimized to contract clusterings. | ||
* | ||
* @file: cluster_coarsener.h | ||
* @author: Daniel Seemaier | ||
* @date: 29.09.2021 | ||
******************************************************************************/ | ||
#pragma once | ||
|
||
#include "sparsification/Sampler.h" | ||
|
||
#include "kaminpar-shm/coarsening/clusterer.h" | ||
#include "kaminpar-shm/coarsening/coarsener.h" | ||
#include "kaminpar-shm/coarsening/contraction/cluster_contraction.h" | ||
#include "kaminpar-shm/datastructures/graph.h" | ||
#include "kaminpar-shm/datastructures/partitioned_graph.h" | ||
#include "kaminpar-shm/kaminpar.h" | ||
|
||
namespace kaminpar::shm { | ||
class SparsifingClusteringCoarsener : public Coarsener { | ||
public: | ||
SparsifingClusteringCoarsener(const Context &ctx, const PartitionContext &p_ctx); | ||
|
||
SparsifingClusteringCoarsener(const SparsifingClusteringCoarsener &) = delete; | ||
SparsifingClusteringCoarsener &operator=(const SparsifingClusteringCoarsener) = delete; | ||
|
||
SparsifingClusteringCoarsener(SparsifingClusteringCoarsener &&) = delete; | ||
SparsifingClusteringCoarsener &operator=(SparsifingClusteringCoarsener &&) = delete; | ||
|
||
void initialize(const Graph *graph) final; | ||
|
||
CSRGraph sparsify(const CSRGraph *csr, StaticArray<EdgeWeight> sample); | ||
|
||
bool coarsen() final; | ||
PartitionedGraph uncoarsen(PartitionedGraph &&p_graph) final; | ||
|
||
[[nodiscard]] const Graph ¤t() const final { | ||
return _hierarchy.empty() ? *_input_graph : _hierarchy.back()->get(); | ||
} | ||
|
||
[[nodiscard]] std::size_t level() const final { | ||
return _hierarchy.size(); | ||
} | ||
|
||
private: | ||
std::unique_ptr<CoarseGraph> pop_hierarchy(PartitionedGraph &&p_graph); | ||
|
||
[[nodiscard]] bool keep_allocated_memory() const; | ||
|
||
const CoarseningContext &_c_ctx; | ||
const PartitionContext &_p_ctx; | ||
|
||
const Graph *_input_graph; | ||
std::vector<std::unique_ptr<CoarseGraph>> _hierarchy; | ||
|
||
std::unique_ptr<Clusterer> _clustering_algorithm; | ||
std::unique_ptr<sparsification::Sampler> _sampling_algorithm; | ||
|
||
contraction::MemoryContext _contraction_m_ctx{}; | ||
}; | ||
} // namespace kaminpar::shm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.