Graph Utilities#
Block Gibbs needs the free blocks to be independent sets — no two nodes in
one block may share a factor — so building a sampler for a new graph starts with
a graph coloring. rlf_coloring implements Recursive Largest First, which
produces the color classes that become the free blocks.
The high-level model front doors (IsingEBM via ising_sample, and the
continuous programs) call this for you; reach for it directly when you are
assembling a custom PGM and need the sampling order yourself.
hamon.graph_utils.rlf_coloring(n_nodes: int, edges: collections.abc.Iterable[tuple[int, int]]) -> list[int]
#
Color an integer-indexed graph with Recursive Largest First (RLF).
Nodes are 0 .. n_nodes - 1; edges are (u, v) index pairs (direction
and duplicates ignored, self-loops dropped) — any iterable of pairs or an
(m, 2) integer array. Returns colors where colors[i] is the
color class of node i.
RLF builds each color class as a maximal independent set, repeatedly adding the vertex with the most neighbors already excluded from the class (ties broken toward fewest remaining-candidate neighbors, then smallest index). It minimizes the number of colors more aggressively than first-fit/greedy heuristics on dense graphs and matches them on sparse/bipartite ones — and in hamon the color count is the number of sequential block-Gibbs groups, which sets the NRPT round-loop XLA compile cost. Deterministic (index tie-breaking) so colorings are reproducible.
Carries no worst-case bound and can exceed degeneracy + 1, though
rarely enough on real interaction graphs that a smallest-last fallback
was measured and did not earn its keep.
The selection rule is evaluated with incrementally maintained neighbor counters over a CSR adjacency and a vectorized argmax, so the cost is O(|V|² elementwise + |V|·χ + |E|·χ) in NumPy rather than O(|V|·|E|) in Python-set operations. The coloring produced is identical to the reference set-based implementation for any input.