1"""Task-based production block: zero-AI limit, uniqueness of the automation threshold, Euler's theorem, shares."""2import numpy as np3import pytest4from hypothesis import given, settings, strategies as st56from age.economy.tasks import TaskTech789def test_zero_ai_limit_is_cobb_douglas():10 t = TaskTech(alpha=0.33)11 K, L = 3.0, 1.012 Y = t.output(0.0, K, 0.0, L)13 assert np.isclose(Y, K ** 0.33 * L ** 0.67)14 pr = t.prices(0.0, K, 0.0, L)15 assert pr['iota'] == 0.0 and pr['pQ'] == 0.016 assert np.isclose(pr['share_L'], 0.67)171819@settings(max_examples=40, deadline=None)20@given(QP=st.floats(1e-4, 50.0), L=st.floats(0.2, 3.0), psi1=st.floats(0.5, 6.0))21def test_threshold_unique_and_monotone(QP, L, psi1):22 t = TaskTech(psi1=psi1, iota_bar=0.9)23 i1 = t.iota_of(QP, L)24 i2 = t.iota_of(QP * 1.5, L)25 assert 0.0 < i1 <= 0.926 assert i2 >= i1 - 1e-12 # more compute -> more automation (capped)27 if i1 < 0.9 - 1e-9:28 # interior: threshold condition psi(iota) = iota/(1-iota) L/QP holds29 assert np.isclose(t.psi(i1), i1 / (1 - i1) * L / QP, rtol=1e-8)303132def test_euler_theorem_and_shares():33 """Factor payments exhaust output (CRS in K, L, QP): RK K + w L + pQ QP = Y."""34 t = TaskTech(alpha=0.33, iota_bar=0.6)35 K, L, QP = 4.0, 1.0, 0.736 pr = t.prices(0.1, K, QP, L)37 total = pr['RK'] * K + pr['w'] * L + pr['pQ'] * QP38 assert np.isclose(total, pr['Y'], rtol=1e-10)39 assert np.isclose(pr['share_K'] + pr['share_Q'] + pr['share_L'], 1.0)404142def test_marginal_products_numerically():43 t = TaskTech(alpha=0.33, iota_bar=0.9)44 K, L, QP, z = 4.0, 1.0, 0.5, 0.045 pr = t.prices(z, K, QP, L)46 h = 1e-647 dYdK = (t.output(z, K + h, QP, L) - t.output(z, K - h, QP, L)) / (2 * h)48 dYdL = (t.output(z, K, QP, L + h) - t.output(z, K, QP, L - h)) / (2 * h)49 dYdQ = (t.output(z, K, QP + h, L) - t.output(z, K, QP - h, L)) / (2 * h)50 # envelope: iota re-optimised inside output(); marginal products equal competitive prices51 assert np.isclose(dYdK, pr['RK'], rtol=1e-5)52 assert np.isclose(dYdL, pr['w'], rtol=1e-4)53 assert np.isclose(dYdQ, pr['pQ'], rtol=1e-4)545556def test_compute_demand_inverts_prices():57 t = TaskTech(alpha=0.33, iota_bar=0.9)58 K, L, QP, z = 4.0, 1.0, 0.5, 0.059 pr = t.prices(z, K, QP, L)60 QP_back = t.production_compute_demand(pr['pQ'], pr['w'], L, z, K)61 assert np.isclose(QP_back, QP, rtol=1e-6)62