Repository navigation
Fix formula reads with ADD or DIVIDE in a Microsimulation - #647
Merged
Merged
Conversation
…vide Population.__call__ passes decode_enums=False to calculate_add or calculate_divide for every options=[ADD] or options=[DIVIDE] read in a formula, as it has since 0abe43a. Simulation's methods take that argument, but Microsimulation's overrides did not, so every such read raised a TypeError in a Microsimulation. Both overrides now take decode_enums, with Simulation's default of False, and pass it to super(). Simulation.calculate_add and calculate_divide accept the flag without using it, so every call that worked before returns the same values. Example tests run formulas that read with ADD and DIVIDE on a small country-template system. Hypothesis properties check that a Microsimulation's unweighted reads equal a Simulation's over generated data and read sequences, and that formula results equal the same arithmetic in NumPy. A strict xfail records that an Enum read with DIVIDE returns labels in a Microsimulation and an EnumArray in a Simulation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a Microsimulation, calculate_add and calculate_divide return a MicroSeries, and pandas pairs two Series' values by index label. GroupPopulation.project labels each member's value with its group's position. So a formula that projected such a read and combined it with another Series raised a ValueError, or, when every group had one member and the data listed them out of group order, paired members with another group's value. policyengine-us's wi_wheap_categorically_eligible has that shape (lines 38-44). Population.__call__ now returns the NumPy array a Simulation returns for these reads. They raised a TypeError in every Microsimulation on master, so no value that computed before moves. The fixture now takes each person's household, so data can list members in any order, and adds fee_or_all_paid, a reader with the PE-US formula's shape. The Enum DIVIDE test now records both classes' results instead of failing as a strict xfail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…order Population calls and calculate_add and calculate_divide requests now pair each variable with periods its option accepts, and population calls read only variables the population can read, so they return values instead of mostly raising in both classes. The data lists people in any order. hypothesis.event reports the mix of values, zeros and errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… run A new property checks that each population call a formula makes with ADD or DIVIDE returns a NumPy array in both classes. The NumPy-arithmetic property now runs for each formula, 25 examples each: with 100 examples drawn across all ten, one seeded run never drew fee_or_all_paid or members_grant_divided. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pandas 3 returns a read-only view from Series.to_numpy(), so in a Microsimulation a formula that wrote to such a read would raise "ValueError: assignment destination is read-only" where a Simulation computes. Copy the values instead, and test that population calls return writable arrays in both classes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The NumPy reference sums a household's grants and then divides by 12, while a household's DIVIDE read divides each member's float32 grant by 12 and then sums. Whole grants that nearly cancel, such as 9,990 and -10,000 in one household, made members_grant_divided return -0.83331299 against -0.83333333, past rtol=1e-6, so the property could fail by chance. With yearly amounts in multiples of 12, every monthly share is whole, every sum and share is exact in float32, and the property checks exact equality. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
November 11, 2026 05:41
Contributor
Author
|
I'm handing this PR to the US + core hub to land. The independent review approves, and CI passes at
|
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 12, 2026
PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
7 tasks done
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 12, 2026
…LIHEAP cooling registry notes (#10730) * Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ents Population.__call__ sends a formula's read to calculate, calculate_add or calculate_divide with one set of keyword arguments. For each calculate method that Microsimulation overrides, the test binds every keyword call that Simulation's method takes to the override. On master, the four calls that pass decode_enums to calculate_add or calculate_divide fail. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
In a Microsimulation, Population.__call__ gets a MicroSeries from a read with ADD or DIVIDE and copied it with result.to_numpy(copy=True). microdf warns on every MicroSeries.to_numpy call that the result carries no weights, and it reports the warning at the caller's line, so each such read in a formula raised a UserWarning at population.py. numpy.array copies the values into a new array that the formula can write to, and it calls neither MicroSeries.to_numpy nor MicroSeries.values. The new test reads a person variable and a household variable with each option and checks that no warning mentions MicroSeries. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Master and 3.36.0 raise the TypeError on these reads before any to_numpy call, so no release emitted the microdf warning that the second fragment described. Delete that fragment, and state the first in one sentence, as docs/engineering/skills/github-prs.md asks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Arkansas LIHEAP summer regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Arkansas LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pay Arkansas LIHEAP cooling to unsubsidized renters with utilities in rent Plan item 3.3 makes these renters eligible. Rewords the energy account comments, adds an in-rent renter case, and checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Stop Arkansas LIHEAP income limits at the federal maximum Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Cite HHS's FY2025 median income table for the capped limits Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: cap case, fuel condition, rent-route tests Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Georgia LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Georgia LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply Georgia LIHEAP cooling review fixes Describes the lower income limit as the Level I limit, checks the national liheap total, and records the cooling benefit amounts in the source-conflict candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Point the Georgia floor candidate at the moved income test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: in-rent route, fuel condition, ruling record Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Oklahoma LIHEAP regular summer cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Oklahoma LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply Oklahoma LIHEAP cooling review fixes Points the Register reference at its first cited page, describes the guideline lag by benefit year, checks the national liheap total, and records the cooling income boundary in the source-conflict candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: pinning cases, ruling record, fuel condition Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Louisiana LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Louisiana LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pay Louisiana LIHEAP cooling to renters with utilities in rent Guide section 3.6 E.1 pays these renters; the subsidized energy-cost gate still applies. Adds the allowance-equals-bill boundary, an in-rent renter case, and the national liheap total check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Correct the EIA bill figure in Louisiana cooling test comments Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Note the accepted FY2027 Louisiana plan in the income rate comment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: fuel condition and pinning cases Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply review suggestions 5 and 6: cooling-season note, utility-allowance candidate covers cooling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Kentucky LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Kentucky LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pay Kentucky LIHEAP cooling to renters with utilities in rent 921 KAR 4:116 Section 4(3)(a)2 pays the landlord for these renters. The income-point bands now use heating's guideline year, which reproduces the FY2026 workbook; the income limit keeps the 2026 guideline. Updates shared parameter descriptions, test comments and margins, and checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: rent-route cases and fuel condition Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add South Carolina LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count South Carolina LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply South Carolina LIHEAP cooling review fixes Records the FY2026 and FY2027 plan service limits, describes the age thresholds for heating and cooling, tightens test margins, and checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: FY2027 one-award limit and fuel condition Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Alabama LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Alabama LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Verify Alabama LIHEAP cooling for FY2025 and pay in-rent renters Adds the FY2025 plan, the February 2025 benefit chart and the FY2027 plan as references, a FY2025 case, and an in-rent renter case. Manual section 6.1.3 pays unsubsidized renters with utilities in rent. Marks 2025-2026 verified and checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Stop Alabama LIHEAP income limits at the federal maximum and drop a removed plan link Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Cite HHS's FY2025 median income table for the capped limits Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: 2025 heating cap sizes, fuel condition, pinning cases Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Nebraska LIHEAP regular cooling assistance Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Nebraska LIHEAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply Nebraska LIHEAP cooling review fixes Points the eligibility reference at its first cited page, adds the DHHS energy assistance page, describes the guideline lag by federal fiscal year, and checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Cite Nebraska's FY2027 Guidance Document for the cooling tables Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: in-rent route, fuel condition, pinning cases Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
added a commit
to PolicyEngine/policyengine-us
that referenced
this pull request
Nov 15, 2026
* Add a national LIHEAP total and LIHEAP cooling registry notes Sum each state's regular LIHEAP payment in a new liheap variable, add an Illinois regular heating payment without crisis assistance, add a Michigan Home Heating Credit registry entry, and record each state's cooling treatment in its registry note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add Virginia EAP cooling assistance electric bill payment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Count Virginia EAP cooling in the national LIHEAP total Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Guard the LIHEAP payment list and reword the Rhode Island cooling note Add regular_payments.yaml to the aggregate-list integrity test, which checks that each member exists, is state-gated and is not dropped between year blocks. Say that Rhode Island plans no regular cooling payment, since its FY2027 plan still allows a leftover-funds cooling grant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Apply Virginia LIHEAP cooling review fixes Dates the cooling guideline lag from FY2025, fixes the electric bill maximum comment, cites the EIA 2024 average bill in the tests, and adds a retiree case that checks the national liheap total. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Make state LIHEAP formulas run in a microsimulation The national `liheap` total evaluates every state's formula over a mixed-state population, which no household test does. Two patterns on main raised errors there: - 26 formula files passed options=[ADD] to an entity call. Core's Microsimulation.calculate_add rejects the keyword an entity call passes. The option is redundant: a plain read already sums a monthly variable over the year through the same Core function. - The DC and Illinois payment formulas look up a matrix by an income level that is 0 for households outside the state. Add the floor Maryland and Kansas already use. Also: - Reword the North Dakota registry note: the state reserves an optional direct cooling payment, so its cooling component is not only equipment. - Add a `liheap` case with Texas, DC and Illinois households in one simulation. - Add a code-health check against options=[ADD] and options=[DIVIDE]. - Check that every state payment in the LIHEAP registry entry is in the list `liheap` sums. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Drop the options=[ADD] code-health check PolicyEngine/policyengine-core#647 fixes the cause in Core: it lets a Microsimulation accept the keyword an entity call passes with options=[ADD] or options=[DIVIDE]. Once that is released the option works again, so a check that bans it here would be wrong. The 26 formula files stay without the option, which was redundant and lets `liheap` run on today's Core. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Pin the Wayback capture of the 2023 Virginia cooling release Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> * Label the WYDaily citation for Virginia's cooling guideline year as a press report Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Pin the Michigan, California and Illinois list entries and add the program prefix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix issues from review: subsidized heat-in-rent ruling, fuel condition, size pin Addresses DTrim99's round-1 review; upstream main merged first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
US + core hub merge audit, core#647 at
🤖 Generated with Claude Code |
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.
On master, a formula that reads a variable with
options=[ADD]oroptions=[DIVIDE]raises this error in aMicrosimulation, though aSimulationcomputes it:A policyengine-us impact run hit the error on
spm_unit("snap", period, options=[ADD])inmt_liheap_categorical_eligibility.py(PolicyEngine/policyengine-us#10141 (comment)). At PolicyEngine/policyengine-us@2b39b88e2f, 21 formulas read withoptions=[ADD], and each raised the error whenever it ran in aMicrosimulation. In PolicyEngine/policyengine-us#10730, we replaced theoptions=[ADD]reads in 26 formula files with plain reads to avoid the error. No formula on policyengine-us main (PolicyEngine/policyengine-us@61c743cb61) reads with an option.Cause
Population.__call__has passeddecode_enums=Falsewith every read since 0abe43a (December 2022), and it sends reads withoptions=[ADD]oroptions=[DIVIDE]tocalculate_addorcalculate_divide(population.py#L147-L163).Simulation.calculate_addandcalculate_dividetake it (simulation.py#L2057-L2062, #L2126-L2131), butMicrosimulationoverrides both without it (microsimulation.py#L84-L118), so Python rejects the call.Plain reads go to
calculate, which takes the flag. When a formula reads a monthly flow over a year or a yearly flow over a month,Simulation._calculatecallscalculate_addorcalculate_dividewithout the flag (simulation.py#L1741-L1753), so those reads kept working.Fix
Both overrides now take
decode_enums: bool = False,Simulation's default, and pass it tosuper().Simulation.calculate_addandcalculate_divideaccept the flag without using it, and the new parameter goes last, so every direct call that worked before returns the same values.Population.__call__now returns a NumPy array for a read with ADD or DIVIDE, as aSimulationdoes (population.py#L167-L178). In aMicrosimulationthe overrides return aMicroSeries, and pandas pairs two Series' values by index label.GroupPopulation.projectlabels each member's value with its group's position (group_population.py#L366-L370). So a formula that projected such a read and combined it with another Series would raise microdf'sValueError: Cannot propagate weights unambiguously to these rows(microdf 1.5.11 and 1.5.12). If every group had one member and the data listed them out of group order, members would get other groups' values without an error. At 2b39b88e2f, policyengine-us'swi_wheap_categorically_eligibleprojected its ADD read ofsnapto members and combined it with a person-level read ofssi(lines 33-44).Population.__call__copies the values withnumpy.array, which returns a new writable array that shares no memory with the Series and keeps its dtype for numbers and booleans. pandas 3 returns a read-only view of a Series' values, so a formula that wrote to the view would raiseValueError: assignment destination is read-only, while the same formula computes in aSimulation. From version 1.2.2, microdf warns on everyMicroSeries.to_numpyor.valuescall that the result carries no weights (PolicyEngine/microdf#278), andnumpy.arraycalls neither.On master these reads raised the
TypeErrorin every coreMicrosimulation, and aSimulationalready returns arrays, so the conversion moves no value that computed before. Converting inPopulation.__call__leaves direct calls alone:calculate_add(..., use_weights=False)worked on master and still returns aMicroSeries.Invariants and tests
tests/fixtures/microsimulation_option_reads.pyadds to the country template ten formulas that read with ADD or DIVIDE. They read person and household variables, sum members' values into households, compare a sum with zero and call theaddhelper. One of them,fee_or_all_paid, projects a household's ADD read to its members.tests/core/test_microsimulation_option_reads_property.pychecks three properties with Hypothesis:Microsimulation's unweighted reads equal aSimulation's, or both raise the same type of error. Hypothesis generates one to four households of one to three people, listed in any order, with weights, whole monthly amounts, yearly amounts in multiples of 12 and up to six reads in sequence. The reads cover the formulas, the population calls they make,calculate_addandcalculate_dividewith either value ofdecode_enums, and plain reads at months, years and a three-month period. Population calls and the two methods read each variable over periods its option accepts.hypothesis.eventrecords each read's outcome, and in two 200-example runs, population calls returned nonzero values in 19% and 31% of examples and raised in none.Example tests in
tests/core/test_microsimulation_option_reads.pycheck hand-computed values for each formula and forfee_or_all_paidon two one-person households listed in reverse order. They also check that seven population calls return writable arrays equal to aSimulation's, the weights on a weighted result, and both methods with each value ofdecode_enums. Four more check that population calls raise no microdf warning aboutMicroSeriesvalues. microdf added that warning in 1.2.2, so those four can fail only under microdf 1.2.2 or later.uv.lockpins 1.2.1, and CI installs without the lock and resolves 1.5.12.tests/core/test_microsimulation_calculate_signatures.pybinds each keyword call thatSimulation.calculate,calculate_add,calculate_divideandcalculate_dataframetake, with every subset of their optional arguments, toMicrosimulation's override. It checks only that each keyword call binds. So it can't catch an override that takes a flag and ignores it, a default that differs fromSimulation's, a keyword thatPopulation.__call__passes andSimulationlacks (unweighted), or an override in a country package. Positional calls already differed on master:Microsimulation.calculate_addtakesmap_tothird, whereSimulation.calculate_addtakesdecode_enums. SoMicrosimulation.calculate_add(name, period, True)passesTrueasmap_toand raisesKeyError: True. No caller in core or on policyengine-us main passes a third argument by position.On master, 44 of the 62 new tests fail (21 signature tests, 29 example tests and 12 property tests). In 40 the
Microsimulationraises theTypeError, and the signature test rejects the 4 keyword calls that passdecode_enumstocalculate_addorcalculate_divide. The other 18 check the NumPy reference alone or bind calls that master's overrides already take. Without the conversion inPopulation.__call__, 10 fail, and Hypothesis falsifies all three properties.fee_or_all_paidraises theValueError, the reverse-order case returns[True, False]against theSimulation's[False, True], and five population calls return aMicroSeries. With.to_numpy()in place of the copy, 10 fail: five population calls return read-only arrays, four calls raise microdf's warning, and Hypothesis falsifies the second property. With.to_numpy(copy=True), the four warning tests fail.In CI, on this branch merged with master, core's full suite passes, the 62 new tests included, on Ubuntu and Windows under Python 3.11 to 3.14 with microdf 1.5.12.
ruff format --check .passes too.policyengine-us
No formula on policyengine-us main reads with an option, so this change moves no policyengine-us result there. With it, a policyengine-us formula can again read with
options=[ADD]oroptions=[DIVIDE]in aMicrosimulation. No policyengine-usMicrosimulationhas run on this branch.A formula can still get a
MicroSeriesfrom a plain read thatSimulation._calculatesends tocalculate_add, such asadd(person, period, ["ssi"]). ThatMicroSerieslabels values by position, so it pairs correctly with arrays and with unprojected reads of its entity. On main,wi_wheap_categorically_eligibleprojects a plain read ofsnapand ORs it withadd(person, period, ["ssi"]) > 0, so the second gap below applies to it. By our reading of the code, aMicrosimulationwould raise microdf'sValueErrorthere only when this formula reads bothssiandsnapover the year before any other formula does.Remaining gaps
Simulation.calculate_addandcalculate_divideread each term withself.calculate, which in aMicrosimulationdecodes Enums and applies weights by default (simulation.py#L2093-L2096, #L2152-L2160). So an Enum read with DIVIDE over a year returns member names in aMicrosimulationand anEnumArrayin aSimulation. On master that read raised theTypeError. Now a formula that compares it with a member, asread == Tenure.OWNERdoes in the test, gets False for every person, where aSimulationgets[True, False, True].test_enum_read_with_divide_over_a_year_gives_member_names_in_a_microsimulationrecords both results. For the same reason, an Enum read with ADD, or with DIVIDE over a month, raises aTypeErrorin aMicrosimulation, andcalculate_add(..., use_weights=False)returns aMicroSeriesthat still carries weights.Microsimulationcomputes a plain read thatSimulation._calculatesends tocalculate_addorcalculate_divide, the read still returns a weightedMicroSeriesto the formula, as on master. A formula that projects one and combines it with another Series pairs values by label too. Once theMicrosimulationhas cached the value, after an earlier plain read or a read with ADD or DIVIDE, a later plain read returns the cached array instead. The holder stores it withnumpy.asarray, which under pandas 3 gives a read-only view of theMicroSeries. So a formula that writes to that read raisesValueError: assignment destination is read-only, while aSimulationcomputes the same formula. On master, a formula that wrote to a second such read raised the same error. No formula on policyengine-us main writes in place to a value it takes straight from an entity read.Simulation, a read with ADD or DIVIDE can hand the formula the array the simulation stores. DIVIDE over a year returns the stored yearly value, so a write to it changes every later read. ADD over a year of a monthly flow and DIVIDE over a month of a yearly flow return the value they cache. A write to that value changes later plain reads at that period, while a later read with the option computes the value again. In aMicrosimulation,Population.__call__copies these reads, so after such a write the two classes return different values. No formula on policyengine-us main reads with ADD or DIVIDE.Microsimulationbut has "micro" in its name, such as policyengine-uk's,Population.__call__passesunweighted=Trueto the calculate methods.Simulation.calculate_addandcalculate_dividedon't accept that argument, so a read with ADD or DIVIDE in such a class raises aTypeError. On policyengine-uk main (PolicyEngine/policyengine-uk@d3db7ac07d), only two test reads use an option, and both expect policyengine-uk'sStoredDrawErrorbefore the read reaches core.impact: no output moves for any variable that computed before; formulas that read with
options=[ADD]oroptions=[DIVIDE]now compute in aMicrosimulation(policyengine-us main has none since PolicyEngine/policyengine-us#10730)axiom: n/a: core infrastructure fix
🤖 Generated with Claude Code