@@ -238,3 +238,41 @@ def test_empty_graph():
238238 graph , labels , graph_depth = 2 , mode = "all"
239239 )
240240 assert out .shape == (0 , 2 )
241+
242+
243+ def test_default_threading_is_deterministic_on_large_chain ():
244+ # Regression guard for a data race in the lazy CSR-adjacency rebuild: with
245+ # default (multi-threaded) execution, every worker used to trigger the
246+ # not-thread-safe rebuild concurrently on the first node_adjacency() read,
247+ # corrupting the adjacency. That produced run-to-run varying counts and
248+ # intermittent segfaults. A graph this size reliably exposes the race
249+ # (a 10-node chain does not). The result must equal the single-threaded
250+ # reference on every run.
251+ n = 2000
252+ graph = _make_chain (n ) # built via from_edges -> arrives "dirty"
253+ labels = np .ones (n , dtype = np .uint64 )
254+ reference = bic .graph .lifted_multicut .lifted_edges_from_node_labels (
255+ graph , labels , graph_depth = 3 , mode = "all" , number_of_threads = 1
256+ )
257+ for _ in range (25 ):
258+ out = bic .graph .lifted_multicut .lifted_edges_from_node_labels (
259+ graph , labels , graph_depth = 3 , mode = "all" # default: multi-threaded
260+ )
261+ assert out .tolist () == reference .tolist ()
262+
263+
264+ def test_default_threading_is_deterministic_on_rag ():
265+ # Same race, reached through the region_adjacency_graph construction path,
266+ # which also returns a graph with a dirty (not-yet-built) adjacency.
267+ n = 2000
268+ segmentation = np .repeat (np .arange (n , dtype = np .uint32 ), 16 ).reshape (n , 4 , 4 )
269+ rag = bic .graph .region_adjacency_graph (segmentation )
270+ labels = np .ones (rag .numberOfNodes , dtype = np .uint64 )
271+ reference = bic .graph .lifted_multicut .lifted_edges_from_node_labels (
272+ rag , labels , graph_depth = 3 , mode = "all" , number_of_threads = 1
273+ )
274+ for _ in range (25 ):
275+ out = bic .graph .lifted_multicut .lifted_edges_from_node_labels (
276+ rag , labels , graph_depth = 3 , mode = "all" # default: multi-threaded
277+ )
278+ assert out .tolist () == reference .tolist ()
0 commit comments