"""Unit tests for src.utils.random_utils -- the determinism backbone of the whole pipeline.""" from __future__ import annotations import numpy as np from src.config.schema import Range from src.utils.random_utils import SeedManager, derive_seed, resolve_scalar_or_range def test_derive_seed_is_deterministic(): assert derive_seed(42, 1, "placement") == derive_seed(42, 1, "placement") def test_derive_seed_varies_with_each_part(): base = derive_seed(42, 1, "placement") assert derive_seed(42, 2, "placement") != base assert derive_seed(42, 1, "rendering") != base assert derive_seed(43, 1, "placement") != base def test_derive_seed_in_valid_range(): seed = derive_seed(0, 999999, "x") assert 0 <= seed < 2**32 def test_seed_manager_same_sample_same_stage_is_deterministic(): sm1 = SeedManager(master_seed=7, sample_index=3) sm2 = SeedManager(master_seed=7, sample_index=3) draws1 = sm1.numpy_rng("placement").uniform(0, 1, size=10) draws2 = sm2.numpy_rng("placement").uniform(0, 1, size=10) assert np.allclose(draws1, draws2) def test_seed_manager_different_stages_are_independent(): sm = SeedManager(master_seed=7, sample_index=3) a = sm.numpy_rng("placement").uniform(0, 1, size=5) b = sm.numpy_rng("rendering").uniform(0, 1, size=5) assert not np.allclose(a, b) def test_seed_manager_different_samples_are_independent(): a = SeedManager(master_seed=7, sample_index=1).numpy_rng("placement").uniform(0, 1, size=5) b = SeedManager(master_seed=7, sample_index=2).numpy_rng("placement").uniform(0, 1, size=5) assert not np.allclose(a, b) def test_resolve_scalar_or_range_with_scalar(): rng = np.random.default_rng(0) assert resolve_scalar_or_range(0.5, rng) == 0.5 def test_resolve_scalar_or_range_with_range_stays_in_bounds(): rng = np.random.default_rng(0) r = Range(min=-3.0, max=5.0) for _ in range(200): v = resolve_scalar_or_range(r, rng) assert -3.0 <= v <= 5.0 def test_resolve_scalar_or_range_with_dict_range(): rng = np.random.default_rng(0) v = resolve_scalar_or_range({"min": 1.0, "max": 1.0}, rng) assert v == 1.0 def test_resolve_scalar_or_range_degenerate_range_returns_bound(): rng = np.random.default_rng(0) r = Range(min=2.0, max=2.0) assert resolve_scalar_or_range(r, rng) == 2.0