include/spatial/connected_components.hpp provides num::connected_components, a template BFS labelling function with a pre-allocated flat queue (no heap allocation per call, no recursion).
Problem
Connected-component labeling partitions included vertices of a finite graph into maximal connected subsets. For Ising nucleation, included vertices are the spin-down sites and the largest component is the nucleus observable.
connected_components uses caller-supplied predicates for site inclusion and neighbor traversal.
Routine Reference
};
template<typename InCluster, typename Neighbors>
int n_sites,
InCluster&& in_cluster,
Neighbors&& neighbors);
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
Labels
id[i] | Meaning |
-2 | Excluded – in_cluster(i) returned false |
>=0 | Cluster index |
Sites with id[i] == ClusterResult::largest_id belong to the largest cluster.
Algorithm
Iterative BFS with a pre-allocated flat queue of size n_sites:
for each unvisited included site s:
assign cluster id, push to queue
while queue not empty:
pop i, increment size
for each neighbor nb of i:
if unvisited: label nb, push
update largest_id / largest_size
No heap allocations after the initial ClusterResult construction.
Ising Nucleation Observable
[&](int i) { return spins[i] < 0.0; },
[&](int i, auto&& visit) {
visit(nbr.up[i]); visit(nbr.dn[i]);
visit(nbr.lt[i]); visit(nbr.rt[i]);
});
4-neighbor periodic-boundary index arrays for an NxN lattice.
Generalizations
The callable interface accepts any graph topology:
[&](int i) { return active[i]; },
[&](int i, auto&& visit) {
for (int nb : six_neighbors(i, nx, ny, nz))
visit(nb);
});
[&](int i) { return !excluded[i]; },
[&](int i, auto&& visit) {
for (int nb : adj[i]) visit(nb);
});