1"""F5-conf-01: competitive equilibrium of a 2x2 Cobb-Douglas exchange economy.2Run from workspace root: ~/wp29/venv/bin/python out/analysis.py3Reads only data/, writes out/results.json and out/exclusions.csv deterministically."""4import json, os5import numpy as np6import pandas as pd7from scipy.optimize import brentq89ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))10D = os.path.join(ROOT, "data"); O = os.path.join(ROOT, "out")1112end = pd.read_csv(os.path.join(D, "endowments.csv"))13par = pd.read_csv(os.path.join(D, "parameters.csv"))14n_rows = {"endowments.csv": int(len(end)), "parameters.csv": int(len(par))}15P = dict(zip(par["parameter"], par["value"].astype(float)))16issues = []1718# --- validation of inputs19assert set(end["agent"]) == {"A", "B"} and len(end) == 2 and not end.duplicated("agent").any()20assert end[["good1", "good2"]].notna().all().all() and (end[["good1", "good2"]] > 0).all().all()21aA, aB = P["alpha_A"], P["alpha_B"]22assert 0 < aA < 1 and 0 < aB < 123e = end.set_index("agent")[["good1", "good2"]].astype(float)24e1 = {i: e.loc[i, "good1"] for i in "AB"}; e2 = {i: e.loc[i, "good2"] for i in "AB"}25alpha = {"A": aA, "B": aB}2627agg1_rows, agg2_rows = e1["A"] + e1["B"], e2["A"] + e2["B"]28agg1_sheet, agg2_sheet = P["aggregate_endowment_good1"], P["aggregate_endowment_good2"]29if not np.isclose(agg1_rows, agg1_sheet):30 issues.append({31 "issue": (f"parameters.csv aggregate_endowment_good1 = {agg1_sheet:g} is inconsistent with the sum of "32 f"individual endowments in endowments.csv ({e1['A']:g} + {e1['B']:g} = {agg1_rows:g})."),33 "handling": (f"Used the sum of individual endowments ({agg1_rows:g}) as the aggregate endowment of good 1, "34 "because the individual endowments are the primary data and also determine agents' wealth; "35 "using the summary-sheet value would make the market-clearing condition inconsistent with the "36 "budget constraints (Walras' law would fail). The summary value was not used in any computation "37 "other than this diagnostic.")})38if not np.isclose(agg2_rows, agg2_sheet):39 issues.append({"issue": f"aggregate_endowment_good2 sheet value {agg2_sheet:g} != sum of rows {agg2_rows:g}",40 "handling": "Used sum of individual endowments."})41agg1, agg2 = agg1_rows, agg2_rows4243# --- demands (p2 = 1)44def demand(i, p):45 w = p * e1[i] + e2[i]46 return alpha[i] * w / p, (1 - alpha[i]) * w4748def z1(p):49 return sum(demand(i, p)[0] for i in "AB") - agg15051def z2(p):52 return sum(demand(i, p)[1] for i in "AB") - agg25354# --- closed form: p = sum alpha_i e2_i / sum (1-alpha_i) e1_i55p_cf = sum(alpha[i] * e2[i] for i in "AB") / sum((1 - alpha[i]) * e1[i] for i in "AB")5657# --- independent numerical root of z1(p) = 0 (Brent on a wide bracket; closed form not used)58lo, hi = 1e-6, 1e659assert z1(lo) > 0 and z1(hi) < 060p_num = brentq(z1, lo, hi, xtol=1e-14, rtol=1e-15, maxiter=500)6162x = {i: demand(i, p_cf) for i in "AB"}63ed1, ed2 = z1(p_cf), z2(p_cf)64walras = p_cf * ed1 + ed265# Walras' law should hold at arbitrary prices too: check on a grid (diagnostic)66grid = np.logspace(-2, 2, 41)67walras_grid_max = float(max(abs(p * z1(p) + z2(p)) for p in grid))68# diagnostic: excess demand of good 1 if the (inconsistent) summary-sheet aggregate were used69ed1_vs_sheet = float(sum(x[i][0] for i in "AB") - agg1_sheet)7071res = {72 "task_id": "F5-conf-01",73 "price_ratio_p1_over_p2": float(p_cf),74 "x1_A": float(x["A"][0]), "x2_A": float(x["A"][1]),75 "x1_B": float(x["B"][0]), "x2_B": float(x["B"][1]),76 "excess_demand_good1": float(ed1),77 "excess_demand_good2": float(ed2),78 "walras_law_residual": float(walras),79 "walras_law_residual_max_abs_on_price_grid": walras_grid_max,80 "aggregate_endowment_good1": float(agg1),81 "aggregate_endowment_good2": float(agg2),82 "aggregate_endowment_good1_summary_sheet": float(agg1_sheet),83 "excess_demand_good1_vs_summary_sheet_aggregate": ed1_vs_sheet,84 "price_ratio_numerical": float(p_num),85 "price_abs_diff_closed_vs_numerical": float(abs(p_cf - p_num)),86 "wealth_A": float(p_cf * e1["A"] + e2["A"]), "wealth_B": float(p_cf * e1["B"] + e2["B"]),87 "feasibility": "complete",88 "feasibility_reason": None,89 "data_issues": issues,90 "n_input_rows": n_rows,91 "n_analysed": 2,92 "random_seed": None,93}94with open(os.path.join(O, "results.json"), "w") as f:95 json.dump(res, f, indent=2)96pd.DataFrame([{"step": 1, "rule": "keep agents A and B with finite positive endowments", "n_before": n_rows["endowments.csv"],97 "n_after": 2, "n_removed": n_rows["endowments.csv"] - 2,98 "rationale": "no rows removed; both agents enter the equilibrium"}]).to_csv(os.path.join(O, "exclusions.csv"), index=False)99print(json.dumps({k: res[k] for k in ["price_ratio_p1_over_p2", "price_ratio_numerical", "x1_A", "x2_A", "x1_B", "x2_B",100 "excess_demand_good1", "walras_law_residual"]}, indent=1))101