Skip to content

Conversation

@mmcky
Copy link
Contributor

@mmcky mmcky commented Dec 9, 2025

Summary

Fixes #759 - Weekly Colab execution check failure in the ifp_advanced lecture.

Problem

The solve_model function in lectures/ifp_advanced.md had a critical mismatch between its signature and how it was being called throughout the lecture:

Function signature:

def solve_model(
    ifp: IFP,
    c_init: jnp.ndarray,  # consumption policy initial guess
    a_init: jnp.ndarray,  # endogenous grid initial guess
    ...
) -> (c_out, a_out):  # returns (consumption policy, asset grid)

Issue: All 5 call sites were:

  1. Passing parameters in the wrong order: (ifp, a_init, c_init) instead of (ifp, c_init, a_init)
  2. Expecting returns in the wrong order: a_vec, c_vec = instead of c_vec, a_vec =

This caused the notebook to fail during execution, as the wrong arrays were being used for asset grids vs consumption policies.

Changes

Fixed all 5 occurrences in lectures/ifp_advanced.md:

  1. Line 490 - Initial solve_model call
  2. Line 497 - Timed solve_model call (also fixed .block_until_ready() to use σ_star instead of a_star)
  3. Line 645 - Simulation section call
  4. Line 737 - Return volatility analysis loop
  5. Line 814 - Income volatility analysis loop

Testing

  • ✅ Verified syntax validity of modified file
  • ✅ All parameter orders now match the function signature
  • ✅ All return value assignments now match the function's return order
  • ⏳ Local build test in progress

This ensures the notebook will execute correctly when the Colab workflow runs again.

Closes #759

The solve_model function signature expects (ifp, c_init, a_init) and returns (c_out, a_out),
but all call sites were passing parameters in the wrong order (a_init, c_init) and
expecting returns in the wrong order (a_out, c_out).

This fixes all 5 call sites in the lecture to use the correct parameter and return order:
- Line 490: Fixed initial solve_model call
- Line 497: Fixed timed solve_model call
- Line 645: Fixed simulation section call
- Line 737: Fixed return volatility loop call
- Line 814: Fixed income volatility loop call

Fixes #759
@mmcky
Copy link
Contributor Author

mmcky commented Dec 9, 2025

Investigation: Root Cause Analysis

I traced the bug back to its origin. The issue was introduced in commit 60235eb (PR #757) on December 2, 2025.

What Changed in PR #757

Before PR #757:

  • Function name: solve_model_time_iter
  • Parameters: (model, a_vec, σ_vec, ...)
  • Return order: (a_new, σ_new)
  • All calls correctly used: a_vec, c_vec = solve_model_time_iter(ifp, a_init, c_init)

After PR #757:

  • Function renamed to solve_model
  • Parameters changed order to: (ifp, c_init, a_init, ...) ⚠️
  • Return order changed to: (c_out, a_out) ⚠️
  • BUT: Call sites were NOT updated - still used old order: a_vec, c_vec = solve_model(ifp, a_init, c_init)

The Bug

PR #757 refactored the function to use jax.lax.while_loop for better performance and changed both:

  1. Parameter order: a_vec, σ_vecc_init, a_init
  2. Return order: a_new, σ_newc_out, a_out

However, none of the 5 call sites were updated to match the new signature, causing:

  • Wrong arrays passed as arguments (assets passed where consumption was expected)
  • Wrong arrays assigned to variables (consumption assigned to asset variables)
  • Execution failure in Colab workflow

This PR fixes all 5 call sites to match the new function signature.

@mmcky
Copy link
Contributor Author

mmcky commented Dec 9, 2025

Why PR #757's CI Didn't Catch the Bug

Excellent question! You're right that the cache would be invalidated when the code changed. Here's the actual reason the bug wasn't caught:

The Critical Detail: Identical Initial Values

The bug didn't cause an execution error because all call sites initialize both parameters to the same value:

Example 1 (lines 483-485):

σ_init = jnp.empty((k, n))
for z in range(n):
    σ_init = σ_init.at[:, z].set(ifp.s_grid)
a_init = σ_init.copy()  # ← SAME VALUE!

Example 2 (lines 642-644):

a_init = s_grid[:, None] * jnp.ones(n_z)
c_init = a_init  # ← SAME VALUE!

Why This Masked the Bug

When you call:

solve_model(ifp, a_init, c_init)  # Wrong order

But a_init == c_init, it's effectively the same as calling:

solve_model(ifp, c_init, a_init)  # Correct order

The function executed successfully, just with subtly incorrect iteration logic that wasn't obvious in the output.

Why the Weekly Colab Check Failed

The weekly check may have:

  1. Hit numerical instabilities during the solve iteration
  2. Had different random seeds causing divergence
  3. Run with stricter validation checks
  4. Encountered the issue when the wrongly-ordered return values (a_vec, c_vec instead of c_vec, a_vec) were used in subsequent compute_asset_stationary calls, causing simulation errors

The bug was silent but real - it executed without crashing but with incorrect computation logic.

@mmcky
Copy link
Contributor Author

mmcky commented Dec 9, 2025

@jstac I still don't understand why colab failed and the preview didn't.
(not sure the final comment above is accurate yet)

But it appears some function calls weren't updated when we updated ifp_advanced.

@github-actions
Copy link

github-actions bot commented Dec 9, 2025

📖 Netlify Preview Ready!

Preview URL: https://pr-762--sunny-cactus-210e3e.netlify.app (ca4439b)

📚 Changed Lecture Pages: ifp_advanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weekly Colab Execution Check Failed - 20016370666

2 participants