Skip to content
Merged
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/abolish-benefit-cap-scenario.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an `abolish_benefit_cap` scenario for benefit-cap removal analysis.
14 changes: 13 additions & 1 deletion docs/book/usage/scenarios.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,18 @@ reformed_cap = reformed_sim.calculate("benefit_cap", 2026).mean()
print(f"Benefit cap - frozen: £{baseline_cap:.0f}/year, indexed: £{reformed_cap:.0f}/year")
```

If you want to remove the cap entirely for a poverty-analysis package, PolicyEngine
UK also exposes a reusable scenario:

```python
from policyengine_uk import Simulation
from policyengine_uk.scenarios import abolish_benefit_cap

sim = Simulation(situation=benefit_cap_family, scenario=abolish_benefit_cap)
benefit_cap_reduction = sim.calculate("benefit_cap_reduction", 2026).mean()
print(f"Benefit cap reduction after abolition: £{benefit_cap_reduction:.0f}")
```

## Advanced scenario techniques

### Time-varying parameters
Expand Down Expand Up @@ -571,4 +583,4 @@ for name, scenario in scenarios:
- Consider unintended interactions between different policy areas
```

These techniques let you model complex policy changes that go beyond simple parameter adjustments. Simulation modifiers give you complete control over how the tax-benefit system works, allowing you to implement everything from gradual phase-outs to dynamic eligibility changes. The key is to understand the underlying data structures and use them thoughtfully to represent real policy proposals.
These techniques let you model complex policy changes that go beyond simple parameter adjustments. Simulation modifiers give you complete control over how the tax-benefit system works, allowing you to implement everything from gradual phase-outs to dynamic eligibility changes. The key is to understand the underlying data structures and use them thoughtfully to represent real policy proposals.
1 change: 1 addition & 0 deletions policyengine_uk/scenarios/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .abolish_benefit_cap import abolish_benefit_cap
from .pip_reform import reform_pip_phase_in
from .reindex_benefit_cap import reindex_benefit_cap
from .repeal_two_child_limit import repeal_two_child_limit
Expand Down
12 changes: 12 additions & 0 deletions policyengine_uk/scenarios/abolish_benefit_cap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import numpy as np

from policyengine_uk.model_api import Scenario

abolish_benefit_cap = Scenario(
parameter_changes={
"gov.dwp.benefit_cap.single.in_london": {"year:2026:10": np.inf},
"gov.dwp.benefit_cap.single.outside_london": {"year:2026:10": np.inf},
"gov.dwp.benefit_cap.non_single.in_london": {"year:2026:10": np.inf},
"gov.dwp.benefit_cap.non_single.outside_london": {"year:2026:10": np.inf},
}
)
47 changes: 47 additions & 0 deletions policyengine_uk/tests/test_abolish_benefit_cap_scenario.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import numpy as np

from policyengine_uk import Simulation
from policyengine_uk.scenarios import abolish_benefit_cap

BENEFIT_CAP_FAMILY = {
"people": {
"parent1": {"age": {2026: 30}, "employment_income": {2026: 0}},
"parent2": {"age": {2026: 28}, "employment_income": {2026: 0}},
"child1": {"age": {2026: 6}},
"child2": {"age": {2026: 3}},
"child3": {"age": {2026: 1}},
},
"benunits": {
"family": {"members": ["parent1", "parent2", "child1", "child2", "child3"]}
},
"households": {
"home": {
"members": ["parent1", "parent2", "child1", "child2", "child3"],
"rent": {2026: 24_000},
}
},
}


class TestAbolishBenefitCapScenario:
def test_removes_benefit_cap_reduction(self):
baseline = Simulation(situation=BENEFIT_CAP_FAMILY)
reformed = Simulation(
situation=BENEFIT_CAP_FAMILY, scenario=abolish_benefit_cap
)

baseline_reduction = baseline.calculate("benefit_cap_reduction", 2026)
baseline_uc = baseline.calculate("universal_credit", 2026)
reformed_cap = reformed.calculate("benefit_cap", 2026)
reformed_reduction = reformed.calculate("benefit_cap_reduction", 2026)
reformed_uc = reformed.calculate("universal_credit", 2026)
reformed_uc_pre_cap = reformed.calculate(
"universal_credit_pre_benefit_cap", 2026
)

assert baseline_reduction[0] > 0
assert np.isfinite(baseline.calculate("benefit_cap", 2026)[0])
assert np.isinf(reformed_cap[0])
assert reformed_reduction.tolist() == [0.0]
assert reformed_uc.tolist() == reformed_uc_pre_cap.tolist()
assert reformed_uc[0] > baseline_uc[0]
Loading