Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/fix-person-entity-id-int-2267.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Store `person_household_id` and `person_benunit_id` as integers, like the other identifier variables, so identifiers above 16,777,216 read back exactly from `calculate`, `to_input_dataframe()` and `UKSingleYearDataset.from_simulation`. A simulation built from a policyengine-core dataset file no longer merges households or benefit units whose identifiers rounded to the same number. A simulation now gives an `EntityIdWarning` when an identifier is not a whole number from -2,147,483,648 to 2,147,483,647, the range it can store exactly.
7 changes: 7 additions & 0 deletions docs/book/usage/simulations.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,13 @@ Each table should contain the ID columns needed to link entities together:
- `benunit`: `benunit_id`, plus any benefit-unit variables
- `household`: `household_id`, plus any household-level variables

Whatever the data source, keep identifiers to whole numbers from
-2,147,483,648 to 2,147,483,647. A simulation stores them as 32-bit integers,
so within that range the identifiers it returns (for example
`sim.calculate("person_household_id", 2025)`) are the ones in your tables.
Outside it, the simulation gives an `EntityIdWarning`: the identifiers it
returns differ from yours, and so may anything rebuilt from them.

Use `UKSingleYearDataset` when you have one cross-section and want PolicyEngine
UK to extend it forward using its standard uprating assumptions.

Expand Down
21 changes: 21 additions & 0 deletions policyengine_uk/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
UKMultiYearDataset,
UKSingleYearDataset,
)
from policyengine_uk.utils.entity_ids import ENTITY_ID_VARIABLES, check_entity_ids
from policyengine_uk.utils.scenario import Scenario
from policyengine_uk.data.economic_assumptions import (
extend_single_year_dataset,
Expand Down Expand Up @@ -553,11 +554,31 @@ def build_from_ids(
person_household_id: Array mapping persons to households
benunit_id: Array of benefit unit IDs
household_id: Array of household IDs

Warns:
EntityIdWarning: If an ID is not a whole number, or is outside the
range of the variable that stores it, so that the stored ID
differs from the one given.
"""
from policyengine_core.simulations.simulation_builder import (
SimulationBuilder,
) # Import here to avoid circular dependency

# The callers store these columns as the variables' values after
# building the entities, and exports and rebuilds read them from there.
# The populations below take the arrays as given.
for variable_name, ids in zip(
ENTITY_ID_VARIABLES,
(
person_id,
person_benunit_id,
person_household_id,
benunit_id,
household_id,
),
):
check_entity_ids(self.tax_benefit_system.variables[variable_name], ids)

builder = SimulationBuilder()
builder.populations = self.tax_benefit_system.instantiate_entities()

Expand Down
Loading
Loading