SPB Git

spb/wp29_uqo

Public
3.9 KB · 86 lines python
1"""F5-conf-04: VFI vs closed form, optimal growth with log utility.2Run from workspace root: ~/wp29/venv/bin/python out/analysis.py3Reads only data/model.csv; writes out/results.json. Deterministic, no randomness."""4import json, os5import numpy as np6import pandas as pd78ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))9df = pd.read_csv(os.path.join(ROOT, "data", "model.csv"))10p = dict(zip(df["parameter"], df["value"]))11alpha, beta = float(p["alpha"]), float(p["beta"])12y_min, y_max, N = float(p["y_min"]), float(p["y_max"]), int(float(p["grid_points"]))13tol = float(p["vfi_tolerance"])14evals = [float(p["eval_y_1"]), float(p["eval_y_2"]), float(p["eval_y_3"])]15assert p["grid_spacing"].strip().lower() == "log"16data_issues = []1718# ---- Closed form (guess-and-verify V = A + B ln y) ----19ab = alpha * beta20B = 1.0 / (1.0 - ab)21A = (np.log(1.0 - ab) + (ab / (1.0 - ab)) * np.log(ab)) / (1.0 - beta)22c_closed = lambda y: (1.0 - ab) * np.asarray(y)23V_closed = lambda y: A + B * np.log(np.asarray(y))24savings_rate = ab  # baseline quantity (y-c)/y2526# ---- VFI on the prescribed log grid; choice = next-period output y' on the same grid ----27y = np.exp(np.linspace(np.log(y_min), np.log(y_max), N))28k_needed = y ** (1.0 / alpha)                 # capital (savings) needed to reach y'_j29C = y[:, None] - k_needed[None, :]            # consumption for state i, choice j30feasible = C > 031U = np.where(feasible, np.log(np.where(feasible, C, 1.0)), -np.inf)32V = np.zeros(N)33n_iter, sup = 0, np.inf34while sup >= tol:35    TV = np.max(U + beta * V[None, :], axis=1)36    sup = float(np.max(np.abs(TV - V)))37    V = TV38    n_iter += 139    if n_iter > 100000:40        raise RuntimeError("VFI did not converge")41pol = np.argmax(U + beta * V[None, :], axis=1)   # policy for the converged V42c_grid = y - k_needed[pol]43hits_bound = bool(np.any(pol == 0) or np.any(pol == N - 1))44if hits_bound:45    data_issues.append({"issue": "VFI policy hits grid boundary", "handling": "reported; results may be truncated"})4647c_num = [float(np.interp(e, y, c_grid)) for e in evals]          # linear in y48V_num1 = float(np.interp(np.log(evals[1]), np.log(y), V))       # linear in ln y49cc = [float(c_closed(e)) for e in evals]50data_issues.append({"issue": "Evaluation points y=0.5,1,2 are not grid nodes",51                    "handling": "VFI policy linearly interpolated in y, value function linearly interpolated in ln y between adjacent nodes (allowed by TASK.md)"})5253res = {54    "task_id": "F5-conf-04",55    "c_closed_y05": cc[0], "c_closed_y1": cc[1], "c_closed_y2": cc[2],56    "c_num_y05": c_num[0], "c_num_y1": c_num[1], "c_num_y2": c_num[2],57    "max_abs_error_policy": float(max(abs(a - b) for a, b in zip(c_num, cc))),58    "value_closed_y1": float(V_closed(1.0)),59    "value_num_y1": V_num1,60    "savings_rate_closed_form": float(savings_rate),61    "contraction_modulus": beta,62    "grid_points_used": int(N),63    "n_iterations": int(n_iter),64    "final_sup_change": sup,65    "feasibility": "complete",66    "feasibility_reason": None,67    "data_issues": data_issues,68    "n_input_rows": {"model.csv": int(len(df))},69    "n_analysed": int(N),70    "random_seed": None,71    # supplementary diagnostics (not required keys)72    "diag_closed_form_A": float(A), "diag_closed_form_B": float(B),73    "diag_max_abs_policy_error_grid": float(np.max(np.abs(c_grid - c_closed(y)))),74    "diag_max_abs_value_error_grid": float(np.max(np.abs(V - V_closed(y)))),75    "diag_vfi_error_bound_tol": float(beta * tol / (1 - beta)),76    "diag_log_grid_step": float(np.log(y[1] / y[0])),77    "diag_policy_hits_grid_boundary": hits_bound,78    "diag_policy_index_range": [int(pol.min()), int(pol.max())],79    "diag_eval_points": evals,80}81with open(os.path.join(ROOT, "out", "results.json"), "w") as f:82    json.dump(res, f, indent=2)83for k in ["c_closed_y05","c_num_y05","c_closed_y1","c_num_y1","c_closed_y2","c_num_y2",84          "max_abs_error_policy","value_closed_y1","value_num_y1","n_iterations","final_sup_change"]:85    print(k, res[k])86
Files · main
Menu

Theme