numerics 0.1.0
Loading...
Searching...
No Matches
connected_components.hpp
Go to the documentation of this file.
1/// @file spatial/connected_components.hpp
2/// @brief Iterative BFS connected-component labelling.
3///
4/// connected_components(n_sites, in_cluster, neighbors)
5///
6/// Template parameters:
7/// InCluster callable: bool(int i) -- true if site i is in the
8/// cluster Neighbors callable: void(int i, F&& f) -- calls f(nb) for each
9/// neighbor nb of i
10///
11/// Returns ClusterResult where id[i] is:
12/// -2 = excluded (in_cluster returned false)
13/// >=0 = cluster index
14///
15/// ClusterResult::largest_id and largest_size track the biggest connected
16/// component.
17#pragma once
18
19#include <vector>
20
21namespace num {
22
24 std::vector<int> id; ///< Per-site label: -2 excluded, >=0 cluster index
25 std::vector<int> sizes; ///< sizes[c] = number of sites in cluster c
26 int largest_id = -1; ///< Index of largest cluster (-1 if none)
27 int largest_size = 0; ///< Size of largest cluster
28};
29
30/// BFS connected-component labelling with pre-allocated flat queue (no heap per
31/// call).
32///
33/// @param n_sites Total number of sites
34/// @param in_cluster bool(int i) -- include site i?
35/// @param neighbors void(int i, auto&& visit) -- call visit(nb) per neighbor
36/// of i
37template<typename InCluster, typename Neighbors>
39 InCluster&& in_cluster,
40 Neighbors&& neighbors) {
41 ClusterResult res;
42 res.id.resize(n_sites);
43 res.sizes.reserve(64);
44
45 for (int i = 0; i < n_sites; ++i)
46 res.id[i] = in_cluster(i)
47 ? -1
48 : -2; // -1 = unvisited included, -2 = excluded
49
50 std::vector<int> queue(n_sites);
51 int qhead = 0, qtail = 0;
52
53 for (int start = 0; start < n_sites; ++start) {
54 if (res.id[start] != -1)
55 continue;
56
57 const int cid = static_cast<int>(res.sizes.size());
58 res.sizes.push_back(0);
59 res.id[start] = cid;
60 queue[qtail++] = start;
61
62 while (qhead < qtail) {
63 const int i = queue[qhead++];
64 ++res.sizes[cid];
65 neighbors(i, [&](int nb) {
66 if (res.id[nb] == -1) {
67 res.id[nb] = cid;
68 queue[qtail++] = nb;
69 }
70 });
71 }
72
73 if (res.sizes[cid] > res.largest_size) {
74 res.largest_size = res.sizes[cid];
75 res.largest_id = cid;
76 }
77 }
78 return res;
79}
80
81} // namespace num
ClusterResult connected_components(int n_sites, InCluster &&in_cluster, Neighbors &&neighbors)
int largest_id
Index of largest cluster (-1 if none)
std::vector< int > id
Per-site label: -2 excluded, >=0 cluster index.
int largest_size
Size of largest cluster.
std::vector< int > sizes
sizes[c] = number of sites in cluster c