policyengine 5.2.0__tar.gz → 5.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {policyengine-5.2.0 → policyengine-5.3.0}/CHANGELOG.md +7 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/PKG-INFO +1 -1
- policyengine-5.3.0/examples/belgium_axiom_pilot.py +75 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/pyproject.toml +1 -1
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/bundle/manifest.json +10 -10
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/bundle/uk.trace.tro.jsonld +5 -5
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/bundle/us.trace.tro.jsonld +5 -5
- policyengine-5.3.0/src/policyengine/tax_benefit_models/be/__init__.py +29 -0
- policyengine-5.3.0/src/policyengine/tax_benefit_models/be/datasets.py +190 -0
- policyengine-5.3.0/src/policyengine/tax_benefit_models/be/model.py +363 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/PKG-INFO +1 -1
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/SOURCES.txt +5 -0
- policyengine-5.3.0/tests/test_be_axiom_pilot.py +613 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.claude/policyengine-guide.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.claude/quick-reference.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/CONTRIBUTING.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/bump_version.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/capture-version.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/changelog_template.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/check-changelog.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/copilot-instructions.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/dispatch-policyengine-release.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/fetch_version.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/get-changelog-diff.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/has-functional-changes.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/publish-git-tag.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/wait-for-pypi.sh +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/workflows/draft-pdf.yml +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/workflows/pr_code_changes.yaml +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/workflows/pr_docs_changes.yaml +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.github/workflows/push.yaml +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.gitignore +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/.python-version +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/AGENTS.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/CITATION.cff +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/CLAUDE.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/CODE_OF_CONDUCT.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/CONTRIBUTING.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/LICENSE +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/Makefile +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/README.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/architecture.png +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/architecture.svg +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/changelog.d/.gitkeep +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/.gitignore +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/_generator/README.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/_generator/build_reference.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/_quarto.yml +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/bundles.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/countries.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/data-publishing-design.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/decile-impact-spec.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/dev.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/engineering/runbooks/build-m-us-populace-certification.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/engineering/skills/README.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/engineering/skills/data-certification.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/engineering/skills/github-prs.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/engineering/skills/repository-guidance.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/examples.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/getting-started.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/households.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/impact-analysis.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/index.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/methodology/index.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/methodology/model-architecture.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/methodology/us-health-costs.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/microsim.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/outputs.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/programs/index.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/programs/us-chip.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/reference/index.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/reforms.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/regions.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/release-bundles.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/run-records.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/trace-case-study.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/docs/visualisation.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/employment_income_variation_uk.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/employment_income_variation_us.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/household_impact_example.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/income_bands_uk.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/income_distribution_us.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/paper_repro_uk.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/policy_change_uk.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/speedtest_us_simulation.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/examples/us_budgetary_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/paper-preview.html +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/paper.bib +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/paper.md +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/bundle.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/certify_data_release.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/check_data_staleness.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/export_bundle_release_assets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/generate_bundle_artifacts.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/generate_trace_tros.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/scripts/prepare_package_bundle_update.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/setup.cfg +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/bundle.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/cli.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/cache.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/dataset.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/dynamic.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/output.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/parameter.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/parameter_node.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/parameter_value.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/policy.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/region.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/run_record.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/scoping_strategy.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/simulation.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/tax_benefit_model.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/tax_benefit_model_version.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/core/variable.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/uk/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/uk/regions.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/data/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/data/districts.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/data/places.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/data/states.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/countries/us/regions.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/schemas/trace_tro.schema.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/data/uk_geography_assets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/derivations/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/derivations/narrate.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/derivations/trace.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/graph/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/graph/extractor.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/graph/graph.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/aggregate.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/change_aggregate.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/cliff_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/congressional_district_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/constituency_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/decile_analysis.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/decile_grouping.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/decile_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/extra_variables.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/inequality.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/intra_decile_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/labor_supply_response.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/local_authority_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/poverty.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/program_statistics.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/uk_geography_assets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/outputs/uk_geography_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/certification.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/dataset_materialization.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/manifest.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/pyproject_pins.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/trace.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/verify.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/provenance/zenodo.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/results/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/results/schema.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/results/trace_tro.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/results/tracking.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/axes.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/extra_variables.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/household.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/model_version.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/reform.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/common/result.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/uk/datasets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/uk/household.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/uk/model.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/us/analysis.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/us/datasets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/us/household.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/tax_benefit_models/us/model.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/dates.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/design.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/entity_utils.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/errors.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/hashing.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/household_validation.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/parameter_labels.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/parametric_reforms.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine/utils/plotting.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/dependency_links.txt +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/entry_points.txt +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/requires.txt +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/src/policyengine.egg-info/top_level.txt +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/conftest.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/filtering_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/uk_couple_two_kids.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/uk_model_surface.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/uk_single_adult_employment_income.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/uk_single_adult_no_income.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/uk_single_parent_one_child.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/us_married_two_kids_high_income.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/us_model_surface.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/us_single_adult_employment_income.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/us_single_adult_no_income.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/household_calculator_snapshots/us_single_parent_one_child.json +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/parameter_labels_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/region_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/us_reform_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/fixtures/variable_label_fixtures.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_aggregate.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_budgetary_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_bump_version.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_bundle.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_bundle_metadata.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_cache.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_certify_data_release.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_change_aggregate.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_cliff_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_cliff_impact_analysis.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_congressional_district_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_constituency_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_dataset_materialization.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_dataset_persistence.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_dataset_runtime.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_dataset_source.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_decile_grouping.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_derivations.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_dict_reforms_on_simulation.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_entity_mapping.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_entity_utils.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_entity_utils_characterization.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_errors.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_extra_variables.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_filtering.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_graph/__init__.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_graph/conftest.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_graph/test_extractor.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_household_calculator_snapshot.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_household_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_inequality.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_intra_decile_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_labor_supply_response.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_local_authority_impact.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_manifest_version_mismatch.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_models.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_pandas3_compatibility.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_parameter_labels.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_parameter_nodes.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_parameter_values.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_parametric_reforms.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_poverty.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_poverty_by_demographics.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_poverty_run.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_preservation_mirror.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_program_statistics.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_pyproject_pins.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_region.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_region_group_strategy.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_release_manifests.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_results.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_run_record.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_scoping_strategy.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_small_follow_ups.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_trace_tro.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_trace_tro_verify.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_uk_analysis.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_uk_geography_assets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_uk_program_statistics.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_uk_regions.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_us_long_term_datasets.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_us_microsim_structural_reforms.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_us_program_statistics.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_us_reform_application.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_us_regions.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_variable_labels.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_variable_metadata.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/tests/test_zenodo_mirror.py +0 -0
- {policyengine-5.2.0 → policyengine-5.3.0}/uv.lock +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [5.3.0] - 2026-08-30
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- Belgium pilot: add an Axiom-backed model over Microcosm-BE entity tables with content-bound RuleSpec/engine provenance, separately labeled data and policy periods, metadata-preserving HDF5 round trips, nonuniform calibrated-weight coverage, and in-memory outputs that cannot overwrite their inputs.
|
|
6
|
+
|
|
7
|
+
|
|
1
8
|
## [5.2.0] - 2026-08-29
|
|
2
9
|
|
|
3
10
|
### Added
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Belgium population microsimulation through the Axiom rules engine.
|
|
2
|
+
|
|
3
|
+
Runs the calibrated populace-be pilot dataset (populace-us support records
|
|
4
|
+
reweighted to Statbel/SPF/ONSS/ONEM targets from PolicyEngine/ledger)
|
|
5
|
+
through the rulespec-be composed worker pipeline, and scores the aggregates
|
|
6
|
+
against Belgian administrative facts.
|
|
7
|
+
|
|
8
|
+
This is a demonstration of the engine channel, not a certified Belgian
|
|
9
|
+
model: the support records are American, and coverage is the worker slice
|
|
10
|
+
(employee SSC with the statutory low-wage work bonus, and individual PIT
|
|
11
|
+
before withholding with the fiscal work-bonus credit).
|
|
12
|
+
|
|
13
|
+
The pilot's unpublished source stack currently requires Python 3.14: install
|
|
14
|
+
``microcosm-frame`` from PolicyEngine/microcosm, plus the
|
|
15
|
+
``axiom-rules-engine`` Python wrapper and dense extension from source. Their
|
|
16
|
+
current checkouts must agree on the canonical RuleSpec-root loader API. The
|
|
17
|
+
output is intentionally in memory (``filepath=None``) so it cannot overwrite
|
|
18
|
+
the input artifact; set a distinct output filepath explicitly before saving.
|
|
19
|
+
|
|
20
|
+
Usage::
|
|
21
|
+
|
|
22
|
+
POPULACE_BE_DATASET=.../populace_be_pilot_2026.h5 \\
|
|
23
|
+
RULESPEC_BE_ROOT=.../rulespec-be \\
|
|
24
|
+
uv run python examples/belgium_axiom_pilot.py
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import os
|
|
28
|
+
|
|
29
|
+
from policyengine.core.simulation import Simulation
|
|
30
|
+
from policyengine.tax_benefit_models.be import (
|
|
31
|
+
EMPLOYEE_SSC,
|
|
32
|
+
PIT_BEFORE_WITHHOLDING,
|
|
33
|
+
AxiomBelgiumPilot,
|
|
34
|
+
PopulaceBelgiumDataset,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
DATASET = os.environ["POPULACE_BE_DATASET"]
|
|
38
|
+
RULESPEC = os.environ.get("RULESPEC_BE_ROOT", "~/TheAxiomFoundation/rulespec-be")
|
|
39
|
+
|
|
40
|
+
# Ledger facts (PolicyEngine/ledger, Belgian publisher packages)
|
|
41
|
+
ONSS_WORKER_CONTRIBUTIONS_2024 = 20_836_582_673
|
|
42
|
+
SPF_PIT_BEFORE_WITHHOLDING_2023 = 62_840_116_134
|
|
43
|
+
|
|
44
|
+
dataset = PopulaceBelgiumDataset(
|
|
45
|
+
name="populace-be-pilot",
|
|
46
|
+
description="populace-us support reweighted to Belgian ledger targets",
|
|
47
|
+
filepath=DATASET,
|
|
48
|
+
year=2026,
|
|
49
|
+
)
|
|
50
|
+
model_version = AxiomBelgiumPilot(rulespec_root=RULESPEC, period=2025)
|
|
51
|
+
|
|
52
|
+
simulation = Simulation(dataset=dataset, tax_benefit_model_version=model_version)
|
|
53
|
+
simulation.run()
|
|
54
|
+
|
|
55
|
+
output = simulation.output_dataset
|
|
56
|
+
person = output.data.person
|
|
57
|
+
ssc_net = person[EMPLOYEE_SSC].sum()
|
|
58
|
+
pit = person[PIT_BEFORE_WITHHOLDING].sum()
|
|
59
|
+
|
|
60
|
+
print("Belgium pilot (Axiom engine over populace-be, worker slice)")
|
|
61
|
+
print(
|
|
62
|
+
f" data vintage {output.year}; policy period {output.policy_period}; "
|
|
63
|
+
f"model {model_version.version}"
|
|
64
|
+
)
|
|
65
|
+
print(f" employee SSC after work bonus EUR {ssc_net / 1e9:6.2f}B")
|
|
66
|
+
print(" (ONSS 2024 contributions: EUR 20.84B; the bonus is outsized here")
|
|
67
|
+
print(" because the US-support wage distribution is low-wage-heavy)")
|
|
68
|
+
print(
|
|
69
|
+
f" PIT before withholding EUR {pit / 1e9:6.2f}B "
|
|
70
|
+
"(SPF 2023, all PIT: EUR 62.84B)"
|
|
71
|
+
)
|
|
72
|
+
print(
|
|
73
|
+
f" PIT vs SPF ratio {pit / SPF_PIT_BEFORE_WITHHOLDING_2023:.3f}"
|
|
74
|
+
" (worker slice only)"
|
|
75
|
+
)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bundle_version": "5.
|
|
2
|
+
"bundle_version": "5.3.0",
|
|
3
3
|
"citation": {
|
|
4
4
|
"publisher": "PolicyEngine",
|
|
5
|
-
"title": "PolicyEngine bundle 5.
|
|
5
|
+
"title": "PolicyEngine bundle 5.3.0",
|
|
6
6
|
"type": "software-bundle",
|
|
7
|
-
"version": "5.
|
|
7
|
+
"version": "5.3.0"
|
|
8
8
|
},
|
|
9
9
|
"countries": {
|
|
10
10
|
"uk": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"data_releases": {
|
|
18
18
|
"uk": {
|
|
19
19
|
"build_id": "policyengine-uk-data-1.56.16",
|
|
20
|
-
"bundle_id": "uk-5.
|
|
20
|
+
"bundle_id": "uk-5.3.0",
|
|
21
21
|
"certification": {
|
|
22
22
|
"built_with_model_git_sha": "12a1e028afeef08d8b2d74ee03fd9de3a78b2dd3",
|
|
23
23
|
"built_with_model_version": "2.89.2",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"version": "2.90.2",
|
|
100
100
|
"wheel_url": "https://files.pythonhosted.org/packages/ec/da/658bff2df6094bd7bf2b0f561ff60fd41508adbd0a3af29b4553c83bc678/policyengine_uk-2.90.2-py3-none-any.whl"
|
|
101
101
|
},
|
|
102
|
-
"policyengine_version": "5.
|
|
102
|
+
"policyengine_version": "5.3.0",
|
|
103
103
|
"region_datasets": {
|
|
104
104
|
"national": {
|
|
105
105
|
"path_template": "enhanced_frs_2024_25.h5"
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
},
|
|
113
113
|
"us": {
|
|
114
114
|
"build_id": "populace-us-2024-buildp-sparse-rmloss100-cae8640-20260728T011454Z",
|
|
115
|
-
"bundle_id": "us-5.
|
|
115
|
+
"bundle_id": "us-5.3.0",
|
|
116
116
|
"certification": {
|
|
117
117
|
"built_with_model_version": "1.764.6",
|
|
118
118
|
"certified_by": "policyengine.py bundle certification",
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
"version": "1.764.6",
|
|
187
187
|
"wheel_url": "https://files.pythonhosted.org/packages/e2/5a/0566666f30ad06e416f0cf25b24bdee73acd71897fb2de3c0ac43b59e3e3/policyengine_us-1.764.6-py3-none-any.whl"
|
|
188
188
|
},
|
|
189
|
-
"policyengine_version": "5.
|
|
189
|
+
"policyengine_version": "5.3.0",
|
|
190
190
|
"region_datasets": {
|
|
191
191
|
"national": {
|
|
192
192
|
"path_template": "populace_us_2024.h5"
|
|
@@ -254,10 +254,10 @@
|
|
|
254
254
|
"packages": {
|
|
255
255
|
"policyengine": {
|
|
256
256
|
"import_name": "policyengine",
|
|
257
|
-
"install_requirement": "policyengine==5.
|
|
257
|
+
"install_requirement": "policyengine==5.3.0",
|
|
258
258
|
"name": "policyengine",
|
|
259
259
|
"role": "bundle_carrier",
|
|
260
|
-
"version": "5.
|
|
260
|
+
"version": "5.3.0"
|
|
261
261
|
},
|
|
262
262
|
"policyengine-core": {
|
|
263
263
|
"import_name": "policyengine_core",
|
|
@@ -283,6 +283,6 @@
|
|
|
283
283
|
"version": "1.764.6"
|
|
284
284
|
}
|
|
285
285
|
},
|
|
286
|
-
"policyengine_version": "5.
|
|
286
|
+
"policyengine_version": "5.3.0",
|
|
287
287
|
"schema_version": 2
|
|
288
288
|
}
|
|
@@ -18,18 +18,18 @@
|
|
|
18
18
|
"schema:url": "https://policyengine.org"
|
|
19
19
|
},
|
|
20
20
|
"schema:dateCreated": "2026-08-18T14:20:32.100961Z",
|
|
21
|
-
"schema:description": "TRACE TRO for certified runtime bundle uk-5.
|
|
21
|
+
"schema:description": "TRACE TRO for certified runtime bundle uk-5.3.0 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
|
|
22
22
|
"schema:name": "policyengine uk certified bundle TRO",
|
|
23
23
|
"trov:createdWith": {
|
|
24
24
|
"@type": "schema:SoftwareApplication",
|
|
25
25
|
"schema:name": "policyengine",
|
|
26
|
-
"schema:softwareVersion": "5.
|
|
26
|
+
"schema:softwareVersion": "5.3.0"
|
|
27
27
|
},
|
|
28
28
|
"trov:hasArrangement": [
|
|
29
29
|
{
|
|
30
30
|
"@id": "arrangement/1",
|
|
31
31
|
"@type": "trov:ArtifactArrangement",
|
|
32
|
-
"rdfs:comment": "Certified arrangement for bundle uk-5.
|
|
32
|
+
"rdfs:comment": "Certified arrangement for bundle uk-5.3.0.",
|
|
33
33
|
"trov:hasArtifactLocation": [
|
|
34
34
|
{
|
|
35
35
|
"@id": "arrangement/1/location/bundle_manifest",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@type": "trov:ResearchArtifact",
|
|
76
76
|
"schema:name": "policyengine.py bundle manifest for uk",
|
|
77
77
|
"trov:mimeType": "application/json",
|
|
78
|
-
"trov:sha256": "
|
|
78
|
+
"trov:sha256": "57c6fe9c5c370ea2b9460120656004b1a583db06cabb6c774551effc3c125695"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"@id": "composition/1/artifact/data_release_manifest",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"trov:hasFingerprint": {
|
|
103
103
|
"@id": "composition/1/fingerprint",
|
|
104
104
|
"@type": "trov:CompositionFingerprint",
|
|
105
|
-
"trov:sha256": "
|
|
105
|
+
"trov:sha256": "90a113dd7e642af4c137af233b512fa7ff68b5ba0aa9b4102b7dd02bd8fe5cbf"
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"trov:hasPerformance": {
|
|
@@ -18,18 +18,18 @@
|
|
|
18
18
|
"schema:url": "https://policyengine.org"
|
|
19
19
|
},
|
|
20
20
|
"schema:dateCreated": "2026-07-28T03:56:03.415544+00:00",
|
|
21
|
-
"schema:description": "TRACE TRO for certified runtime bundle us-5.
|
|
21
|
+
"schema:description": "TRACE TRO for certified runtime bundle us-5.3.0 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
|
|
22
22
|
"schema:name": "policyengine us certified bundle TRO",
|
|
23
23
|
"trov:createdWith": {
|
|
24
24
|
"@type": "schema:SoftwareApplication",
|
|
25
25
|
"schema:name": "policyengine",
|
|
26
|
-
"schema:softwareVersion": "5.
|
|
26
|
+
"schema:softwareVersion": "5.3.0"
|
|
27
27
|
},
|
|
28
28
|
"trov:hasArrangement": [
|
|
29
29
|
{
|
|
30
30
|
"@id": "arrangement/1",
|
|
31
31
|
"@type": "trov:ArtifactArrangement",
|
|
32
|
-
"rdfs:comment": "Certified arrangement for bundle us-5.
|
|
32
|
+
"rdfs:comment": "Certified arrangement for bundle us-5.3.0.",
|
|
33
33
|
"trov:hasArtifactLocation": [
|
|
34
34
|
{
|
|
35
35
|
"@id": "arrangement/1/location/bundle_manifest",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"@type": "trov:ResearchArtifact",
|
|
76
76
|
"schema:name": "policyengine.py bundle manifest for us",
|
|
77
77
|
"trov:mimeType": "application/json",
|
|
78
|
-
"trov:sha256": "
|
|
78
|
+
"trov:sha256": "57c6fe9c5c370ea2b9460120656004b1a583db06cabb6c774551effc3c125695"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"@id": "composition/1/artifact/data_release_manifest",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"trov:hasFingerprint": {
|
|
103
103
|
"@id": "composition/1/fingerprint",
|
|
104
104
|
"@type": "trov:CompositionFingerprint",
|
|
105
|
-
"trov:sha256": "
|
|
105
|
+
"trov:sha256": "c9806c4dbc8cb664ca2ed431af72f8540c08171fea5ce02d6e579f2d6866cf21"
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"trov:hasPerformance": {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Belgium pilot: Axiom rules engine over Microcosm entity tables.
|
|
2
|
+
|
|
3
|
+
The first non-policyengine-core country in policyengine.py. Statutes are
|
|
4
|
+
encoded as RuleSpec YAML (TheAxiomFoundation/rulespec-be), compiled and
|
|
5
|
+
executed by axiom-rules-engine, and driven over Microcosm-BE entity tables.
|
|
6
|
+
See ``examples/belgium_axiom_pilot.py`` for the end-to-end population run
|
|
7
|
+
and ``model.py`` for scope and source-install requirements.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .datasets import BEYearData, PopulaceBelgiumDataset
|
|
11
|
+
from .model import (
|
|
12
|
+
EMPLOYEE_SSC,
|
|
13
|
+
PIT_BEFORE_WITHHOLDING,
|
|
14
|
+
REMUNERATION,
|
|
15
|
+
AxiomBelgium,
|
|
16
|
+
AxiomBelgiumPilot,
|
|
17
|
+
be_model,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"AxiomBelgium",
|
|
22
|
+
"AxiomBelgiumPilot",
|
|
23
|
+
"BEYearData",
|
|
24
|
+
"EMPLOYEE_SSC",
|
|
25
|
+
"PIT_BEFORE_WITHHOLDING",
|
|
26
|
+
"PopulaceBelgiumDataset",
|
|
27
|
+
"REMUNERATION",
|
|
28
|
+
"be_model",
|
|
29
|
+
]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Belgium pilot dataset: Microcosm entity tables with calibrated weights.
|
|
2
|
+
|
|
3
|
+
The pilot layout has two entities (person, household), mirroring the
|
|
4
|
+
Microcosm ``BE_SCHEMA``. Files are pandas HDF5 stores with ``person``,
|
|
5
|
+
``household``, and ``_time_period`` keys. The canonical Microcosm-BE layout
|
|
6
|
+
stores calibrated weights once, on the household table; PolicyEngine derives
|
|
7
|
+
effective person weights through ``person_household_id`` when loading. Legacy
|
|
8
|
+
files may also carry ``person_weight``, but that redundant copy must match the
|
|
9
|
+
household weights exactly. Dataset metadata and the optional policy period are
|
|
10
|
+
stored as attributes on the ``_time_period`` record so the current
|
|
11
|
+
``microcosm.frame`` reader can ignore them while PolicyEngine can round-trip
|
|
12
|
+
them.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any, ClassVar, Optional
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
import pandas as pd
|
|
21
|
+
from microdf import MicroDataFrame
|
|
22
|
+
from pydantic import ConfigDict, Field
|
|
23
|
+
|
|
24
|
+
from policyengine.core import Dataset, YearData
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _person_with_household_weights(
|
|
28
|
+
person: pd.DataFrame,
|
|
29
|
+
household: pd.DataFrame,
|
|
30
|
+
) -> pd.DataFrame:
|
|
31
|
+
"""Return persons with effective weights derived from household weights."""
|
|
32
|
+
person_membership = "person_household_id"
|
|
33
|
+
household_id = "household_id"
|
|
34
|
+
household_weight = "household_weight"
|
|
35
|
+
for table_name, table, required in (
|
|
36
|
+
("person", person, person_membership),
|
|
37
|
+
("household", household, household_id),
|
|
38
|
+
("household", household, household_weight),
|
|
39
|
+
):
|
|
40
|
+
if required not in table.columns:
|
|
41
|
+
raise ValueError(
|
|
42
|
+
f"Belgium {table_name} table is missing required column {required!r}."
|
|
43
|
+
)
|
|
44
|
+
duplicate_ids = household[household_id].duplicated(keep=False)
|
|
45
|
+
if duplicate_ids.any():
|
|
46
|
+
values = household.loc[duplicate_ids, household_id].drop_duplicates().tolist()
|
|
47
|
+
raise ValueError(f"Belgium household_id values must be unique; found {values}.")
|
|
48
|
+
if household[household_weight].isna().any():
|
|
49
|
+
raise ValueError("Belgium household_weight values must not be null.")
|
|
50
|
+
|
|
51
|
+
weight_by_household = household.set_index(household_id)[household_weight]
|
|
52
|
+
derived = person[person_membership].map(weight_by_household)
|
|
53
|
+
if derived.isna().any():
|
|
54
|
+
missing = (
|
|
55
|
+
person.loc[derived.isna(), person_membership].drop_duplicates().tolist()
|
|
56
|
+
)
|
|
57
|
+
raise ValueError(
|
|
58
|
+
"Belgium person_household_id values must resolve to household rows; "
|
|
59
|
+
f"missing {missing}."
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if "person_weight" in person.columns:
|
|
63
|
+
legacy = pd.to_numeric(person["person_weight"], errors="coerce")
|
|
64
|
+
if legacy.isna().any() or not np.array_equal(
|
|
65
|
+
legacy.to_numpy(dtype=float),
|
|
66
|
+
derived.to_numpy(dtype=float),
|
|
67
|
+
):
|
|
68
|
+
raise ValueError(
|
|
69
|
+
"Legacy Belgium person_weight values do not exactly match the "
|
|
70
|
+
"effective household_weight values."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
result = person.copy()
|
|
74
|
+
result["person_weight"] = derived.to_numpy(copy=True)
|
|
75
|
+
return result
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class BEYearData(YearData):
|
|
79
|
+
"""Entity-level data for a single Belgian year."""
|
|
80
|
+
|
|
81
|
+
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
82
|
+
|
|
83
|
+
person: MicroDataFrame
|
|
84
|
+
household: MicroDataFrame
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def entity_data(self) -> dict[str, MicroDataFrame]:
|
|
88
|
+
return {"person": self.person, "household": self.household}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class PopulaceBelgiumDataset(Dataset):
|
|
92
|
+
"""Belgium pilot dataset loaded from a Microcosm-BE HDF5 artifact.
|
|
93
|
+
|
|
94
|
+
``year`` identifies the input dataset vintage. ``policy_period`` is set on
|
|
95
|
+
derived outputs and identifies the year of law executed by Axiom. Keeping
|
|
96
|
+
both fields prevents a 2025-policy run over a 2026-vintage population from
|
|
97
|
+
being mislabeled as though those were the same period.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
data: Optional[BEYearData] = None
|
|
101
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
102
|
+
policy_period: Optional[int] = None
|
|
103
|
+
|
|
104
|
+
_TIME_PERIOD_KEY: ClassVar[str] = "_time_period"
|
|
105
|
+
_METADATA_ATTRIBUTE: ClassVar[str] = "policyengine_metadata_json"
|
|
106
|
+
_POLICY_PERIOD_ATTRIBUTE: ClassVar[str] = "policyengine_policy_period"
|
|
107
|
+
|
|
108
|
+
def load(self) -> None:
|
|
109
|
+
if self.filepath is None:
|
|
110
|
+
raise ValueError("Cannot load a Belgium pilot dataset without a filepath.")
|
|
111
|
+
with pd.HDFStore(self.filepath, mode="r") as store:
|
|
112
|
+
person = store["person"]
|
|
113
|
+
household = store["household"]
|
|
114
|
+
if f"/{self._TIME_PERIOD_KEY}" in store.keys():
|
|
115
|
+
stored_year = int(store[self._TIME_PERIOD_KEY].iloc[0])
|
|
116
|
+
if stored_year != self.year:
|
|
117
|
+
raise ValueError(
|
|
118
|
+
"Belgium dataset period mismatch: "
|
|
119
|
+
f"constructor year={self.year}, HDF5 "
|
|
120
|
+
f"{self._TIME_PERIOD_KEY}={stored_year}."
|
|
121
|
+
)
|
|
122
|
+
attributes = store.get_storer(self._TIME_PERIOD_KEY).attrs
|
|
123
|
+
metadata_json = getattr(attributes, self._METADATA_ATTRIBUTE, None)
|
|
124
|
+
if metadata_json is not None:
|
|
125
|
+
stored_metadata = json.loads(str(metadata_json))
|
|
126
|
+
if self.metadata and self.metadata != stored_metadata:
|
|
127
|
+
raise ValueError(
|
|
128
|
+
"Belgium dataset metadata differs from the metadata "
|
|
129
|
+
"stored in its HDF5 artifact."
|
|
130
|
+
)
|
|
131
|
+
self.metadata = stored_metadata
|
|
132
|
+
stored_policy_period = getattr(
|
|
133
|
+
attributes, self._POLICY_PERIOD_ATTRIBUTE, None
|
|
134
|
+
)
|
|
135
|
+
if stored_policy_period is not None:
|
|
136
|
+
stored_policy_period = int(stored_policy_period)
|
|
137
|
+
if (
|
|
138
|
+
self.policy_period is not None
|
|
139
|
+
and self.policy_period != stored_policy_period
|
|
140
|
+
):
|
|
141
|
+
raise ValueError(
|
|
142
|
+
"Belgium dataset policy-period mismatch: "
|
|
143
|
+
f"constructor policy_period={self.policy_period}, "
|
|
144
|
+
f"HDF5 policy period={stored_policy_period}."
|
|
145
|
+
)
|
|
146
|
+
self.policy_period = stored_policy_period
|
|
147
|
+
person = _person_with_household_weights(person, household)
|
|
148
|
+
self.data = BEYearData(
|
|
149
|
+
person=MicroDataFrame(person, weights="person_weight"),
|
|
150
|
+
household=MicroDataFrame(household, weights="household_weight"),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def save(self) -> None:
|
|
154
|
+
if self.data is None:
|
|
155
|
+
raise ValueError("No data to save.")
|
|
156
|
+
if self.filepath is None:
|
|
157
|
+
raise ValueError("Cannot save a Belgium pilot dataset without a filepath.")
|
|
158
|
+
# Serialize before opening in mode="w": invalid metadata must not
|
|
159
|
+
# truncate an existing destination.
|
|
160
|
+
metadata_json = json.dumps(
|
|
161
|
+
self.metadata,
|
|
162
|
+
allow_nan=False,
|
|
163
|
+
separators=(",", ":"),
|
|
164
|
+
sort_keys=True,
|
|
165
|
+
)
|
|
166
|
+
household = pd.DataFrame(self.data.household)
|
|
167
|
+
person = _person_with_household_weights(
|
|
168
|
+
pd.DataFrame(self.data.person),
|
|
169
|
+
household,
|
|
170
|
+
)
|
|
171
|
+
filepath = Path(self.filepath)
|
|
172
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
173
|
+
with pd.HDFStore(filepath, mode="w") as store:
|
|
174
|
+
# Microcosm carries only explicit entity weights. Person weights
|
|
175
|
+
# are inherited from households and reconstructed on load.
|
|
176
|
+
store["person"] = person.drop(columns=["person_weight"])
|
|
177
|
+
store["household"] = household
|
|
178
|
+
store.put(
|
|
179
|
+
self._TIME_PERIOD_KEY,
|
|
180
|
+
pd.Series([self.year]),
|
|
181
|
+
format="table",
|
|
182
|
+
)
|
|
183
|
+
attributes = store.get_storer(self._TIME_PERIOD_KEY).attrs
|
|
184
|
+
setattr(attributes, self._METADATA_ATTRIBUTE, metadata_json)
|
|
185
|
+
if self.policy_period is not None:
|
|
186
|
+
setattr(
|
|
187
|
+
attributes,
|
|
188
|
+
self._POLICY_PERIOD_ATTRIBUTE,
|
|
189
|
+
int(self.policy_period),
|
|
190
|
+
)
|