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) ? -1 : -2; // -1 = unvisited included, -2 = excluded
47
48 std::vector<int> queue(n_sites);
49 int qhead = 0, qtail = 0;
50
51 for (int start = 0; start < n_sites; ++start) {
52 if (res.id[start] != -1)
53 continue;
54
55 const int cid = static_cast<int>(res.sizes.size());
56 res.sizes.push_back(0);
57 res.id[start] = cid;
58 queue[qtail++] = start;
59
60 while (qhead < qtail) {
61 const int i = queue[qhead++];
62 ++res.sizes[cid];
63 neighbors(i, [&](int nb) {
64 if (res.id[nb] == -1) {
65 res.id[nb] = cid;
66 queue[qtail++] = nb;
67 }
68 });
69 }
70
71 if (res.sizes[cid] > res.largest_size) {
72 res.largest_size = res.sizes[cid];
73 res.largest_id = cid;
74 }
75 }
76 return res;
77}
78
79} // 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