feat(lib): add sample_duration, truncnorm_sample (no scipy)
This commit is contained in:
@@ -104,3 +104,40 @@ def test_build_timestamps_total_close_to_target() -> None:
|
||||
ts = build_timestamps(log_dt, total_duration_ms=300.0)
|
||||
# Last timestamp should be roughly total - one slot
|
||||
assert abs(ts[-1] - 270) < 60 # tolerant of clipping
|
||||
|
||||
|
||||
from ai_mouse._postprocess import sample_duration, truncnorm_sample
|
||||
|
||||
|
||||
def test_truncnorm_sample_within_bounds() -> None:
|
||||
rng = np.random.default_rng(0)
|
||||
samples = [
|
||||
truncnorm_sample(80.0, 30.0, 20.0, 300.0, rng) for _ in range(500)
|
||||
]
|
||||
arr = np.array(samples)
|
||||
assert arr.min() >= 20.0
|
||||
assert arr.max() <= 300.0
|
||||
# Mean roughly close to mu
|
||||
assert abs(arr.mean() - 80.0) < 5.0
|
||||
|
||||
|
||||
def test_truncnorm_sample_far_outside_falls_back_to_clip() -> None:
|
||||
rng = np.random.default_rng(0)
|
||||
# mu far outside [low, high] — rejection will fail
|
||||
v = truncnorm_sample(mu=1000.0, sigma=1.0, low=20.0, high=30.0, rng=rng)
|
||||
assert 20.0 <= v <= 30.0
|
||||
|
||||
|
||||
def test_sample_duration_uses_correct_bin() -> None:
|
||||
dist_dict = {
|
||||
"bins": [0, 50, 100, 200, 400, 600, 800, 1200, float("inf")],
|
||||
"params": [
|
||||
{"mu_log": 4.0, "sigma_log": 0.01}, # bin 0: dist < 50
|
||||
{"mu_log": 5.0, "sigma_log": 0.01}, # bin 1: 50 <= dist < 100
|
||||
{"mu_log": 6.0, "sigma_log": 0.01}, # bin 2: 100 <= dist < 200
|
||||
] + [{"mu_log": 7.0, "sigma_log": 0.01}] * 5,
|
||||
}
|
||||
rng = np.random.default_rng(0)
|
||||
v = sample_duration(dist_dict, 150.0, rng)
|
||||
# exp(6) ~ 403, with tiny sigma we should land near there
|
||||
assert 350 < v < 460
|
||||
|
||||
Reference in New Issue
Block a user