Global code - #32
Open
Daniel-Jensen wants to merge 18 commits into
Open
Conversation
…TATE.md Relocates all standalone Python model files into code/global/ and removes the old flat code/ layout. Updates STATE.md with the full fix log (BUG-1 through ISSUE-5), post-fix Walras residuals, BD mechanism results, and the W-G1 structural limitation explanation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces risk_branch.py (two-branch expectations, bond decomposition), full test suite under tests/, and calibration/bank/transition/government updates supporting the CK–Bocola pass-through experiment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mprovements in clarity Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment out the Cole-Kehoe sunspot section in main.py (flag off, call and CLI override disabled) so the default pipeline runs SS + TFP only. Includes accumulated model/calibration/plot refinements and the sunspot transition study notes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Cole-Kehoe/Bocola risk-only experiment was near-inert and wrong-signed:
a persistent rise in priced default probability RAISED consumption and barely
moved output. Forensics (docs/sunspot_transition_study.md §8) traced this to
three compounding causes, each fixed here.
1. Priced event was ~6x too mild. delta_b/recovery had been reverted to
0.25/0.80 (~1y duration, 20% haircut); pure repricing was -5.3% vs -30.1%
at the documented 0.036/0.45 (7y GR/DE duration, Greek PSI haircut).
-> calibration.py: restored delta_b=0.036, recovery_rate=0.45.
2. The GK bank block ABSORBED the shock instead of amplifying it. In the
feared default branch capital lost far less than bonds, so capital was the
"safe haven", two-branch pricing drove the IC multiplier mu NEGATIVE (the
always-binding IC violated in equilibrium), the pricing wedge lambda*mu/Omega
collapsed and propped bond prices up, and the imposed IC equality with
alpha falling forced an equilibrium bank-RECAPITALIZATION boom (n, I, Q up).
-> capital.py: def_capital_quality_D (GK capital-quality loss, quality0
hook applied once at branch h=0) so capital is NOT the branch safe
haven; base-path mu_D is positive again. xi_K=0.05 (0.10 tested/rejected:
over-compresses mu, flips C_D[0] positive).
3. Output had no transmission channel. Impact Y is pinned by the static GHH
labour identity; no spread ever entered production (a -30% bond crash /
-20% bank equity moved Y_D only -0.2%).
-> firms.py + transition.py: Neumeyer-Perri working-capital wedge
(zeta_wc=1), firms pre-finance the wage bill at rdep(-1)+lambda*mu/Omega;
the wedge enters labour demand, financing income routes to household
dividends (goods-market identity preserved; zeta=0 nests exactly).
Branch feasibility (the documented PSI event wipes out bank equity):
- risk_branch.py: restored the haircut feasibility ladder (as homotopy /
fallback) AND a contingent government recapitalization (recap_share_D=0.5,
HFSF/EFSF analogue) financed by branch issuance; attempt order
full -> full+recap -> ladder(+recap); branch["rescue_mode"] reports which.
The full PSI event is now priced. _shifted_y0 scales the Kap block by the
capital-quality profile so branch probes clear the Jermann penalty wall.
- government.py: recap_path plumbing; Bohn rule now responds to the SURVIVING
stock (taxing the pre-haircut stock was a ~31%-of-GDP one-quarter tax spike
that alone made full-event branches infeasible; a no-op when def_real=0).
- bank.py: recap_D/F equity injection added to retained net worth (not gross
income); threaded through transition._inner_economy.
Guardrails / calibration:
- transition.py: mu-monitor warns when the IC multiplier goes negative on a
solved path (out["mu_min_D/F"]); surfaced in main.py's CK table.
- calibration.py: T back to 200; centerpiece sunspot 1%*0.95^t.
- steady_state.py/firms.py: SS working-capital dividend routing (SS Walras 2e-10).
Results (sunspot 1%*0.95^t, T=200): 12/13 CLAUDE.md sign criteria pass -
Q_bD[0] -5.7%, n_D[0] -3.4%, n_F[0] -2.4%, Y_D[0] down, C_D[0] down, lending
spread +343bp, risk premium +73bp, base-path mu_D=+0.010>0, rescue full+recap.
Remaining item (risk-on n_D[0] above risk-off) is the M1 deposit-rate channel,
kept as a test warning pending the deferred union deposit market.
Tests: test_risk_channel re-promotes the two directional asserts (risk-on
Q_bD[0]<off, mu_D>0) and adds branch-budget/surv_d and quality0/zeta nesting
asserts; all of test_ss_identities, test_bank_block, test_fast_kernels,
test_signs_bocola, test_transition_walras, test_risk_channel pass.
Docs: CLAUDE.md, docs/STATE.md, docs/sunspot_transition_study.md §8 updated.
This commit also lands accumulated standalone-model infrastructure that was
already uncommitted in the working tree (solvers.py parallel-FD-Jacobian
Newton + jac_cache, fast_kernels.py numba EGM/distribution kernels with numpy
fallback, and the distribution/household/plots/trade refinements they depend
on) — transition.py imports solvers.py, so these are required for a working
build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make solve_default_branch price a single fixed feared event instead of searching, and update the runtime function reference to match this and the rest of the 2026-07-15 rework. Branch behaviour (risk_branch.py, calibration.py): - The branch now does ONE deterministic solve of a fixed event: branch_haircut_scale (new, default 1.0 = full Greek-PSI haircut) with the government recap on (recap_share_D > 0). No search on the common path. - The old feasibility ladder (scan over scales 0.075…1.0) is demoted to an opt-in fallback, branch_use_ladder (new, default False). If the fixed event is infeasible the branch RAISES with an actionable hint (raise recap_share_D, lower branch_haircut_scale, or enable the ladder) instead of silently searching. - Removes a wasted probe: the previous attempt order tried the full event WITHOUT recap first, which always failed at the PSI calibration and burned a full transition solve every risk round. - Drops the now-unused target_scale/target_mode plumbing from solve_default_branch and its caller. Verified identical to the previous behaviour: rescue_mode=full+recap, scale=1.0, Q_bD[0] -5.67%, n_D[0] -3.44%, n_F[0] -2.39%, min mu_D +0.010 — the full+recap event is exactly what the old ladder landed on. Docs (docs/function_reference.md + rebuilt .pdf): updated every entry the 2026-07-15 rework touched — solve_default_branch (was still stating "the feasibility ladder was removed … recapitalization is not modelled"), solve_capital_path (quality0 capital-quality loss), govt_transition (recap outlays + Bohn rule on the surviving stock), steady_state_firm/solve_firm_path (working-capital wedge), _inner_economy (wedge, recap threading, mu-monitor), and solve_transition (accept_tol, mu_min returns, and the actual Newton + jac_cache solver, which the doc still described as the old hybr/krylov path). CLAUDE.md and docs/sunspot_transition_study.md note the ladder is now opt-in. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codebase-wide readability pass across every module in code/global/, plus a small correctness fix for an edge case the previous commit (d1bd6eb) missed. Comment/docstring cleanup (behaviour-preserving): - Every function now opens with a single one-line summary comment; the long multi-line explanations were trimmed to short inline notes only where the logic is non-obvious. - Removed all triple-quoted docstrings (module + function). - Removed stale objects: beta_guess_D/F and the rk_D/F_guess seeds (always overwritten in solve_steady_state before use), recap_share_F (no F default branch — only recap_share_D is read), the T_arr duplicate of T in transition.py, and the dead ss["ss_cap_D"] guard in plots.py. - Executable code preserved line-for-line. Verified byte-identical: SS (Y_ss=1, Q_bD_ss=0.8780, n_ss=3.2476), TFP transition (goods_D=2.16e-13, min_mu_D=-0.0307), and the sunspot risk-ON path (Q_bD[0]=-5.67%, n_D[0]=-3.44%, min_mu_D=+0.0101) all match the pre-cleanup values exactly. ~1,400 comment lines removed (files ~20-30% shorter). Zero-shock branch guard (risk_branch.solve_transition_ck_risk): - When there is no priced risk anywhere (def_price ≡ 0), return the risk-off path and skip the default-branch solve. This is exactly correct — pi ≡ 0 nests the risk-neutral model — and avoids a fragile branch solve from the healthy SS state, which needs the (now off-by-default) feasibility ladder as a homotopy. Fixes test_zero_shock_with_risk_machinery, which regressed when d1bd6eb turned the ladder off (that commit was validated only on the sunspot path, missing this edge case). Tests: test_ss_identities, test_bank_block, test_fast_kernels, test_signs_bocola, test_transition_walras, and all of test_risk_channel (incl. the re-enabled zero-shock test) pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ut branch - Fix Ω-kernel weight swap: Ω = β[f + (1−f)α′] (Bocola Prop. 1; f = exit share, weight 1−f ≈ 0.95 on the franchise value — was 0.05). beta_inter 0.96 → 0.99 (≈ β_hh); recalibrated SS: α_ss = 1.24, λ = 0.31. - Occasionally-binding IC: capital-market residual is now the Fischer-Burmeister complementarity 0 ≤ μ ⊥ αn − λ·assets ≥ 0; portfolio shares and branch inits on actual net worth. No new unknowns. - Default risk is exogenous (Bocola eqs. 11-12): π_t is an input path; Cole-Kehoe zones, zone iterations, and solve_transition_ck deleted. - Pure-haircut feared event (recovery 0.45 on the whole claim): output-cost, ξ_K, and recap patches now diagnostic flags, all 0. Feasible via a numerical recap-share warm-start continuation; branch rk_d < 0 without ξ_K (capital no longer the safe haven), branch μ > 0 throughout. - Removed: F-side default machinery, chi_tilt, sdf_mode empirical/model + kappa_d, branch ladder/haircut scale, anchored entrant mode. - solve_transition_ck_risk → solve_transition_risk(pi_D_path=...); tests and CLAUDE.md updated. Full pipeline 66s; risk fixed point converges in 7 rounds; complementarity ~1e-12 on all solved paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Production uses the stock carried into t: Y_t = Z_t K_{t-1}^a N_t^{1-a};
mpk on the lagged vintage, matching the bank claim return
rk_t = (mpk_t + (1-d)Q_t)/Q_{t-1} exactly. Impact output moves through
hours alone (identity Y^_0 = (1-a)N^_0, tested to 1e-12).
- quality0 (branch capital-quality loss) now hits Y_0 directly (GK11).
- cap_profit re-derived: pure Jermann rents Q(K_t-(1-d)K_lag) - I; the mpk
reconciliation term existed only for the old contemporaneous timing.
- Headline experiment (pi = 1%*0.95^t): Y_D[0] -0.32% (was +0.07%),
I_D[0] -1.16% (was +1.77%) - the impact investment boom is gone.
- New tests: impact-composition identity + headline comovement case.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The two national deposit clearings become (i) ONE union-wide clearing in D-good units and (ii) deposit-UIP (1+rdep_D) = (1+rdep_F)p'/p - the flexible-price image of a single union rate with national inflation differentials (BKK/Baxter-Crucini single-traded-bond margin; integrated GK bank funding as in Dedola-Karadi-Lombardo 2013). Zero-profit interbank pass-through -> no Walras leak (goods_F stays at the grid floor). - Cross-border deposit position out['nfa_dep_D'] is the new absorption margin (breaks the national S=I trap behind the M1 comovement problem). - Stage-2 SS: beta_F = beta_D (symmetric-SS doctrine) with an F-market clearing assert; beta value unchanged. - Unknown layout unchanged (7T); bank and household blocks untouched. - Headline experiment (pi = 1%*0.95^t, risk-neutral): Y_D[0] -0.22%, I_D[0] -1.00%; income-SDF sign gate no longer trips in the risk suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… flags Reduce comment noise and dead code across code/global/ without changing model behavior (arithmetic verified bit-identical on every hot path: steady_state_bank over 1980 inputs, bank_backward on the TPI floor path, the CB price floor over 20k draws). - Comment convention: every module and function carries exactly one leading ALL-CAPS comment; further explanation is lowercase # notes on the specific hard line. Docstrings and **bold** markers removed. - New prints.py: all console reporting (SS table, residual checks, risk and TPI diagnostic tables, lending_spread_bps). main.py is now orchestration only; model blocks no longer format output. - market_residuals moved into transition.py as the single definition of the clearing diagnostics, shared by prints.py and the tests (was duplicated in tests/common.py as transition_residuals). - Removed switched-off machinery that was all 0/inert at the baseline: def_output_cost_D, def_output_rho_D, def_capital_quality_D and its quality0 capital plumbing, recap_share_D, the pin_rdep deposit-rate diagnostic, the hybr_factor argument, capital_branch_summary, and the standalone hm_bond_price_ss/hm_bond_return_ss helpers (inlined). The recap continuation survives as _RECAP_LADDER (numerical warm-start scaffolding only). - Docs (CLAUDE.md, function_reference.md, STATE.md) updated to match. Tests: ss_identities, bank_block, fast_kernels, transition_walras, signs_bocola, risk_channel all pass. Full main.py pipeline (SS -> TFP -> risk -> TPI) converges at the documented 1% headline. The pre-existing TPI solver fragility at larger shocks is unchanged (test_tpi on_date=5 and main.py at PI_SHOCK=0.02 stall in the base solve). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nel opt-in code/global's two-branch risk channel produces an expansionary artifact (the crisis-state bank levers into capital as a safe haven); code/bocola2016/ builds a standalone reference solution — Smolyak time-iteration over the true recursive competitive equilibrium — to validate against instead of the finite-horizon branch approximation. main.py now defaults to the liquidity- channel-only headline (RUN_RISK_TWO_BRANCH=False, RUN_TPI=False) with the two-branch run kept available behind a flag; prints.py handles both modes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…alibration fixes Add a recursive global equilibrium solve for the frozen two-country model, replacing the perfect-foresight MIT transition + representative post-default branch with a genuine recursive law of motion: - state_grid.py: Smolyak sparse grid + Chebyshev basis (Krueger-Kubler 2004), square collocation, agreed 8-state box builder. - point_map.py: single-point period map -- the per-period image of transition.py's 7-unknown stacked system; P sufficient for N (no separate household-wealth state). - expectations.py: two-branch Gauss-Hermite quadrature over (eps_s, d') that replaces risk_branch.py's representative branch -- the bad state is the SAME fitted rules at a reachable point. - decision_rules.py: per-regime Chebyshev coefficient layer (SOLVE7 + DERIVED4). - household_ks.py: 1-moment Krusell-Smith household layer over the aggregate state, internally consistent (no separate perceived law of motion). - recursive_residual.py / recursive_main.py: pointwise time-iteration driver (Coleman operator, not a monolithic Newton -- far less stiff at the occasionally-binding kink). - recursive_experiment.py: the pass-through experiment -- elevated priced default probability lowers Y_D and C_D persistently, the sign the representative branch could not deliver. - tests/: state-grid exactness + recursive nesting regression. Calibration realignment to Bocola (2016) Tables 1-2: - leverage^bg 4.0 -> 5.0 and spread 200bp -> 8bp (mu^bg = 0.001, barely-binding SS); the fold that blocked lev 5 was a high-spread artifact. - delta_b 0.036 -> 0.056 (Bocola's pi, HM/CE perpetuity maturing fraction). - B_gov set so D-bank D-sovereign holdings are 7.6% of assets (Bocola exp^bg, Table B1). The old 3.722 misread "93% of bank EQUITY" as debt/GDP, tripling exposure and making default expansionary via a huge fiscal windfall. - phi_lamb -> gamma_tau = 1.0 (Bocola's debt-level tax rule). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Push the standalone Bocola (2016) reference solve toward his Figure-5 magnitudes and document the residual numerical obstacle honestly. - full_rotated.py / simulate_full.py: PCA-decorrelated 6-state grid + best- iterate tracking. Cuts the infeasible-corner fraction 53% -> 13% and strengthens the pass-through (Q_b -19% at p^d 2.5%, near Bocola's ~-15%). - rotated_grid.py: generalise rotated_from_path to any number of trailing exogenous dims, with optional exog_lo/exog_hi box overrides. - time_iteration_full.py: warm start from saved coefficients + best-iterate return (the two-regime near-unit-root iteration is not globally contractive -- it reaches a good near-fixed-point then oscillates away). - expectations.py: softplus floor on next-period investment so Q_K' is differentiable everywhere (the hard np.where(I'>0) kink made the FD Jacobian noisy); BGP stays a rest point to 1e-12. - newton_collocation.py / full_continue.py: Newton on the stacked collocation residual with Fischer-Burmeister complementarity smoothing (mu an explicit unknown). FB-Newton unstalls where the axis-aligned solve was stuck (residual 0.037 -> 0.0053) but floors at ~5e-3 on a handful of hard anchored corners coupled to the interior through the global fit. - docs: honest state of the replication -- the financial pass-through is replicated and correctly signed; matching the real-side magnitudes needs a corner-decoupling solver (local/FE basis or tuned Smolyak+filter) plus the Neumeyer-Perri working-capital wedge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.