build_from_populations keeps _user_input_keys for the holders it replaces
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
Research direction
Start in Simulation.build_from_populations, where the issue says populations and holders are replaced, and compare its handling of _user_input_keys with subsample. Add a regression test that sets an input, rebuilds without it, then calculates that period and checks the record no longer lists the input. The payload does not name a test file, so locate the existing simulation rebuild tests first.
Written by the indexing model from the issue text.
Description
Simulation.build_from_populations replaces every population, and so every holder, but keeps Simulation._user_input_keys. After a rebuild, the record of set_input values still lists (variable, branch, period) entries for values the new holders never received. This is the same drift as #559, through a path #561 did not cover. #561 keeps the record in step for Holder.delete_arrays and clone, and subsample resets it before rebuilding.
Reproduction (core only, 3.32.27; same code path in 3.33.0)
from policyengine_core import periods
from policyengine_core.country_template import CountryTaxBenefitSystem
from policyengine_core.simulations import SimulationBuilder
FEB = periods.period("2018-02")
tbs = CountryTaxBenefitSystem()
households = {"h": {"parents": ["a"]}}
sim = SimulationBuilder().build_from_entities(
tbs,
{
"persons": {"a": {"salary": {"2018-02": 1000}, "disposable_income": {"2018-02": 5000}}},
"households": households,
},
)
# Rebuild the same simulation with new populations and no disposable_income input.
sim.build_from_populations(tbs.instantiate_entities())
SimulationBuilder().build_from_entities(
tbs,
{"persons": {"a": {"salary": {"2018-01": 1000, "2018-02": 1000}}}, "households": households},
sim,
)
print(sim.get_holder("disposable_income")._get_array_from_storage(FEB)) # None
print(("disposable_income", "default", FEB) in sim._user_input_keys) # True
sim.calculate("disposable_income", "2018-02") # the formula value is cached under that record
Output on 3.32.27:
after rebuild: stored 2018-02: None
after rebuild: record has disposable_income 2018-02: True
calculated disposable_income 2018-02: [1430.0]
to_input_dataframe exports disposable_income: False ['salary__2018-01', 'salary__2018-02']
to_input_dataframe does not export the stale entry. Code that reads the record directly does see it, though. PolicyEngine-UK's supplied-input helpers (policyengine_uk/utils/supplied_inputs.py) treat a recorded (variable, branch, period) with a stored value as supplied. After a rebuild, a value carried over or calculated into that period passes as a supplied input. PE-UK reproduced this for a Class 4 trading loss: profits came out at £20,000 and NIC at £445.80, where they should be £30,000 and £1,045.80. PE-UK keeps a sweep in Simulation.calculate for this case (PolicyEngine/policyengine-uk#2260); it can go once core fixes the rebuild.
PE-UK's Simulation.build_from_situation calls build_from_populations(tax_benefit_system.instantiate_entities()) and then SimulationBuilder.build_from_dict(..., self). Its property tests rebuild cloned template simulations this way (test_state_pension_age.py, test_state_pension_credit_qualifying_age.py).
Suggested fix
In build_from_populations, reset _user_input_keys to an empty set, as subsample does. Every holder is new at that point, so none of the old entries can name a stored value. Also reset _user_input_contexts if no set_input can be running across a rebuild. Add a regression test: set an input, rebuild without it, calculate that period, and check that the record no longer names it.
- Dominant language
- Python
- Stars
- 22
- Forks
- 30
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 25
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from PolicyEngine/policyengine-core
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
PolicyEngine/policyengine-core#549 ·
Maintainers usually reply within 2 days
-
`restore_simulation` silently drops memberless group entitiesPossibly taken @Adelagric claimed this 34 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
PolicyEngine/policyengine-core#547 ·
Maintainers usually reply within 2 days
-
Difficulty 4/5 3-5 days Newbie friendliness 57/100
PolicyEngine/policyengine-core#614 ·
Maintainers usually reply within 2 days
-
A reform simulation's baseline reads the reform's default for people the situation gives no valuePossibly taken @MaxGhenis claimed this 2 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 35/100
PolicyEngine/policyengine-core#612 ·
Maintainers usually reply within 2 days
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
PolicyEngine/policyengine-core#609 ·
Maintainers usually reply within 2 days
All issues in PolicyEngine/policyengine-core
Similar issues
-
customer-reported question
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Azure/azure-sdk-for-python#49548 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
btclib-org/btclib-wallet#409 ·
Maintainers usually reply within 1 day
-
Phase 2 PSA Capability & Career Profile
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
bcgov/digital-journeys#2310 ·
-
bug good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
fastmachinelearning/hls4ml#1582 ·
Maintainers usually reply within 3 days
-
Sort modelsOpenenhancement good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Maintainers usually reply within 1 day