From ed1dea2639b1191421de3986483aedcc14067a12 Mon Sep 17 00:00:00 2001 From: godosa Date: Wed, 7 Oct 2026 00:01:14 +0200 Subject: worldhistory: initial public history --- tests/test_events.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/test_events.py (limited to 'tests/test_events.py') diff --git a/tests/test_events.py b/tests/test_events.py new file mode 100644 index 0000000..89ef9e5 --- /dev/null +++ b/tests/test_events.py @@ -0,0 +1,85 @@ +import unittest + +import numpy as np + +from tests.helpers import fields, line_world, make_history, make_race +from worldhistory.events import apply_event, cull, era_switch, seed +from worldhistory.regions import Regions +from worldhistory.state import new_state + + +class EventTest(unittest.TestCase): + def test_seed_totals_and_fringe(self): + w = line_world(200) + r = make_race(seed={"clusters": 20, "heads": 100}) + q = np.linspace(0, 1, 200)[None] + st = new_state(1, 200, np.zeros((1, 6)), seed=0) + placed = seed(st, w, [r], q, np.ones((1, 200), bool), 0.25, np.random.default_rng(0)) + self.assertAlmostEqual(float(st.P.sum()), 2000.0) + cells = placed["a"] + fringe_cells = [c for c in cells if 0.05 < q[0, c] < 0.3] + self.assertGreaterEqual(len(fringe_cells), 5) # 25 % of 20 on the fringe + self.assertEqual(float(st.P[0, 0]), 0.0) # q = 0: never + + def test_seed_realm_land_skips_sea(self): + ocean = np.arange(200) >= 100 # right half is sea, and the best q + w = line_world(200, ocean=ocean) + r = make_race(seed={"clusters": 20, "heads": 100, "realm": "land"}, habitat={"realm": "both"}) + q = np.linspace(0.1, 1, 200)[None] + st = new_state(1, 200, np.zeros((1, 6)), seed=0) + placed = seed(st, w, [r], q, np.ones((1, 200), bool), 0.25, np.random.default_rng(0)) + self.assertTrue(placed["a"]) + self.assertTrue(all(c < 100 for c in placed["a"])) + + def test_cull_exact_and_by_race(self): + rs = [make_race("a"), make_race("b")] + st = new_state(2, 3, np.zeros((2, 6)), seed=0) + st.P[:] = 100.0 + cull(st, rs, np.array([True, True, False]), 0.6, {"b": 0.8}) + np.testing.assert_allclose(st.P, [[40, 40, 100], [20, 20, 100]]) + + def test_cull_noise(self): + w = line_world(500) + st = new_state(1, 500, np.zeros((1, 6)), seed=0) + st.P[:] = 100.0 + cull(st, [make_race()], np.ones(500, bool), 0.3, {}, noise=w.noise(1), amp=0.15) + self.assertAlmostEqual(float(st.P.mean()), 70.0, delta=2.0) + self.assertGreater(float(st.P.std()), 5.0) + + def test_era_switch_drowns_land_races(self): + w = line_world(3) + w.eras["late"] = fields(3, ocean=[False, True, True]) + land, sea = make_race("l"), make_race("s", habitat={"realm": "sea", "terms": [{"p": "sea", "w": 1}]}) + st = new_state(2, 3, np.zeros((2, 6)), seed=0) + st.P[0] = 10.0 + st.P[1, 2] = 5.0 + era_switch(st, w, [land, sea], "late") + np.testing.assert_array_equal(st.P[0], [10, 0, 0]) + np.testing.assert_array_equal(st.P[1], [0, 0, 5]) + self.assertEqual(w.era, "late") + + def test_targeted_seed_places_one_race_in_region(self): + w = line_world(200) # lon 0 .. ~178°, 0.9° apart + h = make_history(regions={"west": {"kind": "box", "lat": [-1, 1], "lon": [-1, 45]}}, + event=[{"year": 0, "kind": "seed", "race": "b", "region": "west", "clusters": 3, + "heads": 50}]) + rs = [make_race("a", seed={"clusters": 5, "heads": 100}), make_race("b", seed={"clusters": 5, "heads": 100})] + q = np.ones((2, 200)) * 0.5 + st = new_state(2, 200, np.zeros((2, 6)), seed=0) + log = apply_event(st, w, rs, h.events[0], Regions(w, h.regions), q, np.ones((2, 200), bool), h, 0) + self.assertEqual(float(st.P[0].sum()), 0.0) # race a: untouched + self.assertAlmostEqual(float(st.P[1].sum()), 150.0) # 3 clusters × 50 + west = np.flatnonzero(w.lon <= 45) + self.assertTrue(set(np.flatnonzero(st.P[1])) <= set(west)) + self.assertEqual(len(log["placed"]["b"]), 3) + + def test_apply_event_log(self): + w = line_world(2) + h = make_history(regions={"west": {"kind": "box", "lat": [-1, 1], "lon": [-1, 0.5]}}, + event=[{"year": 20, "kind": "die_off", "region": "west", "share": 0.9}]) + st = new_state(1, 2, np.zeros((1, 6)), seed=0) + st.P[:] = 100.0 + log = apply_event(st, w, [make_race()], h.events[0], Regions(w, h.regions), None, None, h, 0) + np.testing.assert_allclose(st.P[0], [10, 100]) + self.assertEqual(log["before"]["a"], 200.0) + self.assertEqual(log["after"]["a"], 110.0) -- cgit