File size: 2,357 Bytes
1a12965
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""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