VeloGraphX
High-performance dynamic graph analytics in C++20
Loading...
Searching...
No Matches
kcore.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cstddef>
5#include <cstdint>
6#include <functional>
7#include <queue>
8#include <stdexcept>
9#include <utility>
10#include <vector>
11
14
15namespace velographx {
16
17template <class Graph>
19 public:
20 explicit BasicIncrementalKCore(Graph& g) : g_(g) {
21 if (is_directed(g_)) {
22 throw std::invalid_argument(
23 "IncrementalKCore requires an undirected graph; directed k-core semantics must be selected explicitly");
24 }
25 recompute();
26 }
27
28 [[nodiscard]] const std::vector<std::uint32_t>& core() const noexcept { return core_; }
29 [[nodiscard]] std::size_t last_repaired_vertices() const noexcept { return last_repaired_vertices_; }
30
31 void apply(const UpdateBatch& batch) {
32 if (batch.updates.empty()) {
33 last_repaired_vertices_ = 0;
34 return;
35 }
36
37 std::vector<std::uint8_t> affected(vertex_count(g_), 0);
38 for (const auto& e : batch.updates) {
39 if (e.src < vertex_count(g_)) mark_component(e.src, affected);
40 if (e.dst < vertex_count(g_)) mark_component(e.dst, affected);
41 }
42
43 apply_updates(g_, batch);
44 if (core_.size() < vertex_count(g_)) core_.resize(vertex_count(g_), 0);
45 affected.resize(vertex_count(g_), 0);
46
47 // Include the post-update components too. Insertions can merge components,
48 // while deletions can split them; the union of pre/post components is a
49 // correctness-preserving repair region for undirected k-core.
50 for (const auto& e : batch.updates) {
51 if (e.src < vertex_count(g_)) mark_component(e.src, affected);
52 if (e.dst < vertex_count(g_)) mark_component(e.dst, affected);
53 }
54
55 recompute_region(affected);
56 }
57
58 void recompute() {
59 const auto n = vertex_count(g_);
60 core_.assign(n, 0);
61 std::vector<std::uint8_t> all(n, 1);
62 recompute_region(all);
63 }
64
65 private:
66 void mark_component(VertexId seed, std::vector<std::uint8_t>& marked) const {
67 if (seed >= vertex_count(g_) || seed >= marked.size() || marked[seed]) return;
68 std::queue<VertexId> q;
69 marked[seed] = 1;
70 q.push(seed);
71 while (!q.empty()) {
72 const auto u = q.front();
73 q.pop();
74 for_each_neighbor(g_, u, [&](VertexId v) {
75 if (v < marked.size() && !marked[v]) {
76 marked[v] = 1;
77 q.push(v);
78 }
79 });
80 }
81 }
82
83 void recompute_region(const std::vector<std::uint8_t>& affected) {
84 const auto n = vertex_count(g_);
85 if (core_.size() < n) core_.resize(n, 0);
86
87 std::vector<std::uint32_t> degree(n, 0);
88 std::vector<std::uint8_t> removed(n, 0);
89 last_repaired_vertices_ = 0;
90
91 using Item = std::pair<std::uint32_t, VertexId>;
92 std::priority_queue<Item, std::vector<Item>, std::greater<Item>> heap;
93
94 for (VertexId u = 0; u < n; ++u) {
95 if (u >= affected.size() || !affected[u]) continue;
96 ++last_repaired_vertices_;
97 for_each_neighbor(g_, u, [&](VertexId v) {
98 if (v < affected.size() && affected[v]) ++degree[u];
99 });
100 core_[u] = 0;
101 heap.push({degree[u], u});
102 }
103
104 std::uint32_t current_core = 0;
105 while (!heap.empty()) {
106 const auto [queued_degree, u] = heap.top();
107 heap.pop();
108 if (u >= n || removed[u] || queued_degree != degree[u]) continue;
109
110 removed[u] = 1;
111 current_core = std::max(current_core, queued_degree);
112 core_[u] = current_core;
113
114 for_each_neighbor(g_, u, [&](VertexId v) {
115 if (v >= n || v >= affected.size() || !affected[v] || removed[v]) return;
116 if (degree[v] != 0) --degree[v];
117 heap.push({degree[v], v});
118 });
119 }
120 }
121
122 Graph& g_;
123 std::vector<std::uint32_t> core_;
124 std::size_t last_repaired_vertices_{0};
125};
126
128
129} // namespace velographx
const std::vector< std::uint32_t > & core() const noexcept
Definition kcore.hpp:28
std::size_t last_repaired_vertices() const noexcept
Definition kcore.hpp:29
void apply(const UpdateBatch &batch)
Definition kcore.hpp:31
void apply_updates(Graph &graph, const Batch &batch)
void for_each_neighbor(const Graph &graph, VertexId u, Fn &&fn)
constexpr bool is_directed(const Graph &graph)
std::uint32_t VertexId
Definition frontier.hpp:6
constexpr std::size_t vertex_count(const Graph &graph)
std::vector< EdgeUpdate > updates