Skip to content

Reform engine: support structural reforms beyond YAML parameter overlay #41

@vahid-ahmadi

Description

@vahid-ahmadi

Gap

src/reforms/mod.rs currently implements reforms as YAML parameter overlays. The recently-added interfaces/python/policyengine_uk_compiled/structural.py pre/post hook (#23) is a workaround that mutates inputs/outputs around the Rust binary — not a true structural reform.

Python's Reform system supports:

  • Callable transforms that can rewrite formulas
  • Variable neutralisation (zero out a variable everywhere)
  • Replacing a variable's class with a new implementation
  • Composing multiple reforms
  • Both parametric (parameter overrides) and structural (formula changes)

Examples to study:

  • policyengine_uk/reforms/conservatives/household_based_hitc.py — replaces a variable's calculation
  • policyengine_uk/reforms/policyengine/disable_simulated_benefits.py — neutralises variables
  • policyengine_uk/reforms/policyengine/adjust_budgets.py — composite reform
  • policyengine_uk/reforms/conservatives/, policyengine_uk/reforms/cps/, policyengine_uk/reforms/scotland/

Why it matters

Almost every PolicyEngine reform notebook (rail subsidy, salary-sacrifice cap, NICs reform, energy VAT, etc.) requires structural reforms — at minimum, swapping in a new formula for an existing variable. The Rust port cannot reproduce these analyses with parameter overrides alone.

Proposal

Design a Rust trait + registry where a reform can:

  1. Override parameters (current behaviour — keep)
  2. Replace a compute_* function with a custom implementation
  3. Neutralise (set output to zero) a named variable
  4. Compose other reforms

Expose this through the Python wrapper so reform authors can subclass in Python and have it dispatch into the Rust engine.

Effort

Large. This is foundational and unlocks issues for CGT reforms, salary-sacrifice cap, and most other notebooks.

References

  • Python: policyengine_uk/reforms/, policyengine_uk/system.py, policyengine_uk/tax_benefit_system.py
  • Rust: src/reforms/mod.rs, interfaces/python/policyengine_uk_compiled/structural.py

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions