Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 14913@bnt-lap001 Assistant-Session: add7ef69-b901-4756-9a67-34cf1125d96f
97 lines
5.2 KiB
Python
97 lines
5.2 KiB
Python
"""Tests for the coupled world model (ASSEMBLY-WP-0011-T03, models/CrossBorder.md § 3.5)."""
|
|
|
|
import unittest
|
|
|
|
import gadm04 as g
|
|
import world as w
|
|
|
|
T = 20
|
|
|
|
|
|
class TestWorld(unittest.TestCase):
|
|
def test_uncoupled_equals_closed(self):
|
|
closed = g.simulate(T=T)
|
|
rows = w.simulate_world({"A": w.make(), "B": w.make({"m": 0.7})}, T=T)
|
|
for r1, r2 in zip(closed, rows["A"]):
|
|
for k in ("Ko", "P", "VFAC", "G", "A"):
|
|
self.assertEqual(r1[k], r2[k], k)
|
|
other = g.simulate({"m": 0.7}, T=T)
|
|
self.assertEqual(other[-1]["VFAC"], rows["B"][-1]["VFAC"])
|
|
|
|
def test_symmetric_identical_jurisdictions_stay_closed(self):
|
|
f = {c: 0.5 for c in w.COUPLED}
|
|
rows = w.simulate_world({"A": w.make(home="B", f=f), "B": w.make(home="A", f=f)}, T=T)
|
|
closed = g.simulate(T=T)
|
|
for k in ("Ko", "P", "VFAC"):
|
|
self.assertAlmostEqual(rows["A"][-1][k], rows["B"][-1][k], places=12)
|
|
self.assertAlmostEqual(rows["A"][-1][k], closed[-1][k], places=9)
|
|
|
|
def test_full_foreign_share_tracks_home_channel(self):
|
|
f = {c: 1.0 for c in w.COUPLED}
|
|
rows = w.simulate_world({"home": w.make({"m": 0.1}), "host": w.make({"m": 0.9}, home="home", f=f)}, T=T)
|
|
for c in w.COUPLED:
|
|
if c == "Plin":
|
|
continue # host learns from imported lineages, so its Ko (a Plin driver) differs
|
|
self.assertGreater(abs(rows["host"][-1][c] - g.simulate({"m": 0.9}, T=T)[-1][c]), 0.0)
|
|
# the operator part follows the home's channel equation at the home's state
|
|
self.assertAlmostEqual(rows["host"][-1]["OPmem"], rows["home"][-1]["Pmem"], places=2)
|
|
|
|
def test_host_access_rule_lowers_host_only(self):
|
|
f = {c: 1.0 for c in w.COUPLED}
|
|
base = w.simulate_world({"home": w.make(), "host": w.make(home="home", f=f)}, T=T)
|
|
rule = w.simulate_world({"home": w.make(), "host": w.make(home="home", f=f, access={"Pd": 0.3})}, T=T)
|
|
self.assertLess(rule["host"][-1]["Pd"], base["host"][-1]["Pd"])
|
|
self.assertAlmostEqual(rule["home"][-1]["Pd"], base["home"][-1]["Pd"], places=12)
|
|
|
|
def test_spillover_reaches_home(self):
|
|
f = {c: 1.0 for c in w.COUPLED}
|
|
world = {"home": w.make(), "host": w.make(home="home", f=f, access={"Pd": 0.3})}
|
|
no = w.simulate_world(world, T=T)
|
|
yes = w.simulate_world(world, T=T, sigma={"Pd": 0.5})
|
|
self.assertLess(yes["home"][-1]["Pd"], no["home"][-1]["Pd"])
|
|
|
|
def test_frontier_access_raises_laggard_adoption(self):
|
|
lead = w.make({"perm": 1.5})
|
|
lag0 = w.simulate_world({"lead": lead, "lag": w.make({"perm": 0.6})}, T=T)
|
|
lag1 = w.simulate_world({"lead": lead, "lag": w.make({"perm": 0.6}, kappa=0.8)}, T=T)
|
|
self.assertGreater(lag1["lag"][-1]["Ko"], lag0["lag"][-1]["Ko"])
|
|
self.assertEqual(lag1["lead"][-1]["Ko"], lag0["lead"][-1]["Ko"])
|
|
|
|
def test_local_in_context_reproduces_global(self):
|
|
f = {c: 1.0 for c in w.COUPLED}
|
|
glob = w.simulate_world({"home": w.make({"m": 0.2}), "host": w.make({"m": 0.7}, home="home", f=f, kappa=0.5)},
|
|
T=T, record_every=1)
|
|
local = w.simulate_world({"home": w.context(glob["home"], {"m": 0.2}),
|
|
"host": w.make({"m": 0.7}, home="home", f=f, kappa=0.5)}, T=T, record_every=1)
|
|
for k in ("Ko", "P", "Pd", "VFAC"):
|
|
self.assertAlmostEqual(local["host"][-1][k], glob["host"][-1][k], places=9, msg=k)
|
|
|
|
def test_lineage_portability_lowers_host_lineage_concentration(self):
|
|
f = {c: 1.0 for c in w.COUPLED}
|
|
home = w.make({"L": 0.1, "lin_open": 0.1})
|
|
base = w.simulate_world({"home": home, "host": w.make({"L": 0.8, "lin_open": 0.8}, home="home", f=f)}, T=T)
|
|
port = w.simulate_world({"home": home, "host": w.make({"L": 0.8, "lin_open": 0.8}, home="home", f=f, port=0.5)}, T=T)
|
|
self.assertLess(port["host"][-1]["Plin"], base["host"][-1]["Plin"])
|
|
self.assertAlmostEqual(port["home"][-1]["Plin"], base["home"][-1]["Plin"], places=12)
|
|
|
|
def test_endogenous_shares_rest_at_start_and_fall_with_domestic_alternatives(self):
|
|
f = {c: 0.8 for c in w.COUPLED}
|
|
endo = {"lam": 0.5, "gamma": 0.0, "delta": 2.0}
|
|
still = w.simulate_world({"home": w.make(), "host": w.make(home="home", f=f, endo=endo)}, T=1, record_every=1)
|
|
self.assertAlmostEqual(still["host"][1]["f_Pd"], 0.8, places=3) # near rest at start
|
|
push = w.simulate_world({"home": w.make(), "host": w.make({"IX": 0.3}, home="home", f=f, endo=endo)}, T=T)
|
|
fixed = w.simulate_world({"home": w.make(), "host": w.make({"IX": 0.3}, home="home", f=f)}, T=T)
|
|
self.assertLess(push["host"][-1]["f_Pd"], 0.8)
|
|
self.assertEqual(fixed["host"][-1]["f_Pd"], 0.8)
|
|
|
|
def test_split_hook_keeps_measured_level(self):
|
|
f = {c: 0.8 for c in w.COUPLED}
|
|
j = w.make(home="home", f=f, d0={"Pd": 0.3})
|
|
self.assertAlmostEqual(w.mixed(j)["Pd"], w.make(home="home", f=f)["s"]["Pd"], places=12)
|
|
self.assertEqual(j["s"]["Pd"], 0.3)
|
|
d, _a, _sm = w.step_derivatives({"home": w.make(), "host": j})["host"]
|
|
self.assertLess(abs(d["Pd"]), 1e-3) # the domestic segment starts at rest
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|