Skip to content

Commit 9b40a3b

Browse files
authored
Upload full repository structure (NDA-safe math & econ evaluation)
0 parents  commit 9b40a3b

60 files changed

Lines changed: 1432 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

LICENSE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
MIT License
2+
3+
Copyright (c) 2025

README.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Math + Econ Reasoning Portfolio (NDA-safe excerpts)
2+
3+
This repository contains **carefully selected, NDA-safe excerpts** from a larger body of **math- and economics-based analytical work** used to design, evaluate, and verify **LLM reasoning and numerical reliability**.
4+
5+
The materials here focus on the **final verification layer** of much broader analyses:
6+
- reduced-form problem statements
7+
- distilled numerical cores
8+
- deterministic validation logic
9+
10+
The original tasks were typically **more complex, data-driven, and multi-stage**, but are presented here in **simplified, synthetic form** to remain fully public and NDA-compliant.
11+
12+
This is best viewed as a **portfolio of evaluation artefacts** rather than a full reproduction of the underlying research pipelines.
13+
14+
---
15+
16+
## What this repo demonstrates
17+
18+
- **Non-trivial numerical methods**
19+
(bisection / root-finding, verification inequalities, Monte Carlo sanity checks)
20+
21+
- **Reproducible reference solutions**
22+
with explicit tolerances and deterministic outputs
23+
24+
- **Answer validation & scoring logic**
25+
similar to LLM evaluation / grading pipelines
26+
27+
- **Failure-mode awareness**
28+
(bounds, monotonicity assumptions, bracketing errors, model misspecification)
29+
30+
- **Clean Python engineering**
31+
(tests, CI, no side effects on import, CLI + JSON outputs)
32+
33+
---
34+
35+
## Important context (NDA-safe clarification)
36+
37+
The problems in this repository are **not full research problems** and **not client deliverables**.
38+
39+
They are:
40+
- **condensed representations** of larger analytical tasks
41+
- using **synthetic or normalized parameters**
42+
- stripped of proprietary data, domain specifics, and contextual complexity
43+
44+
In practice, the original tasks:
45+
- involved richer stochastic structure or real datasets
46+
- required additional constraints, diagnostics, and robustness checks
47+
- were embedded in broader modeling or evaluation workflows
48+
49+
What you see here corresponds to the **final reasoning and verification step** — the part most relevant for assessing **LLM numerical reasoning, correctness, and failure behavior**.
50+
51+
---
52+
53+
## Repository structure
54+
55+
- `problems/` — problem statements + failure modes
56+
- `src/econ_math_portfolio/models/` — model implementations (no code runs on import)
57+
- `validators/` — validators calling model code
58+
- `originals/` — original standalone scripts kept for transparency (not imported)
59+
- `rubrics/` — scoring rules inspired by LLM evaluation setups
60+
- `tests/` — pytest
61+
- `.github/workflows/ci.yml` — CI (Python 3.10–3.12)
62+
63+
---
64+
65+
## Quickstart
66+
67+
```bash
68+
python -m venv .venv
69+
source .venv/bin/activate
70+
pip install -e ".[dev]"
71+
pytest
72+
python -m econ_math_portfolio list
73+
```
74+
75+
---
76+
77+
## CLI usage
78+
79+
```bash
80+
python -m econ_math_portfolio reference credit_var_quantile
81+
python -m econ_math_portfolio validate cpi_target_discount 0.26191
82+
```
83+
84+
---
85+
86+
## Notebook demo
87+
88+
```bash
89+
jupyter notebook notebooks/demo.ipynb
90+
```
91+
92+
---
93+
94+
## JSON output (tool-calling friendly)
95+
96+
```bash
97+
python -m econ_math_portfolio list --json
98+
python -m econ_math_portfolio reference cpi_target_discount --json
99+
python -m econ_math_portfolio validate cpi_target_discount 0.26191 --json
100+
```
101+
102+
---
103+
104+
## Scoring rubric (LLM evaluation style)
105+
106+
```bash
107+
python -m econ_math_portfolio score submissions/contract_good.json --json
108+
```
109+
110+
Submission format:
111+
112+
```json
113+
{
114+
"task_id": "cpi_target_discount",
115+
"answer": 0.26191,
116+
"explanation": "optional short explanation"
117+
}
118+
```
119+
120+
---
121+
122+
## How to interpret this portfolio
123+
124+
This repository is a **curated slice of real analytical work**, intentionally focused on:
125+
- reasoning clarity
126+
- numerical correctness
127+
- verification and evaluation
128+
129+
The goal is to show **how problems are checked**, not just how they are solved.

notebooks/demo.ipynb

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "812d9969",
6+
"metadata": {},
7+
"source": [
8+
"# Demo notebook: Math + Econ Reasoning Portfolio\n",
9+
"\n",
10+
"This notebook demonstrates:\n",
11+
"- CPI targeting function and the bisection solution\n",
12+
"- Contract task: utility target vs. c_high (and the solved value)\n",
13+
"- Credit VaR: analytic value + Monte Carlo sanity-check distribution\n",
14+
"\n",
15+
"Run after installing dev deps:\n",
16+
"```bash\n",
17+
"pip install -e \".[dev]\"\n",
18+
"```\n"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"id": "746a11f9",
25+
"metadata": {},
26+
"outputs": [],
27+
"source": [
28+
"import math\n",
29+
"import numpy as np\n",
30+
"import matplotlib.pyplot as plt\n",
31+
"\n",
32+
"from econ_math_portfolio.models.cpi_target_discount import CpiParams, cpi, solve_t\n",
33+
"from econ_math_portfolio.models.contract_stochastic_income import ContractParams, lifetime_utility, solve_c_high\n",
34+
"from econ_math_portfolio.models.credit_var_quantile import CreditParams, var_analytic, var_mc\n"
35+
]
36+
},
37+
{
38+
"cell_type": "code",
39+
"execution_count": null,
40+
"id": "a5b5154d",
41+
"metadata": {},
42+
"outputs": [],
43+
"source": [
44+
"# CPI(t) curve + target\n",
45+
"p = CpiParams()\n",
46+
"ts = np.linspace(0, 1, 400)\n",
47+
"vals = [cpi(float(t), p) for t in ts]\n",
48+
"t_star = solve_t(p)\n",
49+
"\n",
50+
"plt.figure()\n",
51+
"plt.plot(ts, vals)\n",
52+
"plt.axhline(p.target_cpi)\n",
53+
"plt.axvline(t_star)\n",
54+
"plt.title(\"CPI(t) and target\")\n",
55+
"plt.xlabel(\"t\")\n",
56+
"plt.ylabel(\"CPI(t)\")\n",
57+
"plt.show()\n",
58+
"\n",
59+
"t_star\n"
60+
]
61+
},
62+
{
63+
"cell_type": "code",
64+
"execution_count": null,
65+
"id": "3559ab6d",
66+
"metadata": {},
67+
"outputs": [],
68+
"source": [
69+
"# Contract task: utility as a function of c_high + solved c_high\n",
70+
"cp = ContractParams()\n",
71+
"c_grid = np.linspace(0.5, 3.0, 400)\n",
72+
"u_vals = [lifetime_utility(cp.delta, cp.c_low, float(c)) for c in c_grid]\n",
73+
"c_star = solve_c_high(cp)\n",
74+
"\n",
75+
"plt.figure()\n",
76+
"plt.plot(c_grid, u_vals)\n",
77+
"plt.axhline(cp.V0)\n",
78+
"plt.axvline(c_star)\n",
79+
"plt.title(\"Lifetime utility target vs c_high\")\n",
80+
"plt.xlabel(\"c_high\")\n",
81+
"plt.ylabel(\"V(c_high)\")\n",
82+
"plt.show()\n",
83+
"\n",
84+
"c_star\n"
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"id": "ffb4364c",
91+
"metadata": {},
92+
"outputs": [],
93+
"source": [
94+
"# Credit VaR: analytic + Monte Carlo sanity check (infinitely granular Vasicek)\n",
95+
"pp = CreditParams()\n",
96+
"analytic = var_analytic(pp)\n",
97+
"mc_q = var_mc(pp, n_paths=200_000, seed=7)\n",
98+
"\n",
99+
"# Show distribution of VaR estimates from multiple seeds\n",
100+
"estimates = [var_mc(pp, n_paths=50_000, seed=s) for s in range(10, 60)]\n",
101+
"plt.figure()\n",
102+
"plt.hist(estimates, bins=20)\n",
103+
"plt.axvline(analytic)\n",
104+
"plt.title(\"MC VaR estimates (batch) vs analytic VaR\")\n",
105+
"plt.xlabel(\"VaR estimate\")\n",
106+
"plt.ylabel(\"count\")\n",
107+
"plt.show()\n",
108+
"\n",
109+
"analytic, mc_q\n"
110+
]
111+
}
112+
],
113+
"metadata": {},
114+
"nbformat": 4,
115+
"nbformat_minor": 5
116+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from __future__ import annotations
2+
3+
import math
4+
5+
6+
def solve_contract() -> float:
7+
# --- Inputs ---
8+
delta = 0.95
9+
prob = 0.5 # equal probability for the two income states
10+
c_low = 0.95
11+
V0_target = 3.0
12+
13+
# Autarky utilities (if consumption equals income)
14+
V_aut_high = math.log(1.1) / (1 - delta)
15+
16+
# Expected lifetime utility under the contract (given c_high)
17+
def expected_value(c_high: float) -> float:
18+
if c_high <= 0:
19+
return -math.inf
20+
exp_u = prob * math.log(c_low) + prob * math.log(c_high)
21+
return exp_u / (1 - delta)
22+
23+
# Participation / exit constraint in the high-income state:
24+
# log(c_high)/(1-delta) >= log(1.1)/(1-delta) => c_high >= 1.1
25+
def exit_constraint(c_high: float) -> bool:
26+
return c_high >= 1.1
27+
28+
# Solve expected_value(c_high) = V0_target via bisection on (0, 10)
29+
tol = 1e-8
30+
low, high = 1e-8, 10.0
31+
32+
# Bracketing check (monotone in c_high)
33+
if expected_value(low) > V0_target:
34+
raise ValueError("Target too low for the chosen lower bound.")
35+
if expected_value(high) < V0_target:
36+
raise ValueError("Target too high for the chosen upper bound.")
37+
38+
while high - low > tol:
39+
mid = (low + high) / 2
40+
val = expected_value(mid)
41+
if val < V0_target:
42+
low = mid
43+
else:
44+
high = mid
45+
46+
solution = (low + high) / 2
47+
48+
# Enforce exit constraint if needed
49+
if not exit_constraint(solution):
50+
print("Exit constraint not satisfied by the utility-matching solution.")
51+
print("Raising c_high to the minimum feasible value: 1.100000")
52+
solution = max(solution, 1.1)
53+
else:
54+
print("Solution satisfies both the target utility and the exit constraint.")
55+
56+
print(f"c_high (income=1.1): {solution:.6f}")
57+
print(f"Contract lifetime utility: {expected_value(solution):.6f}")
58+
print(
59+
f"High-state lifetime utility: {math.log(solution)/(1 - delta):.6f} "
60+
f"(autarky minimum: {V_aut_high:.6f})"
61+
)
62+
return float(solution)
63+
64+
65+
if __name__ == "__main__":
66+
solve_contract()

originals/check_HJB_condition.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from __future__ import annotations
2+
3+
# Original-style script: HJB inequality check at a test state.
4+
#
5+
# Notes:
6+
# - This script is kept in `originals/` for transparency.
7+
# - The repo's main implementation lives in:
8+
# `src/econ_math_portfolio/models/hjb_discount_threshold.py`
9+
#
10+
# We check the inequality in the form used in the repo:
11+
# F(rho) = rho*w^gamma + b*p*gamma*y*w^(gamma-1) + 0.5*sigma^2*p^2*gamma*(gamma-1)*y^2*w^(gamma-2)
12+
# and compute rho_critical (smallest rho with F(rho) >= 0) at x=0,y=1,p=1.
13+
14+
# Model parameters
15+
b = 1.0
16+
sigma = 0.2
17+
gamma = 0.7
18+
19+
20+
def F(rho: float, x: float, y: float, p: float) -> float:
21+
w = x + p * y
22+
if w <= 0:
23+
raise ValueError("Wealth must be positive.")
24+
return (
25+
rho * (w**gamma)
26+
+ b * p * gamma * y * (w ** (gamma - 1))
27+
+ 0.5 * (sigma**2) * (p**2) * gamma * (gamma - 1) * (y**2) * (w ** (gamma - 2))
28+
)
29+
30+
31+
def rho_critical(x: float, y: float, p: float) -> float:
32+
w = x + p * y
33+
if w <= 0:
34+
raise ValueError("Wealth must be positive.")
35+
const = (
36+
b * p * gamma * y * (w ** (gamma - 1))
37+
+ 0.5 * (sigma**2) * (p**2) * gamma * (gamma - 1) * (y**2) * (w ** (gamma - 2))
38+
)
39+
return (-const) / (w**gamma)
40+
41+
42+
if __name__ == "__main__":
43+
p_test = 1.0
44+
x_test = 0.0
45+
y_test = 1.0
46+
47+
rho_star = rho_critical(x_test, y_test, p_test)
48+
test_rhos = [rho_star - 0.01, rho_star, rho_star + 0.01]
49+
50+
print(f"Critical rho (rho*): {rho_star:.6f}")
51+
print(f"Test state: x={x_test}, y={y_test}, p={p_test}")
52+
print("=" * 60)
53+
54+
for rho in test_rhos:
55+
value = F(rho, x_test, y_test, p_test)
56+
status = "SATISFIED" if value >= 0 else "VIOLATED"
57+
print(f"rho = {rho:.6f}")
58+
print(f"delta vs critical: {rho - rho_star:+.6f}")
59+
print(f"F(rho) = {value:.6f}")
60+
print(f"Inequality status: {status}")
61+
print("-" * 60)

0 commit comments

Comments
 (0)