assembly-economics/simulations/gadm02/test_world.py
tegwick 824187da3b ASSEMBLY-WP-0016-T02: endogenous foreign shares and split calibration hook (domestic segment with own counters); share-shifting levers effective but modest; CrossBorder § 8
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
2026-10-13 22:59:32 +02:00

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()