Skip to content

Conversation

@jstac
Copy link
Contributor

@jstac jstac commented Nov 7, 2025

Summary

This PR restructures five lectures into a coherent cake eating series with consistent notation, modern Python patterns, and improved pedagogical flow. The series now progresses logically from deterministic to stochastic problems, introducing increasingly sophisticated solution methods, culminating in a JAX-accelerated implementation.

Lecture Series Structure

  1. Cake Eating I (cake_eating.md) - Introduction to Optimal Saving
  2. Cake Eating II (cake_eating_numerical.md) - Numerical Methods
  3. Cake Eating III (cake_eating_stochastic.md) - Stochastic Dynamics ✨ New framing
  4. Cake Eating IV (cake_eating_time_iter.md) - Time Iteration ✨ Renamed
  5. Cake Eating V (cake_eating_egm.md) - The Endogenous Grid Method ✨ Renamed
  6. Cake Eating VI (cake_eating_egm_jax.md) - EGM with JAX ✨ New

Key Changes

🚀 New JAX Implementation (Cake Eating VI)

Added a new lecture demonstrating high-performance implementation using JAX:

Key JAX features demonstrated:

  • Vectorization with vmap: Replaces for loops with efficient vectorized operations
  • JIT compilation: @jax.jit decorator for compiled performance
  • Functional control flow: jax.lax.while_loop instead of Python loops
  • Hardware acceleration: Supports GPU/TPU through JAX
  • Clean architecture: Global functions with explicit parameters for JAX compatibility

Implementation highlights:

@jax.jit
def solve_model_time_iter(model, σ_init, tol=1e-5, max_iter=1000):
    def condition(loop_state):
        i, σ, error = loop_state
        return (error > tol) & (i < max_iter)
    
    def body(loop_state):
        i, σ, error = loop_state
        σ_new = K(σ, model)
        error = jnp.max(jnp.abs(σ_new - σ))
        return i + 1, σ_new, error
    
    i, σ, error = jax.lax.while_loop(condition, body, initial_state)
    return σ

The lecture focuses on JAX implementation patterns while referring readers to Cake Eating V for algorithmic details.

🔤 Consistent Notation Throughout

Changed state variable from yx in all lectures (III, IV, V) to match the notation in Cake Eating I and II. This includes:

  • Mathematical equations: $y_t$$x_t$, $v(y)$$v(x)$, etc.
  • Python code: function parameters and variables
  • All prose references

🎯 Reframed as Cake Eating Problem

Cake Eating III now clearly presents the problem as stochastic cake eating:

  • The cake "regrows" when you save seeds (invest), like a harvest
  • Connected to stochastic dynamic optimization theory
  • Serves as a bridge to more sophisticated consumption-saving models
  • All "optimal growth" references changed to "cake eating" in text

🐍 Modern Python with Type Hints

Converted from traditional classes to typed NamedTuple:

from typing import NamedTuple, Callable

class Model(NamedTuple):
    β: float              # discount factor
    μ: float              # shock location parameter
    s: float              # shock scale parameter
    grid: jnp.ndarray     # state grid
    shocks: jnp.ndarray   # shock draws
    α: float              # production function parameter

def create_model(...) -> Model:
    """Factory function for creating model instances"""

All functions now have full type annotations.

📚 Improved Pedagogical Flow

Cake Eating III:

  • Introduced as natural continuation of I and II
  • Uses intuitive harvest/regrowth metaphor
  • Explains stochastic production clearly

Cake Eating IV:

  • Clear introduction to time iteration concept
  • Explains advantages over value function iteration (exploits differentiability/FOCs)
  • Previews that EGM (Lecture V) is even more efficient
  • Moved imports to top of file
  • Uses qe.Timer for timing

Cake Eating V:

  • Builds naturally from time iteration
  • Highlights efficiency gains from avoiding root-finding
  • Removed default values from Model class (now only in create_model)
  • Uses qe.Timer for consistency
  • Aligned all comments in class definitions

Cake Eating VI:

  • JAX implementation of EGM
  • Demonstrates modern computational patterns
  • Shows how to structure code for JIT compilation
  • Highlights vectorization benefits

🏗️ Structural Improvements

  • Consistent naming: OptimalGrowthModelModel, ogmodel
  • Inline definitions: Functions defined directly in lectures instead of external files (where appropriate)
  • Self-contained: Reduced dependencies on external code files
  • Updated cross-references: All internal links between lectures work correctly
  • Clean separation: NumPy implementation (V) vs JAX implementation (VI)

File Changes

New

  • cake_eating_egm_jax.md - JAX implementation of EGM

Renamed

  • cake_eating_problem.mdcake_eating.md
  • optgrowth.mdcake_eating_stochastic.md
  • coleman_policy_iter.mdcake_eating_time_iter.md
  • egm_policy_iter.mdcake_eating_egm.md

Deleted

  • optgrowth_fast.md (removed; content was redundant)

Modified

  • _toc.yml - Updated all file references and added new lecture
  • _static/lecture_specific/optgrowth/cd_analytical.py - Updated variable names

Benefits

  1. Better learning progression: Clear path from simple to complex, NumPy to JAX
  2. Consistent notation: No confusion switching between lectures
  3. Modern code: Type hints and JAX patterns improve readability
  4. Unified theme: "Cake eating" metaphor throughout
  5. Self-contained: Less reliance on external files
  6. Performance showcase: JAX lecture demonstrates modern scientific computing

Testing

  • All file renames reflected in _toc.yml
  • All cross-references between lectures updated
  • Consistent notation (x instead of y) throughout
  • Type hints added to all functions
  • All "growth" references changed to "cake eating" in prose
  • JAX implementation tested and runs successfully
  • Model class simplified (no default values, functions stored globally for JAX)

Notes

The lectures maintain mathematical rigor while improving accessibility. The cake eating framing makes the economic intuition clearer, especially for students new to dynamic programming. The new JAX lecture provides a bridge to modern high-performance computing for students ready to scale up their implementations.

🤖 Generated with Claude Code

jstac and others added 2 commits November 7, 2025 14:53
This commit restructures and consolidates five lectures into a coherent
cake eating series with consistent notation, modern Python patterns, and
clearer pedagogical flow.

## File Changes

### Renamed Files
- `cake_eating_problem.md` → `cake_eating.md` (Cake Eating I)
- `optgrowth.md` → `cake_eating_stochastic.md` (Cake Eating III)
- `coleman_policy_iter.md` → `cake_eating_time_iter.md` (Cake Eating IV)
- `egm_policy_iter.md` → `cake_eating_egm.md` (Cake Eating V)

### Deleted Files
- `optgrowth_fast.md` (content merged into Cake Eating III)

### Updated Files
- `_toc.yml` - Updated all file references
- `_static/lecture_specific/optgrowth/cd_analytical.py` - Changed variable names

## Major Changes

### 1. Consistent Notation (y → x)
Changed state variable from `y` to `x` throughout all lectures to maintain
consistency with Cake Eating I and II, which use `x` for cake size.

### 2. Reframed as Cake Eating Problem
- Cake Eating III now explains the problem as a stochastic cake that regrows
  (like a harvest) when seeds are saved
- Connected to stochastic growth theory without claiming to be a growth model
- Updated all references from "optimal growth" to "cake eating" in text
- Changed index entries and section headers accordingly

### 3. Modern Python with Type Hints
Converted from traditional classes to typed NamedTuples:
- `class Model(NamedTuple)` with full type annotations
- `create_model()` factory function
- Type hints on all functions using `Callable`, `np.ndarray`, etc.
- Changed class methods to standalone functions

### 4. Consistent Naming
- `OptimalGrowthModel` → `Model`
- `og` → `model` (variable names)
- All lectures now use the same model structure

### 5. Pedagogical Improvements

**Cake Eating III (Stochastic Dynamics):**
- Introduced as continuation of Cake Eating I and II
- Uses harvest/regrowth metaphor for stochastic production
- Maintained value function iteration approach

**Cake Eating IV (Time Iteration):**
- Clear introduction explaining time iteration concept
- Explains it builds on Cake Eating III
- Previews that Cake Eating V will be even more efficient
- Defined model inline instead of loading external files

**Cake Eating V (EGM):**
- Builds naturally from Cake Eating IV
- Shows efficiency gains from avoiding root-finding
- Consistent model structure throughout

## Technical Details

- All Python code uses consistent variable names (x instead of y)
- Removed external file dependencies where possible
- Inline function definitions for clarity
- Updated cross-references between lectures
- Preserved mathematical rigor while improving accessibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Resolved conflict in _toc.yml by:
- Accepting the new "Optimal Growth" section from main
- Using renamed file "cake_eating" instead of "cake_eating_problem"
- Keeping Household Problems section with only cake eating lectures

The main branch had moved Cass-Koopmans lectures to a separate "Optimal Growth" section, which is preserved in this merge.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 7, 2025

Merge Conflict Resolved

The conflict in _toc.yml has been resolved by merging main into this PR branch.

Resolution details:

  • Accepted the new "Optimal Growth" section from main (containing Cass-Koopmans lectures)
  • Used the renamed cake_eating file (instead of cake_eating_problem) in the Household Problems section
  • Removed duplicate Cass-Koopmans lecture references from Household Problems section

The PR is now mergeable and ready for review.

…ators

This commit fixes issues with the cake eating lecture series that prevented them from executing correctly after the conversion to NamedTuple with type hints.

Changes made:

1. Inlined external code files into lectures:
   - Replaced :load: directives with actual code from analytical.py files
   - Inlined solve_model function from optgrowth/solve_model.py
   - Deleted now-unused external files

2. Fixed Numba incompatibility:
   - Removed @jit decorators from cake_eating_time_iter.md and cake_eating_egm.md
   - Switched from quantecon.optimize.brentq to scipy.optimize.brentq
   - Removed numba imports where no longer needed

3. Fixed function signatures:
   - Corrected parameter order in state_action_value() in cake_eating_stochastic.md
   - Removed [0] indexing from scipy's brentq (returns scalar, not tuple)

4. Added Python files for testing:
   - Generated .py files using jupytext for all cake eating lectures
   - Verified all lectures execute successfully without errors

All five cake eating lectures now execute correctly as standalone Python scripts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 7, 2025

Code Verification and Bug Fixes

Verified all five cake eating lectures execute correctly by converting them to Python with jupytext and running them as standalone scripts. Fixed several issues discovered during testing:

Issues Fixed

  1. External code dependencies: Replaced :load: directives with inline code

    • Inlined functions from analytical.py files into all lectures that used them
    • Inlined solve_model() function into cake_eating_stochastic.md
    • Deleted now-unused external Python files
  2. Numba incompatibility with modern type hints:

    • Removed @jit decorators from cake_eating_time_iter.md and cake_eating_egm.md
    • The NamedTuple with Callable type hints introduced in this PR is incompatible with Numba's JIT compilation
    • Switched from quantecon.optimize.brentq to scipy.optimize.brentq
    • Removed unnecessary numba imports
  3. Function signature bugs:

    • Fixed parameter order in state_action_value() in cake_eating_stochastic.md
    • Fixed brentq return value handling (scipy returns scalar, not tuple)

Verification

All lectures now execute successfully:

  • ✅ cake_eating.md
  • ✅ cake_eating_numerical.md
  • ✅ cake_eating_stochastic.md
  • ✅ cake_eating_time_iter.md
  • ✅ cake_eating_egm.md

Generated .py files are included in the commit for easy verification.

jstac and others added 2 commits November 8, 2025 05:26
The .py files were used for testing lecture execution but should not be part of the repository.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Updated all doc references throughout the lecture series to reflect the renamed files from PR #679:
- cake_eating_problem → cake_eating
- optgrowth → cake_eating_stochastic
- coleman_policy_iter → cake_eating_time_iter
- egm_policy_iter → cake_eating_egm

Also:
- Removed references to the deleted optgrowth_fast lecture
- Inlined solve_model_time_iter function in ifp.md
- Updated terminology from "stochastic optimal growth model" to "cake eating model" in ifp.md

This fixes the Jupyter Book build warnings about unknown documents.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 7, 2025

Fixed Jupyter Book Build Errors

Fixed all cross-reference warnings that were causing the Jupyter Book build to fail.

Changes Made

1. Updated cross-references to renamed lectures:

  • cake_eating_problemcake_eating (3 references in cake_eating_numerical.md, 1 in cake_eating_stochastic.md)
  • optgrowthcake_eating_stochastic (2 references in ifp.md, 1 in lqcontrol.md, 1 in wald_friedman_2.md)
  • coleman_policy_itercake_eating_time_iter (1 reference in ifp.md)
  • egm_policy_itercake_eating_egm (1 reference in ifp_advanced.md)

2. Removed references to deleted lecture:

  • Removed 3 references to optgrowth_fast in cake_eating_stochastic.md (lecture was deleted in this PR)

3. Inlined external code:

  • Replaced :load: directive with inline code for solve_model_time_iter function in ifp.md

4. Updated terminology:

  • Changed "stochastic optimal growth model" to "cake eating model" in ifp.md to match new naming convention

All 13 build warnings about unknown documents have been resolved. The book should now build successfully.

@jstac
Copy link
Contributor Author

jstac commented Nov 7, 2025

@mmcky Just FYI I'm removing quite a few old "load" directives and inlining code.

The reason is that I really need to be able to easily generate excutable code via jupytext --to py...

@github-actions
Copy link

github-actions bot commented Nov 7, 2025

📖 Netlify Preview Ready!

Preview URL: https://pr-679--sunny-cactus-210e3e.netlify.app (11e5850)

📚 Changed Lecture Pages: cake_eating_egm, cake_eating_numerical, ifp, ifp_advanced, lqcontrol, wald_friedman_2

Modernized the cake eating numerical methods lecture by replacing class-based
implementation with a functional programming approach using NamedTuple.

Key changes:
- Replaced `class CakeEating` with `Model = namedtuple('Model', ...)`
- Created `create_cake_eating_model()` helper function for building instances
- Converted class methods to standalone functions:
  - `u(c, γ)` for utility function
  - `u_prime(c, γ)` for utility derivative
  - `state_action_value(c, x, v_array, model)` for Bellman RHS
- Updated Bellman operator `T(v, model)` to use functional style
- Modified policy function `σ(model, v)` to accept model parameter
- Refactored exercise solution from inheritance-based `class OptimalGrowth(CakeEating)`
  to `class ExtendedModel(NamedTuple)` with standalone functions
- Updated all code examples throughout to use `model` parameter pattern
- Generated and tested Python version using jupytext

This aligns with the modern functional style used in cake_eating.md and
reduces reliance on OOP patterns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 7, 2025

Refactored cake_eating_numerical to functional style

I've updated cake_eating_numerical.md to use a modern functional programming approach instead of OOP, making it consistent with the style in cake_eating.md.

Main Changes

Before (OOP style):

class CakeEating:
    def __init__(self, β=0.96, γ=1.5, ...):
        self.β, self.γ = β, γ
        self.x_grid = np.linspace(...)
    
    def u(self, c):
        return (c ** (1 - self.γ)) / (1 - self.γ)
    
    def state_action_value(self, c, x, v_array):
        ...

ce = CakeEating()
v = T(v, ce)

After (Functional style):

Model = namedtuple('Model', ('β', 'γ', 'x_grid'))

def create_cake_eating_model(β=0.96, γ=1.5, ...):
    x_grid = np.linspace(...)
    return Model(β=β, γ=γ, x_grid=x_grid)

def u(c, γ):
    return (c ** (1 - γ)) / (1 - γ)

def state_action_value(c, x, v_array, model):
    ...

model = create_cake_eating_model()
v = T(v, model)

Exercise Solution

Also refactored the exercise from inheritance-based class OptimalGrowth(CakeEating) to a clean functional approach with class ExtendedModel(NamedTuple) and standalone helper functions.

Testing

✅ Generated Python version with jupytext --to py
✅ Successfully ran all code examples
✅ Value function iteration converged in 329 iterations

This reduces OOP complexity and makes the code more maintainable and easier to understand.

@github-actions
Copy link

github-actions bot commented Nov 7, 2025

📖 Netlify Preview Ready!

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

📚 Changed Lecture Pages: cake_eating_egm, cake_eating_numerical, ifp, ifp_advanced, lqcontrol, wald_friedman_2

jstac and others added 2 commits November 8, 2025 09:10
Updated Model definition to use modern class-based NamedTuple syntax
with type annotations instead of collections.namedtuple, matching the
style used for ExtendedModel in the exercise solution.

Before: Model = namedtuple('Model', ('β', 'γ', 'x_grid'))
After:  class Model(NamedTuple):
            β: float
            γ: float
            x_grid: np.ndarray

This provides better type hints and is more consistent with modern
Python typing conventions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
The .py file was only for testing purposes and should not be tracked.
Users can generate it locally using jupytext when needed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

Updated Model definition to use modern class-based NamedTuple syntax with type annotations instead of collections.namedtuple, matching the style used for ExtendedModel in the exercise solution.

Also removed the test Python file - it can be generated locally with jupytext when needed.

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

📖 Netlify Preview Ready!

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

📚 Changed Lecture Pages: cake_eating_egm, cake_eating_numerical, ifp, ifp_advanced, lqcontrol, wald_friedman_2

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

📖 Netlify Preview Ready!

Preview URL: https://pr-679--sunny-cactus-210e3e.netlify.app (8f5d9bf)

📚 Changed Lecture Pages: cake_eating_egm, cake_eating_numerical, ifp, ifp_advanced, lqcontrol, wald_friedman_2

@mmcky
Copy link
Contributor

mmcky commented Nov 8, 2025

@mmcky Just FYI I'm removing quite a few old "load" directives and inlining code.

The reason is that I really need to be able to easily generate excutable code via jupytext --to py...

Roger that @jstac, I might take a note of which ones.

You prefer the jupytext --to py workflow more than jb build lectures (with local caching)?

@mmcky
Copy link
Contributor

mmcky commented Nov 8, 2025

@jstac this re-organization looks great. The new structure makes a lot of sense.

@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

Thanks @mmcky

You prefer the jupytext --to py workflow more than jb build lectures (with local caching)?

Yeah, i do, tbh, at least for intermediate steps. And Claude seems to like interacting directly with a py file.

- Created new lecture cake_eating_egm_jax.md implementing EGM with JAX
  - Uses JAX's vmap for vectorization instead of for loops
  - JIT-compiled solver with jax.lax.while_loop
  - Global utility/production functions for JAX compatibility
  - Streamlined Model class to contain only arrays and scalars
  - Focuses on JAX implementation patterns, refers to cake_eating_egm for theory

- Improved cake_eating_time_iter.md
  - Moved imports to top of file
  - Removed timing benchmarks, added clearer performance discussion
  - Explained why time iteration is faster (exploits differentiability/FOCs)
  - Referenced EGM as even faster variation

- Enhanced cake_eating_egm.md
  - Removed default values from Model class (now only in create_model)
  - Aligned all comments in Model class definition
  - Replaced %%timeit with qe.Timer for consistency
  - Simplified timing discussion

- Updated _toc.yml to include new lecture after cake_eating_egm

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link

github-actions bot commented Nov 8, 2025

- Moved all imports to top of file (NamedTuple with other imports)
- Removed unused Callable import
- Added block_until_ready() to timing for accurate JAX benchmarking
- Improved error output formatting with print statement
- Added comprehensive CRRA utility exercise demonstrating convergence

Exercise improvements:
- Uses correct CRRA form: u(c) = (c^(1-γ) - 1)/(1-γ) that converges to log
- Focuses on γ values approaching 1 from above (1.05, 1.1, 1.2)
- Plots γ=1 (log case) in black with clear labeling
- Includes explanation of endogenous grid coverage differences
- Shows numerical convergence with maximum deviation metrics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

Latest Updates: JAX Lecture Refinements

Just pushed improvements to the new JAX EGM lecture (cake_eating_egm_jax.md):

Code Quality Improvements

  • ✅ Moved all imports to the top of the file (following Python best practices)
  • ✅ Removed unused Callable import
  • ✅ Added .block_until_ready() to timing code for accurate JAX benchmarking (JAX uses asynchronous dispatch)
  • ✅ Improved error output formatting with formatted print statement

New CRRA Utility Exercise

Added a comprehensive exercise demonstrating convergence of CRRA utility to log utility:

Key features:

  • Uses the correct CRRA form: $u(c) = \frac{c^{1-\gamma} - 1}{1-\gamma}$ which converges to log utility as $\gamma \to 1$
  • Focuses on $\gamma$ values approaching 1 from above (1.05, 1.1, 1.2) to ensure similar endogenous grid coverage
  • Plots $\gamma = 1$ (log case) in black with clear labeling
  • Includes explanation of why plots don't cover the entire x-axis range (due to endogenous grid)
  • Shows numerical convergence with maximum deviation metrics

Results demonstrate:

  • Max difference $\gamma=1.0$ to $\gamma=1.05$: 0.62
  • Max difference $\gamma=1.0$ to $\gamma=1.1$: 1.14
  • Max difference $\gamma=1.0$ to $\gamma=1.2$: 1.95

The monotonically increasing differences clearly show convergence to the log utility case as $\gamma \to 1$.

The exercise provides students with hands-on experience adapting the JAX code to different utility functions while understanding the mathematical relationship between CRRA and log utility.

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

@mmcky I'm going to go ahead and merge this, since it touches the _toc and a lot of other files. I've checked it pretty carefully and I think it's all in good shape.

@jstac jstac merged commit b7c6464 into main Nov 8, 2025
1 check passed
@jstac jstac deleted the household_edits branch November 8, 2025 04:18
@mmcky
Copy link
Contributor

mmcky commented Nov 8, 2025

thanks @jstac -- this is a really nice change.

@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

Thanks @mmcky . when I worked through it all i realized what a mess it had become over time. disconnected logic, poor flow, repeated ideas, same ideas different names. it feels good to be starting to get it all back in shape again.

@mmcky
Copy link
Contributor

mmcky commented Nov 8, 2025

@jstac do you want me to make this live?

@jstac
Copy link
Contributor Author

jstac commented Nov 8, 2025

please hold off for now thanks @mmcky . there's a problem with the titles of the job search lectures that i'm fixing now.

@mmcky
Copy link
Contributor

mmcky commented Nov 8, 2025

thanks @jstac -- I'll stop asking, just ping me when you need a release 😄

Let me know if you need a proofread. Happy to do so.

I'm ducking out now but can take a look later today if you'd like.

@github-actions
Copy link

github-actions bot commented Nov 8, 2025

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants