Skip to content

Commit 06f0d2c

Browse files
committed
edited the main class accordingly
1 parent 9412b9d commit 06f0d2c

File tree

4 files changed

+289
-23
lines changed

4 files changed

+289
-23
lines changed
Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from policyengine.economic_impact.base_metric_calculator import BaseMetricCalculator
22
from policyengine_uk import Microsimulation
3+
from policyengine_core.reforms import Reform
4+
35

46
class BudgetaryImpact(BaseMetricCalculator):
57
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
@@ -8,64 +10,80 @@ def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default
810
self.reformed = reformed
911

1012
def calculate(self):
11-
1213
baseline_total_tax = self.baseline.calculate("household_tax").sum()
1314
reformed_total_tax = self.reformed.calculate("household_tax").sum()
14-
1515
tax_revenue_impact = reformed_total_tax - baseline_total_tax
1616

1717
baseline_total_benefits = self.baseline.calculate("household_benefits").sum()
1818
reformed_total_benefits = self.reformed.calculate("household_benefits").sum()
19-
20-
2119
benefit_spending_impact = reformed_total_benefits - baseline_total_benefits
2220

2321
budgetary_impact = tax_revenue_impact - benefit_spending_impact
2422

25-
26-
2723
return {
28-
"budgetary_impact" : round(budgetary_impact,2)
24+
"budgetary_impact": round(budgetary_impact, 2)
2925
}
3026

27+
3128
class BenefitSpendingImpact(BaseMetricCalculator):
3229
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
3330
super().__init__(baseline, reformed, default_period)
3431
self.baseline = baseline
3532
self.reformed = reformed
3633

3734
def calculate(self):
38-
3935
baseline_total_benefits = self.baseline.calculate("household_benefits").sum()
4036
reformed_total_benefits = self.reformed.calculate("household_benefits").sum()
41-
42-
4337
benefit_spending_impact = reformed_total_benefits - baseline_total_benefits
4438

45-
46-
4739
return {
48-
"baseline_total_benefits": round(baseline_total_benefits,2),
49-
"reformed_total_benefits": round(reformed_total_benefits,2),
50-
"benefit_spending_impact": round(benefit_spending_impact,2)
40+
"baseline_total_benefits": round(baseline_total_benefits, 2),
41+
"reformed_total_benefits": round(reformed_total_benefits, 2),
42+
"benefit_spending_impact": round(benefit_spending_impact, 2)
5143
}
5244

45+
5346
class TaxRevenueImpact(BaseMetricCalculator):
5447
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
5548
super().__init__(baseline, reformed, default_period)
5649
self.baseline = baseline
5750
self.reformed = reformed
5851

5952
def calculate(self):
60-
6153
baseline_total_tax = self.baseline.calculate("household_tax").sum()
6254
reformed_total_tax = self.reformed.calculate("household_tax").sum()
63-
6455
tax_revenue_impact = reformed_total_tax - baseline_total_tax
65-
6656

6757
return {
68-
"baseline_total_tax": round(baseline_total_tax,2),
69-
"reformed_total_tax": round(reformed_total_tax,2),
70-
"tax_revenue_impact": round(tax_revenue_impact,2)
71-
}
58+
"baseline_total_tax": round(baseline_total_tax, 2),
59+
"reformed_total_tax": round(reformed_total_tax, 2),
60+
"tax_revenue_impact": round(tax_revenue_impact, 2)
61+
}
62+
63+
64+
65+
# from policyengine_uk import Microsimulation
66+
# # Define your reform
67+
# reformm = Reform.from_dict({
68+
# "gov.hmrc.income_tax.rates.uk[0].rate": {
69+
# "2024-01-01.2100-12-31": 0.55
70+
# }
71+
# }, country_id="uk")
72+
73+
# # Create baseline and reformed simulations
74+
# baseline = Microsimulation() # Ensure this initializes correctly
75+
# reformed = Microsimulation(reform=reformm) # Ensure this applies the reform correctly
76+
77+
# # Set default calculation period
78+
# baseline.default_calculation_period = 2024
79+
# reformed.default_calculation_period = 2024
80+
81+
# # Create metric calculators
82+
# b1 = BenefitSpendingImpact(reformed=reformed, baseline=baseline)
83+
# a1 = BudgetaryImpact(reformed=reformed, baseline=baseline)
84+
# c1 = TaxRevenueImpact(reformed=reformed, baseline=baseline)
85+
86+
# # Print results
87+
# print(b1.calculate())
88+
# print(a1.calculate())
89+
# print(c1.calculate())

policyengine/economic_impact/economic_impact.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,23 @@
4242
TaxRevenueImpact
4343
)
4444

45+
from .labour_supply_impact.earnings.overall.relative.relative import IncomeLSR , SubstitutionLSR , NetLSRChange
46+
47+
from .labour_supply_impact.earnings.overall.absolute.absolute import (
48+
IncomeLSR as AbsoluteIncomeLSR,
49+
SubstitutionLSR as AbsoluteSubstitutionLSR,
50+
NetLSRChange as AbsoluteNetLSRChange
51+
)
52+
53+
from .labour_supply_impact.earnings.by_decile.relative.substitution_effect.substitutional_effect import SubstitutionEffect
54+
from .labour_supply_impact.earnings.by_decile.relative.income_effect.income_effect import IncomeEffect
55+
from .labour_supply_impact.earnings.by_decile.relative.total.total import Total
56+
57+
from .labour_supply_impact.earnings.by_decile.absolute.substitution_effect.substitution_effect import SubstitutionEffect as AbsoluteSubstutionEffect
58+
from .labour_supply_impact.earnings.by_decile.absolute.income_effect.income_effect import IncomeEffect as AbsoluteIncomeEffect
59+
from .labour_supply_impact.earnings.by_decile.absolute.total.total import Total as AbsoluteTotal
60+
61+
4562
from typing import Dict
4663

4764
class EconomicImpact:
@@ -105,7 +122,18 @@ def __init__(self, reform: dict, country: str) -> None:
105122
"poverty/deep/male": DeepMalePoverty(self.baseline, self.reformed),
106123
"poverty/deep/female": DeepFemalePoverty(self.baseline, self.reformed),
107124
"poverty/deep/gender/all": DeepGenderAllPoverty(self.baseline, self.reformed),
108-
125+
"labour_supply_impact/earnings/overall/relative/IncomeLSR" : IncomeLSR(self.baseline,self.reformed),
126+
"labour_supply_impact/earnings/overall/relative/SubstitutionLSR" : SubstitutionLSR(self.baseline,self.reformed),
127+
"labour_supply_impact/earnings/overall/relative/NetLSRChange" : NetLSRChange(self.baseline,self.reformed),
128+
"labour_supply_impact/earnings/overall/absolute/IncomeLSR" : AbsoluteIncomeLSR(self.baseline,self.reformed),
129+
"labour_supply_impact/earnings/overall/absolute/SubstitutionLSR" : AbsoluteSubstitutionLSR(self.baseline,self.reformed),
130+
"labour_supply_impact/earnings/overall/absolute/NetLSRChange" : AbsoluteNetLSRChange(self.baseline,self.reformed),
131+
"labour_supply_impact/earnings/by_decile/relative/IncomeEffect" : IncomeEffect(self.baseline,self.reformed),
132+
"labour_supply_impact/earnings/by_decile/relative/SubstitutionEffect" : SubstitutionEffect(self.baseline,self.reformed),
133+
"labour_supply_impact/earnings/by_decile/relative/Total" : Total(self.baseline,self.reformed),
134+
"labour_supply_impact/earnings/by_decile/absolute/income_effect" : AbsoluteIncomeEffect(self.baseline,self.reformed),
135+
"labour_supply_impact/earnings/by_decile/absolute/substitution_effect" : AbsoluteSubstutionEffect(self.baseline,self.reformed),
136+
"labour_supply_impact/earnings/by_decile/absolute/total" : AbsoluteTotal(self.baseline,self.reformed),
109137
}
110138

111139
def _get_simulation_class(self) -> type:
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from policyengine.economic_impact.base_metric_calculator import BaseMetricCalculator
2+
from policyengine_uk import Microsimulation
3+
from policyengine_core.reforms import Reform
4+
from microdf import MicroSeries
5+
import numpy as np
6+
7+
8+
class IncomeLSR(BaseMetricCalculator):
9+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
10+
super().__init__(baseline, reformed, default_period)
11+
self.baseline = baseline
12+
self.reformed = reformed
13+
14+
def calculate(self):
15+
income_lsr_baseline = 0
16+
income_lsr_reformed = 0
17+
18+
if "employment_income_behavioral_response" in self.baseline.tax_benefit_system.variables:
19+
if any(self.baseline.calculate("employment_income_behavioral_response") != 0):
20+
income_lsr_baseline = self.baseline.calculate("income_elasticity_lsr").sum()
21+
22+
if "employment_income_behavioral_response" in self.reformed.tax_benefit_system.variables:
23+
if any(self.reformed.calculate("employment_income_behavioral_response") != 0):
24+
income_lsr_reformed = self.reformed.calculate("income_elasticity_lsr").sum()
25+
26+
income_lsr = income_lsr_reformed - income_lsr_baseline
27+
# Convert to billions and round to 2 decimal places
28+
income_lsr_billion = round(income_lsr / 1e9, 2)
29+
30+
return {
31+
"income_lsr": income_lsr_billion
32+
}
33+
34+
class SubstitutionLSR(BaseMetricCalculator):
35+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
36+
super().__init__(baseline, reformed, default_period)
37+
self.baseline = baseline
38+
self.reformed = reformed
39+
40+
def calculate(self):
41+
substitution_lsr_baseline = 0
42+
substitution_lsr_reformed = 0
43+
44+
if "employment_income_behavioral_response" in self.baseline.tax_benefit_system.variables:
45+
if any(self.baseline.calculate("employment_income_behavioral_response") != 0):
46+
substitution_lsr_baseline = self.baseline.calculate("substitution_elasticity_lsr").sum()
47+
48+
if "employment_income_behavioral_response" in self.reformed.tax_benefit_system.variables:
49+
if any(self.reformed.calculate("employment_income_behavioral_response") != 0):
50+
substitution_lsr_reformed = self.reformed.calculate("substitution_elasticity_lsr").sum()
51+
52+
substitution_lsr = substitution_lsr_reformed - substitution_lsr_baseline
53+
# Convert to billions and round to 2 decimal places
54+
substitution_lsr_billion = round(substitution_lsr / 1e9, 2)
55+
56+
return {
57+
"substitution_lsr": substitution_lsr_billion
58+
}
59+
60+
class NetLSRChange(BaseMetricCalculator):
61+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
62+
super().__init__(baseline, reformed, default_period)
63+
self.baseline = baseline
64+
self.reformed = reformed
65+
66+
def calculate(self):
67+
income_result = IncomeLSR(baseline=self.baseline, reformed=self.reformed).calculate()
68+
substitution_result = SubstitutionLSR(baseline=self.baseline, reformed=self.reformed).calculate()
69+
70+
income_value = income_result["income_lsr"]
71+
substitution_value = substitution_result["substitution_lsr"]
72+
73+
net_change = (income_value + substitution_value)
74+
# Round to 2 decimal places
75+
net_change_billion = round(net_change, 2)
76+
77+
return {"net_change": net_change_billion}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
from policyengine.economic_impact.base_metric_calculator import BaseMetricCalculator
2+
from policyengine_uk import Microsimulation
3+
from policyengine_core.reforms import Reform
4+
from microdf import MicroSeries
5+
import numpy as np
6+
7+
class IncomeLSR(BaseMetricCalculator):
8+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
9+
super().__init__(baseline, reformed, default_period)
10+
self.baseline = baseline
11+
self.reformed = reformed
12+
13+
def calculate(self):
14+
# Calculate household counts
15+
# household_count_people_baseline = self.baseline.calculate("household_count_people")
16+
# household_count_people_reformed = self.reformed.calculate("household_count_people")
17+
18+
# Calculate baseline and reformed substitution LSR
19+
substitution_lsr_hh_baseline = self._calculate_substitution_lsr(self.baseline)
20+
substitution_lsr_hh_reformed = self._calculate_substitution_lsr(self.reformed)
21+
22+
# Compute the change in substitution LSR
23+
substitution_lsr_hh = np.array(substitution_lsr_hh_reformed) - np.array(substitution_lsr_hh_baseline)
24+
25+
# Calculate baseline and reformed income LSR
26+
income_lsr_hh_baseline = self._calculate_income_lsr(self.baseline)
27+
income_lsr_hh_reformed = self._calculate_income_lsr(self.reformed)
28+
29+
# Compute the change in income LSR
30+
income_lsr_hh = np.array(income_lsr_hh_reformed) - np.array(income_lsr_hh_baseline)
31+
32+
# Calculate weights and earnings
33+
household_weight = self.baseline.calculate("household_weight")
34+
emp_income = MicroSeries(
35+
self.baseline.calculate("employment_income", map_to="household").astype(float).tolist(),
36+
weights=household_weight
37+
)
38+
self_emp_income = MicroSeries(
39+
self.baseline.calculate("self_employment_income", map_to="household").astype(float).tolist(),
40+
weights=household_weight
41+
)
42+
total_lsr_hh = substitution_lsr_hh + income_lsr_hh
43+
earnings = emp_income + self_emp_income
44+
original_earnings = earnings - total_lsr_hh
45+
46+
# Calculate income LSR ratio
47+
income_lsr_hh = MicroSeries(income_lsr_hh, weights=household_weight)
48+
income = income_lsr_hh.sum() / original_earnings.sum() * 100
49+
50+
return {"income": round(income,2)}
51+
52+
def _calculate_substitution_lsr(self, simulation: Microsimulation):
53+
"""Calculate substitution LSR for a given simulation."""
54+
if "employment_income_behavioral_response" in simulation.tax_benefit_system.variables:
55+
if any(simulation.calculate("employment_income_behavioral_response") != 0):
56+
return simulation.calculate("substitution_elasticity_lsr", map_to="household").astype(float).tolist()
57+
return (self.baseline.calculate("household_count_people") * 0).astype(float).tolist()
58+
59+
def _calculate_income_lsr(self, simulation: Microsimulation):
60+
"""Calculate income LSR for a given simulation."""
61+
if "employment_income_behavioral_response" in simulation.tax_benefit_system.variables:
62+
if any(simulation.calculate("employment_income_behavioral_response") != 0):
63+
return simulation.calculate("income_elasticity_lsr", map_to="household").astype(float).tolist()
64+
return (self.baseline.calculate("household_count_people") * 0).astype(float).tolist()
65+
66+
67+
class SubstitutionLSR(BaseMetricCalculator):
68+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
69+
super().__init__(baseline, reformed, default_period)
70+
self.baseline = baseline
71+
self.reformed = reformed
72+
73+
def calculate(self):
74+
# Calculate household counts
75+
# household_count_people_baseline = self.baseline.calculate("household_count_people")
76+
# household_count_people_reformed = self.reformed.calculate("household_count_people")
77+
78+
# Calculate baseline and reformed income LSR
79+
income_lsr_hh_baseline = self._calculate_income_lsr(self.baseline)
80+
income_lsr_hh_reformed = self._calculate_income_lsr(self.reformed)
81+
82+
# Calculate baseline and reformed substitution LSR
83+
substitution_lsr_hh_baseline = self._calculate_substitution_lsr(self.baseline)
84+
substitution_lsr_hh_reformed = self._calculate_substitution_lsr(self.reformed)
85+
86+
# Compute the change in substitution LSR
87+
substitution_lsr_hh = np.array(substitution_lsr_hh_reformed) - np.array(substitution_lsr_hh_baseline)
88+
household_weight = self.baseline.calculate("household_weight")
89+
90+
# Convert to MicroSeries and compute total LSR
91+
substitution_lsr_hh = MicroSeries(substitution_lsr_hh, weights=household_weight)
92+
income_lsr_hh = np.array(income_lsr_hh_reformed) - np.array(income_lsr_hh_baseline)
93+
total_lsr_hh = substitution_lsr_hh + income_lsr_hh
94+
95+
# Calculate earnings
96+
emp_income = MicroSeries(
97+
self.baseline.calculate("employment_income", map_to="household").astype(float).tolist(),
98+
weights=household_weight
99+
)
100+
self_emp_income = MicroSeries(
101+
self.baseline.calculate("self_employment_income", map_to="household").astype(float).tolist(),
102+
weights=household_weight
103+
)
104+
earnings = emp_income + self_emp_income
105+
original_earnings = earnings - total_lsr_hh
106+
107+
# Calculate substitution ratio
108+
substitution = substitution_lsr_hh.sum() / original_earnings.sum() * 100
109+
110+
return {"substitution": round(substitution,2)}
111+
112+
def _calculate_substitution_lsr(self, simulation: Microsimulation):
113+
"""Calculate substitution LSR for a given simulation."""
114+
if "employment_income_behavioral_response" in simulation.tax_benefit_system.variables:
115+
if any(simulation.calculate("employment_income_behavioral_response") != 0):
116+
return simulation.calculate("substitution_elasticity_lsr", map_to="household").astype(float).tolist()
117+
return (self.baseline.calculate("household_count_people") * 0).astype(float).tolist()
118+
119+
def _calculate_income_lsr(self, simulation: Microsimulation):
120+
"""Calculate income LSR for a given simulation."""
121+
if "employment_income_behavioral_response" in simulation.tax_benefit_system.variables:
122+
if any(simulation.calculate("employment_income_behavioral_response") != 0):
123+
return simulation.calculate("income_elasticity_lsr", map_to="household").astype(float).tolist()
124+
return (self.baseline.calculate("household_count_people") * 0).astype(float).tolist()
125+
126+
127+
128+
class NetLSRChange(BaseMetricCalculator):
129+
def __init__(self, baseline: Microsimulation, reformed: Microsimulation, default_period: int = 2024) -> None:
130+
super().__init__(baseline, reformed, default_period)
131+
self.baseline = baseline
132+
self.reformed = reformed
133+
134+
def calculate(self):
135+
income_result = IncomeLSR(baseline=self.baseline, reformed=self.reformed).calculate()
136+
substitution_result = SubstitutionLSR(baseline=self.baseline, reformed=self.reformed).calculate()
137+
138+
income_value = income_result["income"]
139+
substitution_value = substitution_result["substitution"]
140+
141+
net_change = (income_value + substitution_value)
142+
143+
return {"net_change": round(net_change,2)}

0 commit comments

Comments
 (0)