@@ -313,3 +313,52 @@ def test_pca_fit_exclude_samples(fixture, api: AnophelesPca):
313313 len (pca_df .query (f"sample_id in { exclude_samples } and not pca_fit" ))
314314 == n_samples_excluded
315315 )
316+
317+
318+ # --- _jitter() determinism unit tests ---
319+
320+
321+ def test_jitter_determinism ():
322+ """_jitter with the same seed must produce identical results."""
323+ from malariagen_data .util import _jitter
324+
325+ a = np .array ([1.0 , 2.0 , 3.0 , 4.0 , 5.0 ])
326+ fraction = 0.1
327+
328+ rng1 = np .random .default_rng (seed = 42 )
329+ result1 = _jitter (a , fraction , random_state = rng1 )
330+
331+ rng2 = np .random .default_rng (seed = 42 )
332+ result2 = _jitter (a , fraction , random_state = rng2 )
333+
334+ np .testing .assert_array_equal (result1 , result2 )
335+
336+
337+ def test_jitter_different_seeds ():
338+ """_jitter with different seeds must produce different results."""
339+ from malariagen_data .util import _jitter
340+
341+ a = np .array ([1.0 , 2.0 , 3.0 , 4.0 , 5.0 ])
342+ fraction = 0.1
343+
344+ rng1 = np .random .default_rng (seed = 42 )
345+ result1 = _jitter (a , fraction , random_state = rng1 )
346+
347+ rng2 = np .random .default_rng (seed = 99 )
348+ result2 = _jitter (a , fraction , random_state = rng2 )
349+
350+ assert not np .array_equal (result1 , result2 )
351+
352+
353+ def test_jitter_no_global_rng_side_effect ():
354+ """_jitter with explicit random_state must not alter global RNG state."""
355+ from malariagen_data .util import _jitter
356+
357+ np .random .seed (0 )
358+ state_before = np .random .get_state ()[1 ].copy ()
359+
360+ rng = np .random .default_rng (seed = 42 )
361+ _jitter (np .array ([1.0 , 2.0 , 3.0 ]), 0.1 , random_state = rng )
362+
363+ state_after = np .random .get_state ()[1 ].copy ()
364+ np .testing .assert_array_equal (state_before , state_after )
0 commit comments