1"""Model B: zero-AI Aiyagari benchmark, market clearing, distribution mass, delegation monotone in wealth."""2import numpy as np3import pytest45from age.equilibrium.aiyagari import EconomyB, HAParams, rouwenhorst678def test_rouwenhorst_moments():9 g, P = rouwenhorst(7, 0.96, 0.2)10 pi = np.linalg.matrix_power(P, 2000)[0]11 assert np.isclose(pi @ g, 0.0, atol=1e-8)12 assert np.isclose(np.sqrt(pi @ g ** 2), 0.2 / np.sqrt(1 - 0.96 ** 2), rtol=1e-6)13 assert np.allclose(P.sum(axis=1), 1.0)141516@pytest.fixture(scope='module')17def zero_ai():18 p = HAParams(n_a=100, delegation_on=False, KQ0=0.0, m_H=0.0, sigma_rH=1e-6, sigma_rA=1e-6, n_gh=3)19 e = EconomyB(p)20 return e, e.solve(tol=1e-4)212223def test_zero_ai_clears_and_is_sane(zero_ai):24 e, res = zero_ai25 assert 0.0 < res['r'] < 1 / e.p.beta - 1 # r below the complete-markets rate (precautionary saving)26 assert np.isclose(e.hh.lam.sum(), 1.0, atol=1e-8)27 agg = e.hh.aggregates()28 assert abs(agg['A'] - res['K']) < 1e-2 * res['K'] # capital market clears within tolerance29 assert res['D'] == 0.0 and res['iota'] == 0.030 assert 0.3 < res['gini'] < 0.931 assert np.isclose(res['shares']['labor'] + res['shares']['capital'] + res['shares']['compute'], 1.0, atol=1e-6)323334def test_goods_market_identity(zero_ai):35 e, res = zero_ai36 # C + delta K + mistakes + fees-as-compute = Y (fees are transfers to compute owners here: zero AI => 0)37 assert np.isclose(res['C'] + e.p.delta * res['K'] + res['mistakes'], res['Y'], rtol=2e-2)383940def test_delegation_increases_with_wealth():41 p = HAParams(n_a=100, delegation_on=True, KQ0=0.0, m_H=0.01, sigma_rH=0.04, sigma_rA=0.01, phi0=0.02, phi1=0.002,42 n_gh=3)43 e = EconomyB(p)44 e.excess_assets(0.02)45 ws = e.hh.wealth_stats()46 d = ws['deleg_by_decile']47 assert 0 < e.last['agg']['D'] < 148 assert d[-1] >= d[0] # top decile delegates at least as much as the bottom49 assert np.corrcoef(np.arange(10), d)[0, 1] > 0.550