Divide bequest pools by actual group populations, not birth shares - #1187
Open
marcelolafleur wants to merge 2 commits into
Open
Divide bequest pools by actual group populations, not birth shares#1187marcelolafleur wants to merge 2 commits into
marcelolafleur wants to merge 2 commits into
Conversation
With demographics varying across lifetime income groups (PR PSLmodels#1165), group population shares no longer equal lambdas: survivorship differs by group. The use_zeta=False branch of household.get_bq still divided each group's bequest pool by lambdas[j], so bequests received did not sum to bequests left (about +6.5% over-distribution in an OG-ZAF calibration with South African mortality gradients) and the steady state failed the aggregate resource constraint by about 1% of GDP. Divide by the group's actual population share instead — omega_SS[:, j] for the steady state, per-period omega sums along the time path — matching what the use_zeta=True branch already does. When demographics are common across groups the two coincide, so existing results are unchanged (all existing get_bq tests pass unmodified). Adds a conservation test with non-separable omega covering SS and TPI, by-j and pooled. Fixes PSLmodels#1186.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1187 +/- ##
==========================================
+ Coverage 72.66% 72.68% +0.01%
==========================================
Files 22 22
Lines 5726 5730 +4
==========================================
+ Hits 4161 4165 +4
Misses 1565 1565
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
marcelolafleur
marked this pull request as ready for review
July 28, 2026 20:44
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.
Fixes #1186.
With demographics that vary across lifetime income groups (#1165), each group's population share no longer equals its birth share
lambdas[j]and survivorship differs by group. Theuse_zeta = Falsebranch ofhousehold.get_bqstill divided each group's bequest pool bylambdas[j], so bequests received did not sum to bequests left. In an OG-ZAF calibration with South African mortality gradients, households collectively received about 6.5% more bequests than existed, and the steady state failed the aggregate resource constraint by about 1% of GDP.The fix: divide each group's pool by its actual population share:
omega_SS[:, j].sum()in the steady state, per-periodomegasums along the time path, which is what theuse_zeta = Truebranch already does. When demographics are common across groups the two denominators coincide, so results are unchanged in every pre-#1165 use case: all existingget_bqtests pass without modification.Tests: adds a conservation test with a non-separable
omega(group population shares deliberately different fromlambdas) checking that receipts aggregate back to the pool for SS and TPI, by-group and pooled.tests/test_household.pypasses 52/52 locally.cc: @rickecon @jdebacker