diff --git a/kaminpar-shm/coarsening/example_coarsener.cc b/kaminpar-shm/coarsening/example_coarsener.cc new file mode 100644 index 00000000..fdb8de45 --- /dev/null +++ b/kaminpar-shm/coarsening/example_coarsener.cc @@ -0,0 +1,63 @@ +#include "kaminpar-shm/coarsening/example_coarsener.h" + +#include "kaminpar-shm/coarsening/contraction/cluster_contraction.h" +#include "kaminpar-shm/coarsening/max_cluster_weights.h" +#include "kaminpar-shm/factories.h" +#include "kaminpar-shm/kaminpar.h" + +#include "kaminpar-common/assert.h" + +namespace kaminpar::shm { +ExampleCoarsener::ExampleCoarsener(const Context &ctx, const PartitionContext &p_ctx) + : _clustering_algorithm(factory::create_clusterer(ctx)), + _c_ctx(ctx.coarsening), + _p_ctx(p_ctx) {} + +void ExampleCoarsener::initialize(const Graph *graph) { + _hierarchy.clear(); + _input_graph = graph; +} + +bool ExampleCoarsener::coarsen() { + const NodeWeight total_node_weight = current().total_node_weight(); + const NodeID prev_n = current().n(); + + // Compute the graph clustering via label propagation + StaticArray clustering(prev_n, static_array::noinit); + _clustering_algorithm->set_max_cluster_weight( + compute_max_cluster_weight(_c_ctx, _p_ctx, prev_n, total_node_weight) + ); + _clustering_algorithm->compute_clustering(clustering, current(), false); + + // Construct the coarse graph by contracting the current graph + std::unique_ptr coarsened = + contract_clustering(current(), std::move(clustering), _c_ctx.contraction); + _hierarchy.push_back(std::move(coarsened)); + // Coarse graph: coarsened->get() + + // Determine whether the coarsening process should continue + const NodeID next_n = current().n(); + const bool converged = (1.0 - 1.0 * next_n / prev_n) <= _c_ctx.convergence_threshold; + return !converged; +} + +PartitionedGraph ExampleCoarsener::uncoarsen(PartitionedGraph &&p_graph) { + // Graph partition of the coarse graph that must be projected onto the finer graph: + const BlockID p_graph_k = p_graph.k(); + const StaticArray p_graph_partition = p_graph.take_raw_partition(); + + // Current coarse graph + std::unique_ptr coarsened = std::move(_hierarchy.back()); + KASSERT(&coarsened->get() == &p_graph.graph()); + + // Pop coarse graph from the hierarchy: this destroys the graph wrapped in p_graph, i.e., p_graph + // may no longer be used + _hierarchy.pop_back(); + const NodeID next_n = current().n(); + + StaticArray partition(next_n); + coarsened->project(p_graph_partition, partition); + return {current(), p_graph_k, std::move(partition)}; +} +} // namespace kaminpar::shm + diff --git a/kaminpar-shm/coarsening/example_coarsener.h b/kaminpar-shm/coarsening/example_coarsener.h new file mode 100644 index 00000000..aca00621 --- /dev/null +++ b/kaminpar-shm/coarsening/example_coarsener.h @@ -0,0 +1,46 @@ +#pragma once + +#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 ExampleCoarsener : public Coarsener { +public: + ExampleCoarsener(const Context &ctx, const PartitionContext &p_ctx); + + ExampleCoarsener(const ExampleCoarsener &) = delete; + ExampleCoarsener &operator=(const ExampleCoarsener) = delete; + + ExampleCoarsener(ExampleCoarsener &&) = delete; + ExampleCoarsener &operator=(ExampleCoarsener &&) = delete; + + void initialize(const Graph *graph) final; + + 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 pop_hierarchy(PartitionedGraph &&p_graph); + + const CoarseningContext &_c_ctx; + const PartitionContext &_p_ctx; + + const Graph *_input_graph; + std::vector> _hierarchy; + + std::unique_ptr _clustering_algorithm; +}; +} // namespace kaminpar::shm + diff --git a/kaminpar-shm/context_io.cc b/kaminpar-shm/context_io.cc index 4b3ec884..1d49f090 100644 --- a/kaminpar-shm/context_io.cc +++ b/kaminpar-shm/context_io.cc @@ -65,6 +65,7 @@ std::unordered_map get_coarsening_algorithms() return { {"noop", CoarseningAlgorithm::NOOP}, {"clustering", CoarseningAlgorithm::CLUSTERING}, + {"example", CoarseningAlgorithm::EXAMPLE}, }; } @@ -74,6 +75,8 @@ std::ostream &operator<<(std::ostream &out, const CoarseningAlgorithm algorithm) return out << "noop"; case CoarseningAlgorithm::CLUSTERING: return out << "clustering"; + case CoarseningAlgorithm::EXAMPLE: + return out << "example"; } return out << ""; diff --git a/kaminpar-shm/factories.cc b/kaminpar-shm/factories.cc index 5a8d5357..0402ac99 100644 --- a/kaminpar-shm/factories.cc +++ b/kaminpar-shm/factories.cc @@ -22,6 +22,7 @@ // Coarsening #include "kaminpar-shm/coarsening/cluster_coarsener.h" +#include "kaminpar-shm/coarsening/example_coarsener.h" #include "kaminpar-shm/coarsening/noop_coarsener.h" // Refinement @@ -77,6 +78,9 @@ std::unique_ptr create_coarsener(const Context &ctx, const PartitionC case CoarseningAlgorithm::CLUSTERING: return std::make_unique(ctx, p_ctx); + + case CoarseningAlgorithm::EXAMPLE: + return std::make_unique(ctx, p_ctx); } __builtin_unreachable(); diff --git a/kaminpar-shm/kaminpar.h b/kaminpar-shm/kaminpar.h index 163e2288..4742ed8f 100644 --- a/kaminpar-shm/kaminpar.h +++ b/kaminpar-shm/kaminpar.h @@ -80,6 +80,7 @@ enum class EdgeOrdering { enum class CoarseningAlgorithm { NOOP, CLUSTERING, + EXAMPLE, }; enum class ClusteringAlgorithm {