policyengine-uk 2.45.4__py3-none-any.whl → 2.47.2__py3-none-any.whl
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.
Potentially problematic release.
This version of policyengine-uk might be problematic. Click here for more details.
- policyengine_uk/__init__.py +1 -0
- policyengine_uk/data/dataset_schema.py +6 -3
- policyengine_uk/data/economic_assumptions.py +1 -1
- policyengine_uk/dynamics/labour_supply.py +306 -0
- policyengine_uk/dynamics/participation.py +629 -0
- policyengine_uk/dynamics/progression.py +376 -0
- policyengine_uk/microsimulation.py +23 -1
- policyengine_uk/parameters/gov/dynamic/obr_labour_supply_assumptions.yaml +9 -0
- policyengine_uk/parameters/gov/economic_assumptions/yoy_growth.yaml +270 -32
- policyengine_uk/simulation.py +184 -9
- policyengine_uk/tax_benefit_system.py +4 -1
- policyengine_uk/tests/microsimulation/reforms_config.yaml +7 -7
- policyengine_uk/tests/microsimulation/test_validity.py +2 -3
- policyengine_uk/tests/microsimulation/update_reform_impacts.py +104 -40
- policyengine_uk/tests/policy/baseline/gov/dfe/extended_childcare_entitlement/extended_childcare_entitlement.yaml +8 -8
- policyengine_uk/utils/__init__.py +1 -0
- policyengine_uk/utils/compare.py +28 -0
- policyengine_uk/utils/solve_private_school_attendance_factor.py +4 -6
- policyengine_uk/variables/gov/dwp/additional_state_pension.py +1 -1
- policyengine_uk/variables/gov/dwp/basic_state_pension.py +1 -1
- policyengine_uk/variables/household/demographic/benunit/benunit_count_adults.py +11 -0
- policyengine_uk/variables/input/consumption/property/council_tax.py +0 -35
- policyengine_uk/variables/input/rent.py +0 -40
- {policyengine_uk-2.45.4.dist-info → policyengine_uk-2.47.2.dist-info}/METADATA +5 -4
- {policyengine_uk-2.45.4.dist-info → policyengine_uk-2.47.2.dist-info}/RECORD +27 -21
- {policyengine_uk-2.45.4.dist-info → policyengine_uk-2.47.2.dist-info}/WHEEL +0 -0
- {policyengine_uk-2.45.4.dist-info → policyengine_uk-2.47.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
"""Labour supply progression (intensive margin) dynamics module.
|
|
2
|
+
|
|
3
|
+
This module handles the intensive margin of labour supply - how people adjust their
|
|
4
|
+
working hours in response to policy changes. It implements the elasticity-based
|
|
5
|
+
methodology from the OBR's labour supply framework.
|
|
6
|
+
|
|
7
|
+
Reference: https://obr.uk/docs/dlm_uploads/NICS-Cut-Impact-on-Labour-Supply-Note.pdf
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import pandas as pd
|
|
12
|
+
from policyengine_uk import Simulation
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def calculate_derivative(
|
|
16
|
+
sim: Simulation,
|
|
17
|
+
target_variable: str = "household_net_income",
|
|
18
|
+
input_variable: str = "employment_income",
|
|
19
|
+
year: int = 2025,
|
|
20
|
+
count_adults: int = 2,
|
|
21
|
+
delta: float = 1_000,
|
|
22
|
+
) -> np.ndarray:
|
|
23
|
+
"""Calculate the marginal rate of change of target variable with respect to input variable.
|
|
24
|
+
|
|
25
|
+
This function computes numerical derivatives by applying small changes to the input
|
|
26
|
+
variable and measuring the resulting change in the target variable. This is used
|
|
27
|
+
to estimate marginal tax rates and benefit withdrawal rates.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
sim: PolicyEngine simulation object
|
|
31
|
+
target_variable: Variable to measure changes in (typically household_net_income)
|
|
32
|
+
input_variable: Variable to change (typically employment_income)
|
|
33
|
+
year: Year for calculation
|
|
34
|
+
count_adults: Number of adults to apply changes to
|
|
35
|
+
delta: Size of change to apply for derivative calculation (£)
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Array of marginal rates clipped between 0 and 1
|
|
39
|
+
"""
|
|
40
|
+
# Get baseline values for input variable and identify adults
|
|
41
|
+
input_variable_values = sim.calculate(input_variable, year)
|
|
42
|
+
adult_index = sim.calculate("adult_index")
|
|
43
|
+
entity_key = sim.tax_benefit_system.variables[input_variable].entity.key
|
|
44
|
+
|
|
45
|
+
# Calculate baseline target values
|
|
46
|
+
original_target_values = sim.calculate(
|
|
47
|
+
target_variable, year, map_to=entity_key
|
|
48
|
+
)
|
|
49
|
+
new_target_values = original_target_values.copy()
|
|
50
|
+
|
|
51
|
+
# Apply delta change to each adult sequentially to calculate marginal effects
|
|
52
|
+
for i in range(count_adults):
|
|
53
|
+
gets_pay_rise = adult_index == i + 1
|
|
54
|
+
new_input_variable_values = input_variable_values.copy()
|
|
55
|
+
new_input_variable_values[gets_pay_rise] += delta
|
|
56
|
+
sim.reset_calculations()
|
|
57
|
+
sim.set_input(input_variable, year, new_input_variable_values)
|
|
58
|
+
new_target_values[gets_pay_rise] = sim.calculate(
|
|
59
|
+
target_variable, year, map_to=entity_key
|
|
60
|
+
)[gets_pay_rise]
|
|
61
|
+
|
|
62
|
+
# Calculate marginal rate as change in target per unit change in input
|
|
63
|
+
rel_marginal_wages = (new_target_values - original_target_values) / delta
|
|
64
|
+
|
|
65
|
+
# Set non-adult observations to NaN
|
|
66
|
+
rel_marginal_wages[
|
|
67
|
+
~pd.Series(adult_index).isin(range(1, count_adults + 1))
|
|
68
|
+
] = np.nan
|
|
69
|
+
|
|
70
|
+
# Clip to ensure rates are between 0 and 1 (0% to 100% retention)
|
|
71
|
+
return rel_marginal_wages.clip(0, 1)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def calculate_relative_income_change(
|
|
75
|
+
sim: Simulation,
|
|
76
|
+
target_variable: str = "household_net_income",
|
|
77
|
+
year: int = 2025,
|
|
78
|
+
) -> pd.DataFrame:
|
|
79
|
+
"""Calculate relative change in income between baseline and scenario.
|
|
80
|
+
|
|
81
|
+
This function compares the target variable values between the baseline
|
|
82
|
+
simulation and the reform scenario to measure the income effect of the policy.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
sim: PolicyEngine simulation object (should have baseline attribute)
|
|
86
|
+
target_variable: Variable to measure changes in
|
|
87
|
+
year: Year for calculation
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
DataFrame with baseline, scenario, relative change, and absolute change columns
|
|
91
|
+
"""
|
|
92
|
+
# Get income values from baseline and reform scenarios
|
|
93
|
+
original_target_values = sim.baseline.calculate(
|
|
94
|
+
target_variable, year, map_to="person"
|
|
95
|
+
)
|
|
96
|
+
reformed_target_values = sim.calculate(
|
|
97
|
+
target_variable, year, map_to="person"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Calculate relative change, handling division by zero
|
|
101
|
+
rel_change = (
|
|
102
|
+
reformed_target_values - original_target_values
|
|
103
|
+
) / original_target_values
|
|
104
|
+
rel_change[original_target_values == 0] = np.nan
|
|
105
|
+
|
|
106
|
+
# Clip extreme values and fill NaN with 0
|
|
107
|
+
rel_changes = rel_change.clip(-1, 1).fillna(0)
|
|
108
|
+
|
|
109
|
+
return pd.DataFrame(
|
|
110
|
+
{
|
|
111
|
+
"baseline": original_target_values,
|
|
112
|
+
"scenario": reformed_target_values,
|
|
113
|
+
"rel_change": rel_changes,
|
|
114
|
+
"abs_change": reformed_target_values - original_target_values,
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def calculate_derivative_change(
|
|
120
|
+
sim: Simulation,
|
|
121
|
+
target_variable: str = "household_net_income",
|
|
122
|
+
input_variable: str = "employment_income",
|
|
123
|
+
year: int = 2025,
|
|
124
|
+
count_adults: int = 1,
|
|
125
|
+
delta: float = 1_000,
|
|
126
|
+
) -> pd.DataFrame:
|
|
127
|
+
"""Calculate change in marginal rates between baseline and scenario.
|
|
128
|
+
|
|
129
|
+
This function computes how marginal tax rates or benefit withdrawal rates
|
|
130
|
+
change as a result of the policy reform, which drives substitution effects
|
|
131
|
+
in labour supply responses.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
sim: PolicyEngine simulation object (should have baseline attribute)
|
|
135
|
+
target_variable: Variable to measure marginal rates for
|
|
136
|
+
input_variable: Variable to change for derivative calculation
|
|
137
|
+
year: Year for calculation
|
|
138
|
+
count_adults: Number of adults to calculate derivatives for
|
|
139
|
+
delta: Size of change for derivative calculation (£)
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
DataFrame with baseline, scenario, relative change, and absolute change in derivatives
|
|
143
|
+
"""
|
|
144
|
+
# Calculate marginal rates under baseline and reform scenarios
|
|
145
|
+
original_deriv = calculate_derivative(
|
|
146
|
+
sim=sim.baseline,
|
|
147
|
+
target_variable=target_variable,
|
|
148
|
+
input_variable=input_variable,
|
|
149
|
+
year=year,
|
|
150
|
+
count_adults=count_adults,
|
|
151
|
+
delta=delta,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
reformed_deriv = calculate_derivative(
|
|
155
|
+
sim=sim,
|
|
156
|
+
target_variable=target_variable,
|
|
157
|
+
input_variable=input_variable,
|
|
158
|
+
year=year,
|
|
159
|
+
count_adults=count_adults,
|
|
160
|
+
delta=delta,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Calculate relative and absolute changes in marginal rates
|
|
164
|
+
rel_change = reformed_deriv / original_deriv - 1
|
|
165
|
+
abs_change = reformed_deriv - original_deriv
|
|
166
|
+
|
|
167
|
+
# Clip extreme relative changes to avoid misleading results from small baseline derivatives
|
|
168
|
+
rel_change = rel_change.clip(-1, 1)
|
|
169
|
+
|
|
170
|
+
rel_change[rel_change == np.inf] = 0
|
|
171
|
+
|
|
172
|
+
return pd.DataFrame(
|
|
173
|
+
{
|
|
174
|
+
"baseline": original_deriv,
|
|
175
|
+
"scenario": reformed_deriv,
|
|
176
|
+
"rel_change": rel_change,
|
|
177
|
+
"abs_change": abs_change,
|
|
178
|
+
}
|
|
179
|
+
).fillna(0)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def calculate_labour_substitution_elasticities(
|
|
183
|
+
sim: Simulation,
|
|
184
|
+
) -> np.ndarray:
|
|
185
|
+
"""Calculate labour supply substitution elasticities by demographic group.
|
|
186
|
+
|
|
187
|
+
Uses OBR elasticity estimates to assign substitution elasticities based on
|
|
188
|
+
gender, marital status, and presence/age of children. These elasticities
|
|
189
|
+
measure how labour supply responds to changes in marginal tax rates.
|
|
190
|
+
|
|
191
|
+
Reference: https://obr.uk/docs/dlm_uploads/NICS-Cut-Impact-on-Labour-Supply-Note.pdf
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
sim: PolicyEngine simulation object
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
Array of substitution elasticities for each person
|
|
198
|
+
"""
|
|
199
|
+
# Get demographic characteristics for elasticity assignment
|
|
200
|
+
gender = sim.calculate("gender")
|
|
201
|
+
is_married = sim.calculate("is_married", map_to="person")
|
|
202
|
+
has_children = sim.calculate("benunit_count_children", map_to="person") > 0
|
|
203
|
+
youngest_child_age = sim.calculate("youngest_child_age", map_to="person")
|
|
204
|
+
|
|
205
|
+
# Initialize elasticity array
|
|
206
|
+
elasticities = np.zeros(gender.shape, dtype=float)
|
|
207
|
+
|
|
208
|
+
# Married or cohabiting women - higher elasticities, especially with young children
|
|
209
|
+
married_women = (gender == "FEMALE") & is_married
|
|
210
|
+
elasticities[married_women & ~has_children] = 0.14 # No children
|
|
211
|
+
|
|
212
|
+
# Elasticities vary significantly by youngest child's age
|
|
213
|
+
elasticities[married_women & has_children & (youngest_child_age <= 2)] = (
|
|
214
|
+
0.301 # 0-2 years
|
|
215
|
+
)
|
|
216
|
+
elasticities[
|
|
217
|
+
married_women
|
|
218
|
+
& has_children
|
|
219
|
+
& (youngest_child_age >= 3)
|
|
220
|
+
& (youngest_child_age <= 4)
|
|
221
|
+
] = 0.439 # 3-4 years (highest)
|
|
222
|
+
elasticities[
|
|
223
|
+
married_women
|
|
224
|
+
& has_children
|
|
225
|
+
& (youngest_child_age >= 5)
|
|
226
|
+
& (youngest_child_age <= 10)
|
|
227
|
+
] = 0.173 # 5-10 years
|
|
228
|
+
elasticities[married_women & has_children & (youngest_child_age >= 11)] = (
|
|
229
|
+
0.160 # 11+ years
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Lone parents - lower elasticities than married women, reflecting different constraints
|
|
233
|
+
lone_parents = (gender == "FEMALE") & ~is_married & has_children
|
|
234
|
+
elasticities[lone_parents & (youngest_child_age <= 4)] = 0.094 # 0-4 years
|
|
235
|
+
elasticities[
|
|
236
|
+
lone_parents & (youngest_child_age >= 5) & (youngest_child_age <= 10)
|
|
237
|
+
] = 0.128 # 5-10 years
|
|
238
|
+
elasticities[
|
|
239
|
+
lone_parents & (youngest_child_age >= 11) & (youngest_child_age <= 18)
|
|
240
|
+
] = 0.136 # 11-18 years
|
|
241
|
+
|
|
242
|
+
# Men (excluding lone fathers) - moderate, consistent elasticity
|
|
243
|
+
elasticities[(gender == "MALE") & ~(~is_married & has_children)] = 0.15
|
|
244
|
+
|
|
245
|
+
# Single women without children - same as men
|
|
246
|
+
elasticities[(gender == "FEMALE") & ~is_married & ~has_children] = 0.15
|
|
247
|
+
|
|
248
|
+
return elasticities
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def calculate_labour_net_income_elasticities(
|
|
252
|
+
sim: Simulation,
|
|
253
|
+
) -> np.ndarray:
|
|
254
|
+
"""Calculate labour supply income elasticities by demographic group.
|
|
255
|
+
|
|
256
|
+
Uses OBR elasticity estimates to assign income elasticities based on
|
|
257
|
+
gender, marital status, and presence/age of children. These elasticities
|
|
258
|
+
measure how labour supply responds to changes in unearned income.
|
|
259
|
+
|
|
260
|
+
Reference: https://obr.uk/docs/dlm_uploads/NICS-Cut-Impact-on-Labour-Supply-Note.pdf
|
|
261
|
+
Table A2 - Income elasticities
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
sim: PolicyEngine simulation object
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
Array of income elasticities for each person (typically negative)
|
|
268
|
+
"""
|
|
269
|
+
# Get demographic characteristics for elasticity assignment
|
|
270
|
+
gender = sim.calculate("gender")
|
|
271
|
+
is_married = sim.calculate("is_married", map_to="person")
|
|
272
|
+
has_children = sim.calculate("benunit_count_children", map_to="person") > 0
|
|
273
|
+
youngest_child_age = sim.calculate("youngest_child_age", map_to="person")
|
|
274
|
+
|
|
275
|
+
# Initialize elasticity array
|
|
276
|
+
elasticities = np.zeros(gender.shape, dtype=float)
|
|
277
|
+
|
|
278
|
+
# Married or cohabiting women - negative income elasticities (normal good)
|
|
279
|
+
married_women = (gender == "FEMALE") & is_married
|
|
280
|
+
elasticities[married_women & ~has_children] = (
|
|
281
|
+
0.0 # No income effect without children
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# Stronger negative income effects with younger children
|
|
285
|
+
elasticities[married_women & has_children & (youngest_child_age <= 2)] = (
|
|
286
|
+
-0.185
|
|
287
|
+
) # 0-2 years
|
|
288
|
+
elasticities[
|
|
289
|
+
married_women
|
|
290
|
+
& has_children
|
|
291
|
+
& (youngest_child_age >= 3)
|
|
292
|
+
& (youngest_child_age <= 4)
|
|
293
|
+
] = -0.173 # 3-4 years
|
|
294
|
+
elasticities[
|
|
295
|
+
married_women
|
|
296
|
+
& has_children
|
|
297
|
+
& (youngest_child_age >= 5)
|
|
298
|
+
& (youngest_child_age <= 10)
|
|
299
|
+
] = -0.102 # 5-10 years
|
|
300
|
+
elasticities[married_women & has_children & (youngest_child_age >= 11)] = (
|
|
301
|
+
-0.063
|
|
302
|
+
) # 11+ years
|
|
303
|
+
|
|
304
|
+
# Lone parents - smaller negative income effects than married women
|
|
305
|
+
lone_parents = (gender == "FEMALE") & ~is_married & has_children
|
|
306
|
+
elasticities[lone_parents & (youngest_child_age <= 4)] = (
|
|
307
|
+
-0.037
|
|
308
|
+
) # 0-4 years
|
|
309
|
+
elasticities[
|
|
310
|
+
lone_parents & (youngest_child_age >= 5) & (youngest_child_age <= 10)
|
|
311
|
+
] = -0.075 # 5-10 years
|
|
312
|
+
elasticities[
|
|
313
|
+
lone_parents & (youngest_child_age >= 11) & (youngest_child_age <= 18)
|
|
314
|
+
] = -0.054 # 11-18 years
|
|
315
|
+
|
|
316
|
+
# Men (excluding lone fathers) - small negative income effect
|
|
317
|
+
elasticities[(gender == "MALE") & ~(~is_married & has_children)] = -0.05
|
|
318
|
+
|
|
319
|
+
# Single women without children - same as men
|
|
320
|
+
elasticities[(gender == "FEMALE") & ~is_married & ~has_children] = -0.05
|
|
321
|
+
|
|
322
|
+
return elasticities
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def calculate_employment_income_change(
|
|
326
|
+
employment_income: np.ndarray,
|
|
327
|
+
derivative_changes: pd.DataFrame,
|
|
328
|
+
income_changes: pd.DataFrame,
|
|
329
|
+
substitution_elasticities: np.ndarray,
|
|
330
|
+
income_elasticities: np.ndarray,
|
|
331
|
+
) -> np.ndarray:
|
|
332
|
+
"""Calculate total labour supply response combining substitution and income effects.
|
|
333
|
+
|
|
334
|
+
This function implements the Slutsky equation decomposition of labour supply
|
|
335
|
+
responses into substitution and income effects. The total response is the
|
|
336
|
+
sum of these two components.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
employment_income: Baseline employment income levels
|
|
340
|
+
derivative_changes: Changes in marginal rates (substitution effect driver)
|
|
341
|
+
income_changes: Changes in income levels (income effect driver)
|
|
342
|
+
substitution_elasticities: Elasticities for substitution effects
|
|
343
|
+
income_elasticities: Elasticities for income effects
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Array of employment income changes due to labour supply responses
|
|
347
|
+
"""
|
|
348
|
+
# Calculate substitution effect: response to changes in marginal rates
|
|
349
|
+
substitution_response = (
|
|
350
|
+
employment_income
|
|
351
|
+
* derivative_changes["wage_rel_change"]
|
|
352
|
+
* substitution_elasticities
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Calculate income effect: response to changes in unearned income
|
|
356
|
+
income_response = (
|
|
357
|
+
employment_income
|
|
358
|
+
* income_changes["income_rel_change"]
|
|
359
|
+
* income_elasticities
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
# Total labour supply response is sum of substitution and income effects
|
|
363
|
+
total_response = substitution_response + income_response
|
|
364
|
+
|
|
365
|
+
# No response for people with zero employment income
|
|
366
|
+
total_response[employment_income == 0] = 0
|
|
367
|
+
|
|
368
|
+
df = pd.DataFrame(
|
|
369
|
+
{
|
|
370
|
+
"substitution_response": substitution_response,
|
|
371
|
+
"income_response": income_response,
|
|
372
|
+
"total_response": total_response,
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
return df.fillna(0)
|
|
@@ -47,7 +47,6 @@ class Microsimulation(Simulation):
|
|
|
47
47
|
unweighted: bool = False,
|
|
48
48
|
):
|
|
49
49
|
tracer: SimpleTracer = self.tracer
|
|
50
|
-
|
|
51
50
|
result = super().calculate(
|
|
52
51
|
variable_name, period, map_to=map_to, decode_enums=decode_enums
|
|
53
52
|
)
|
|
@@ -81,3 +80,26 @@ class Microsimulation(Simulation):
|
|
|
81
80
|
return values
|
|
82
81
|
weights = self.get_weights(variable_names[0], period, map_to=map_to)
|
|
83
82
|
return MicroDataFrame(values, weights=weights)
|
|
83
|
+
|
|
84
|
+
def compare(
|
|
85
|
+
self,
|
|
86
|
+
other: "Simulation",
|
|
87
|
+
variables: list[str] = None,
|
|
88
|
+
period: str = None,
|
|
89
|
+
change_only: bool = False,
|
|
90
|
+
):
|
|
91
|
+
"""Compare two simulations for a specific variable list.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
other: Another Simulation instance to compare against
|
|
95
|
+
variables: List of variable names to compare. If None, compares all variables.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
DataFrame with comparison results
|
|
99
|
+
"""
|
|
100
|
+
df = super().compare(
|
|
101
|
+
other, variables=variables, period=period, change_only=change_only
|
|
102
|
+
)
|
|
103
|
+
return MicroDataFrame(
|
|
104
|
+
df, weights=self.get_weights(variables[0], period)
|
|
105
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
description: Follow OBR labour supply response assumptions to tax-benefit reforms.
|
|
2
|
+
values:
|
|
3
|
+
0001-01-01: true
|
|
4
|
+
metadata:
|
|
5
|
+
unit: bool
|
|
6
|
+
label: Follow OBR labour supply response assumptions
|
|
7
|
+
reference:
|
|
8
|
+
- title: OBR assumptions
|
|
9
|
+
href: https://obr.uk/docs/dlm_uploads/NICS-Cut-Impact-on-Labour-Supply-Note.pdf
|