From d3adcb492cb168640249bef218a62682e90af587 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 14:23:37 +0100 Subject: [PATCH 1/6] Refactor AMT code to use descriptive variable names rather than those tied to form lines Fixes #3280 --- changelog_entry.yaml | 4 + .../calibration/gov/cbo/income_tax.yaml | 2 +- .../calibration/gov/cbo/payroll_taxes.yaml | 2 +- .../high_income_area_threshold_increase.yaml | 2 +- .../income/amt/capital_gains/brackets.yaml | 174 ------------- .../deductions/standard/aged/amount/head.yaml | 2 +- .../standard/aged/amount/spouse.yaml | 2 +- .../deductions/standard/blind/head.yaml | 2 +- .../alternative_minimum_tax.yaml | 47 ++++ .../alternative_minimum_tax/amt_base_tax.yaml | 23 ++ .../amt_part_iii_required.yaml | 21 ++ .../amt_tax_including_cg.yaml | 59 +++++ .../income/amt_income_less_exemptions.yaml | 43 ++++ .../kiddie_tax/amt_kiddie_tax_applies.yaml | 30 +++ .../ga_additional_standard_deduction.yaml | 2 +- .../alternative_minimum_tax.py | 136 ++-------- .../alternative_minimum_tax/amt_base_tax.py | 37 +++ .../amt_part_iii_required.py | 24 ++ .../amt_tax_including_cg.py | 107 ++++++++ .../income/amt_income_less_exemptions.py | 44 ++++ .../kiddie_tax/amt_kiddie_tax_applies.py | 16 ++ ...end_income_reduced_by_investment_income.py | 19 ++ .../federal_income/capital_gains/dwks06.py | 16 -- .../federal_income/capital_gains/dwks09.py | 4 +- .../federal_income/capital_gains/dwks10.py | 6 +- test.ipynb | 239 ++++++++++++++++++ 26 files changed, 752 insertions(+), 311 deletions(-) delete mode 100644 policyengine_us/parameters/gov/irs/income/amt/capital_gains/brackets.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.yaml create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.py create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.py create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.py create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dividend_income_reduced_by_investment_income.py delete mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks06.py create mode 100644 test.ipynb diff --git a/changelog_entry.yaml b/changelog_entry.yaml index e69de29bb2d..822eb2d31db 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -0,0 +1,4 @@ +- bump: minor + changes: + added: + - Reafctor the Alternative Minimum Tax (AMT) logic. diff --git a/policyengine_us/parameters/calibration/gov/cbo/income_tax.yaml b/policyengine_us/parameters/calibration/gov/cbo/income_tax.yaml index 45ce8db7b75..c3499003626 100644 --- a/policyengine_us/parameters/calibration/gov/cbo/income_tax.yaml +++ b/policyengine_us/parameters/calibration/gov/cbo/income_tax.yaml @@ -28,4 +28,4 @@ metadata: # Source: https://www.cbo.gov/data/budget-economic-data # Sheet 3.Individual Income Tax Details # Row 72: Individual income yax receipts ($B, FY)m - href: https://www.cbo.gov/system/files/2025-01/51138-2025-01-Revenue-Projections.xlsx \ No newline at end of file + href: https://www.cbo.gov/system/files/2025-01/51138-2025-01-Revenue-Projections.xlsx diff --git a/policyengine_us/parameters/calibration/gov/cbo/payroll_taxes.yaml b/policyengine_us/parameters/calibration/gov/cbo/payroll_taxes.yaml index adff7a8db3c..bb4eccfb55f 100644 --- a/policyengine_us/parameters/calibration/gov/cbo/payroll_taxes.yaml +++ b/policyengine_us/parameters/calibration/gov/cbo/payroll_taxes.yaml @@ -33,4 +33,4 @@ values: 2032-01-01: 2_329_390_000_000 2033-01-01: 2_418_530_000_000 2034-01-01: 2_510_311_000_000 - 2035-01-01: 2_605_182_000_000 \ No newline at end of file + 2035-01-01: 2_605_182_000_000 diff --git a/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml b/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml index 9f0997527f0..54b6ae6ce24 100644 --- a/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml +++ b/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml @@ -8,4 +8,4 @@ metadata: href: https://www.congress.gov/bill/116th-congress/senate-bill/1106/text values: - 2019-01-01: 25_000 + 2019-01-01: 2 diff --git a/policyengine_us/parameters/gov/irs/income/amt/capital_gains/brackets.yaml b/policyengine_us/parameters/gov/irs/income/amt/capital_gains/brackets.yaml deleted file mode 100644 index 990b5cb23ec..00000000000 --- a/policyengine_us/parameters/gov/irs/income/amt/capital_gains/brackets.yaml +++ /dev/null @@ -1,174 +0,0 @@ -rates: - description: Long term capital gain and qualified dividends (AMT) rates - metadata: - unit: /1 - 1: - 2013-01-01: 0 - 2: - 2013-01-01: 0.15 - 3: - 2013-01-01: 0.2 -thresholds: - description: Tops of long-term capital gains and qualified dividends (AMT) tax brackets - metadata: - unit: currency-USD - reference: - - title: 2024 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-23-34.pdf#page=8 - - title: 2023 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-22-38.pdf#page=8 - - title: 2022 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-21-45.pdf#page=8 - - title: 2021 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-20-45.pdf#page=8 - - title: 2020 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-19-44.pdf#page=8 - - title: 2019 IRS data release - href: https://www.irs.gov/pub/irs-drop/rp-18-57.pdf#page=8 - - title: Internal Revenue Code §1(j)(5)(B) - # IRC defines amounts as of 2018. - # Defines COLA with rounded up to the nearest multiple of $50. - href: https://www.law.cornell.edu/uscode/text/26/1#j_5_B - uprating: gov.irs.uprating - 1: - HEAD_OF_HOUSEHOLD: - values: - 2013-01-01: 48_600 - 2014-01-01: 49_400 - 2015-01-01: 50_200 - 2016-01-01: 50_400 - 2017-01-01: 50_800 - 2018-01-01: 51_700 - 2019-01-01: 52_750 - 2020-01-01: 53_600 - 2021-01-01: 54_100 - 2022-01-01: 55_800 - 2023-01-01: 59_750 - 2024-01-01: 63_000 - JOINT: - values: - 2013-01-01: 72_500 - 2014-01-01: 73_800 - 2015-01-01: 74_900 - 2016-01-01: 75_300 - 2017-01-01: 75_900 - 2018-01-01: 77_200 - 2019-01-01: 78_750 - 2020-01-01: 80_000 - 2021-01-01: 80_800 - 2022-01-01: 83_350 - 2023-01-01: 89_250 - 2024-01-01: 94_050 - SEPARATE: - values: - 2013-01-01: 36_250 - 2014-01-01: 36_900 - 2015-01-01: 37_450 - 2016-01-01: 37_650 - 2017-01-01: 37_950 - 2018-01-01: 38_600 - 2019-01-01: 39_375 - 2020-01-01: 40_000 - 2021-01-01: 40_400 - 2022-01-01: 41_675 - 2023-01-01: 44_625 - 2024-01-01: 47_025 - SINGLE: - values: - 2013-01-01: 36_250 - 2014-01-01: 36_900 - 2015-01-01: 37_450 - 2016-01-01: 37_650 - 2017-01-01: 37_950 - 2018-01-01: 38_600 - 2019-01-01: 39_375 - 2020-01-01: 40_000 - 2021-01-01: 40_400 - 2022-01-01: 41_675 - 2023-01-01: 44_625 - 2024-01-01: 47_025 - SURVIVING_SPOUSE: - values: - 2013-01-01: 72_500 - 2014-01-01: 73_800 - 2015-01-01: 74_900 - 2016-01-01: 75_300 - 2017-01-01: 75_900 - 2018-01-01: 77_200 - 2019-01-01: 78_750 - 2020-01-01: 80_000 - 2021-01-01: 80_800 - 2022-01-01: 83_350 - 2023-01-01: 89_250 - 2024-01-01: 94_050 - 2: - HEAD_OF_HOUSEHOLD: - values: - 2013-01-01: 425_000 - 2014-01-01: 432_200 - 2015-01-01: 439_000 - 2016-01-01: 441_000 - 2017-01-01: 444_550 - 2018-01-01: 452_400 - 2019-01-01: 461_700 - 2020-01-01: 469_050 - 2021-01-01: 473_750 - 2022-01-01: 488_500 - 2023-01-01: 523_050 - 2024-01-01: 551_350 - JOINT: - values: - 2013-01-01: 450_000 - 2014-01-01: 457_600 - 2015-01-01: 464_850 - 2016-01-01: 466_950 - 2017-01-01: 470_700 - 2018-01-01: 479_000 - 2019-01-01: 488_850 - 2020-01-01: 496_600 - 2021-01-01: 501_600 - 2022-01-01: 517_200 - 2023-01-01: 553_850 - 2024-01-01: 583_750 - SEPARATE: - values: - 2013-01-01: 225_000 - 2014-01-01: 228_800 - 2015-01-01: 232_425 - 2016-01-01: 233_475 - 2017-01-01: 235_350 - 2018-01-01: 239_500 - 2019-01-01: 244_425 - 2020-01-01: 248_300 - 2021-01-01: 250_800 - 2022-01-01: 258_600 - 2023-01-01: 276_900 - 2024-01-01: 291_850 - SINGLE: - values: - 2013-01-01: 400_000 - 2014-01-01: 406_750 - 2015-01-01: 413_200 - 2016-01-01: 415_050 - 2017-01-01: 418_400 - 2018-01-01: 425_800 - 2019-01-01: 434_550 - 2020-01-01: 441_450 - 2021-01-01: 445_850 - 2022-01-01: 459_750 - 2023-01-01: 492_300 - 2024-01-01: 518_900 - SURVIVING_SPOUSE: - values: - 2013-01-01: 450_000 - 2014-01-01: 457_600 - 2015-01-01: 464_850 - 2016-01-01: 466_950 - 2017-01-01: 470_700 - 2018-01-01: 479_000 - 2019-01-01: 488_850 - 2020-01-01: 496_600 - 2021-01-01: 501_600 - 2022-01-01: 517_200 - 2023-01-01: 553_850 - 2024-01-01: 583_750 diff --git a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/head.yaml b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/head.yaml index 4a725f89697..f35c03b79a9 100644 --- a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/head.yaml +++ b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/head.yaml @@ -16,4 +16,4 @@ metadata: href: https://dor.georgia.gov/document/document/2024-it-511-individual-income-tax-booklet/download values: 2021-01-01: 1_300 - \ No newline at end of file + diff --git a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/spouse.yaml b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/spouse.yaml index 2ccf3d3dc04..ec65a3aff65 100644 --- a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/spouse.yaml +++ b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/aged/amount/spouse.yaml @@ -16,4 +16,4 @@ metadata: href: https://dor.georgia.gov/document/document/2024-it-511-individual-income-tax-booklet/download values: 2021-01-01: 1_300 - \ No newline at end of file + diff --git a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/blind/head.yaml b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/blind/head.yaml index d4dfef529b7..15092add6d6 100644 --- a/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/blind/head.yaml +++ b/policyengine_us/parameters/gov/states/ga/tax/income/deductions/standard/blind/head.yaml @@ -16,4 +16,4 @@ metadata: href: https://dor.georgia.gov/document/document/2024-it-511-individual-income-tax-booklet/download values: 2021-01-01: 1_300 - \ No newline at end of file + diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.yaml index 0411edc1565..08a71dc319d 100644 --- a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.yaml +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.yaml @@ -68,3 +68,50 @@ state_code: CA output: alternative_minimum_tax: 0 + +- name: Integration test - single filer with 5k of income + absolute_error_margin: 0.01 + period: 2024 + input: + people: + person1: + age: 40 + employment_income: 2_000_000 + spm_units: + spm_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + alternative_minimum_tax: 0 + +- name: AMT does not apply if regular tax is higher than AMT + period: 2022 + input: + amt_base_tax: 10_000 + amt_part_iii_required: false + amt_tax_including_cg: 2_000 + foreign_tax_credit: 0 + regular_tax_before_credits: 11_000 + form_4972_lumpsum_distributions: 0 + capital_gains_tax: 0 + output: + alternative_minimum_tax: 0 + +- name: Part iii required, AMT higher than regular tax + period: 2022 + input: + amt_base_tax: 15_000 + amt_part_iii_required: true + amt_tax_including_cg: 12_000 + foreign_tax_credit: 0 + regular_tax_before_credits: 11_000 + form_4972_lumpsum_distributions: 0 + capital_gains_tax: 0 + output: + alternative_minimum_tax: 1_000 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml new file mode 100644 index 00000000000..80951a6307b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml @@ -0,0 +1,23 @@ +- name: Single person, low income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 10_000 + output: + amt_base_tax: 2_600 + +- name: Single person, no income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 0 + output: + amt_base_tax: 0 + +- name: Joint, high income + period: 2022 + input: + filing_status: JOINT + amt_income_less_exemptions: 200_000 + output: + amt_base_tax: 52_000 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.yaml new file mode 100644 index 00000000000..b91deb495ee --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.yaml @@ -0,0 +1,21 @@ +- name: Not required + period: 2022 + input: + dwks10: 0 + dwks13: 0 + dwks14: 0 + dwks19: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_part_iii_required: false + +- name: Required + period: 2022 + input: + dwks10: 0 + dwks13: 0 + dwks14: 1 + dwks19: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_part_iii_required: true diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.yaml new file mode 100644 index 00000000000..3a0c72d8f3e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.yaml @@ -0,0 +1,59 @@ +- name: First bracket, no capital gains + period: 2023 + input: + filing_status: SINGLE + amt_income_less_exemptions: 50_000 + dwks10: 0 + dwks13: 0 + dwks14: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_tax_including_cg: 13_000 + +- name: First bracket, no capital gains, higher income + period: 2023 + input: + filing_status: SINGLE + amt_income_less_exemptions: 100_000 + dwks10: 0 + dwks13: 0 + dwks14: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_tax_including_cg: 26_000 + +- name: Income with capital gains in first bracket + period: 2023 + input: + filing_status: SINGLE + amt_income_less_exemptions: 100_000 + dwks10: 50_000 + dwks13: 30_000 + dwks14: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_tax_including_cg: 22_700 + +- name: AMT with capital gains in second bracket + period: 2023 + input: + filing_status: SINGLE + amt_income_less_exemptions: 600_000 + dwks10: 200_000 + dwks13: 150_000 + dwks14: 0 + unrecaptured_section_1250_gain: 0 + output: + amt_tax_including_cg: 144_086 + +- name: AMT with unrecaptured section 1250 gains + period: 2023 + input: + filing_status: SINGLE + amt_income_less_exemptions: 1_000_000 + dwks10: 500_000 + dwks13: 300_000 + dwks14: 0 + unrecaptured_section_1250_gain: 200_000 + output: + amt_tax_including_cg: 230_586 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.yaml new file mode 100644 index 00000000000..391d04015c4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.yaml @@ -0,0 +1,43 @@ +- name: Kiddie tax does not apply, high income + period: 2022 + input: + amt_income: 200_000 + taxable_income: 1_000_000 + amt_kiddie_tax_applies: false + filer_adjusted_earnings: 400_000 + filing_status: SINGLE + output: + amt_income_less_exemptions: 124_100 + +- name: Kiddie tax applies, low income + period: 2022 + input: + amt_income: 200_000 + taxable_income: 200_000 + amt_kiddie_tax_applies: true + filer_adjusted_earnings: 10_000 + filing_status: SINGLE + output: + amt_income_less_exemptions: 181_800 + +- name: Kiddie tax does not apply, income below exemption amount + period: 2022 + input: + amt_income: 10_000 + taxable_income: 1_000_000 + amt_kiddie_tax_applies: false + filer_adjusted_earnings: 400_000 + filing_status: SINGLE + output: + amt_income_less_exemptions: 0 + +- name: Kiddie tax does not apply, exemptions are phased out + period: 2022 + input: + amt_income: 1_000_000 + taxable_income: 1_000_000 + amt_kiddie_tax_applies: false + filer_adjusted_earnings: 400_000 + filing_status: SINGLE + output: + amt_income_less_exemptions: 1_000_000 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.yaml new file mode 100644 index 00000000000..24df9a9e893 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.yaml @@ -0,0 +1,30 @@ +- name: Kiddie tax does applies to single head + period: 2022 + input: + age_head: 18 + output: + amt_kiddie_tax_applies: true + +- name: Older spouse + period: 2022 + input: + age_head: 18 + age_spouse: 19 + output: + amt_kiddie_tax_applies: false + +- name: Younger spouse + period: 2022 + input: + age_head: 18 + age_spouse: 18 + output: + amt_kiddie_tax_applies: true + +- name: Older head + period: 2022 + input: + age_head: 19 + age_spouse: 18 + output: + amt_kiddie_tax_applies: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/deductions/standard/ga_additional_standard_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/deductions/standard/ga_additional_standard_deduction.yaml index 8d5b0c5b996..0b79321c7f0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/deductions/standard/ga_additional_standard_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ga/tax/income/deductions/standard/ga_additional_standard_deduction.yaml @@ -18,4 +18,4 @@ blind_head: true state_code: GA output: - ga_additional_standard_deduction: 2_600 \ No newline at end of file + ga_additional_standard_deduction: 2_600 diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.py index e0f4a269474..04f5c1fb35b 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/alternative_minimum_tax.py @@ -10,126 +10,40 @@ class alternative_minimum_tax(Variable): documentation = "Alternative Minimum Tax (AMT) liability" def formula(tax_unit, period, parameters): - amt_income = tax_unit("amt_income", period) - # Form 6251, Part II top - p = parameters(period).gov.irs.income.amt - phase_out = p.exemption.phase_out - filing_status = tax_unit("filing_status", period) - base_exemption_amount = p.exemption.amount[filing_status] - income_excess = max_(0, amt_income - phase_out.start[filing_status]) - uncapped_exemption_amount = max_( - 0, - (base_exemption_amount - phase_out.rate * income_excess), - ) - age_head = tax_unit("age_head", period) - child = parameters(period).gov.irs.dependent.ineligible_age - young_head = (age_head != 0) & (age_head < child.non_student) - no_or_young_spouse = tax_unit("age_spouse", period) < child.non_student - adj_earnings = tax_unit("filer_adjusted_earnings", period) - child_amount = p.exemption.child.amount - - kiddie_tax_exemption_cap_applies = young_head & no_or_young_spouse - exemption_cap = where( - kiddie_tax_exemption_cap_applies, - adj_earnings + child_amount, - np.inf, - ) - capped_exemption_amount = min_( - uncapped_exemption_amount, exemption_cap - ) - # Line 6 - taxable_income = tax_unit("taxable_income", period) - # Do not add back deduction for filers subject to the kiddie tax - applied_income = where( - kiddie_tax_exemption_cap_applies, taxable_income, amt_income - ) - reduced_income = max_(0, applied_income - capped_exemption_amount) - bracket_fraction = where( - filing_status == filing_status.possible_values.SEPARATE, - 0.5, - 1.0, - ) - tax_rate_threshold = p.brackets.thresholds[-1] * bracket_fraction - lower_rate = p.brackets.rates[0] - higher_rate = p.brackets.rates[1] - lower_tax = min_(reduced_income, tax_rate_threshold) * lower_rate - higher_tax = max_(0, reduced_income - tax_rate_threshold) * higher_rate - - # Line 7 - reduced_income_tax = lower_tax + higher_tax - dwks10, dwks13, dwks14, dwks19, e24515 = [ - add(tax_unit, period, [variable]) - for variable in [ - "dwks10", - "dwks13", - "dwks14", - "dwks19", - "unrecaptured_section_1250_gain", - ] - ] - form_6251_part_iii_required = np.any( - [ - variable > 0 - for variable in [ - dwks10, - dwks13, - dwks14, - dwks19, - e24515, - ] - ] - ) + # Line 7 consists of 3 parts: + # 1. Tax on Foreign income (not modelled) + # 2. Tax on capital gains (Part III) + # 3. Regular AMT tax + # If Form 6251, Part III is required, the regular AMT tax is calculated + # by using the smaller of the regular AMT tax calculated on the + # reduced income or the tax on capital gains (Part III) + # Regular AMT tax: + amt_base_tax = tax_unit("amt_base_tax", period) - # Complete Form 6251, Part III + # Tax on capital gains (Part III) + form_6251_part_iii_required = tax_unit("amt_part_iii_required", period) - line37 = dwks13 - line38 = e24515 - line39 = min_(line37 + line38, dwks10) - line40 = min_(reduced_income, line39) - line41 = max_(0, reduced_income - line40) - line42 = p.brackets.calc(line41) - line44 = dwks14 - cg = p.capital_gains.brackets - line45 = max_(0, cg.thresholds["1"][filing_status] - line44) - line46 = min_(reduced_income, line37) - line47 = min_(line45, line46) - cgtax1 = line47 * cg.rates["1"] - line48 = line46 - line47 - line51 = dwks19 - line52 = line45 + line51 - line53 = max_(0, cg.thresholds["2"][filing_status] - line52) - line54 = min_(line48, line53) - cgtax2 = line54 * cg.rates["2"] - line56 = line47 + line54 - line57 = where(line41 == line56, 0, line46 - line56) - linex2 = where(line41 == line56, 0, max_(0, line54 - line48)) - cgtax3 = line57 * cg.rates["3"] - line61 = where( - line38 == 0, - 0, - p.capital_gains.capital_gain_excess_tax_rate - * max_(0, (reduced_income - line41 - line56 - line57 - linex2)), + amt_tax_including_cg = tax_unit("amt_tax_including_cg", period) + smaller_tax = min_(amt_base_tax, amt_tax_including_cg) + total_amt_tax = where( + form_6251_part_iii_required, smaller_tax, amt_base_tax ) - line62 = line42 + cgtax1 + cgtax2 + cgtax3 + line61 - line64 = min_(reduced_income_tax, line62) - line31 = where(form_6251_part_iii_required, line64, reduced_income_tax) # Form 6251, Part II bottom - line32 = tax_unit("foreign_tax_credit", period) - line33 = line31 - line32 + # Line 8 + foreign_tax_credit = tax_unit("foreign_tax_credit", period) + # Line 9 + reduced_tax = total_amt_tax - foreign_tax_credit + # Line 10 contains regular tax before credits, lump sum distributions, and capital gains tax regular_tax_before_credits = tax_unit( "regular_tax_before_credits", period ) lump_sum_distributions = tax_unit( "form_4972_lumpsum_distributions", period ) - capital_gains = tax_unit("capital_gains_tax", period) - tax_before_credits = regular_tax_before_credits + capital_gains - return max_( - 0, - line33 - - max_( - 0, - (tax_before_credits - line32 - lump_sum_distributions), - ), + capital_gains_tax = tax_unit("capital_gains_tax", period) + tax_before_credits = regular_tax_before_credits + capital_gains_tax + reduced_tax_before_credits = max_( + 0, tax_before_credits - foreign_tax_credit - lump_sum_distributions ) + return max_(0, reduced_tax - reduced_tax_before_credits) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py new file mode 100644 index 00000000000..2926f3fb7ad --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class amt_base_tax(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax" + unit = USD + documentation = "Alternative Minimum Tax (AMT) base tax, Form 6251 Part II Line 7 'All Others'" + reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.irs.income.amt + filing_status = tax_unit("filing_status", period) + # Line 6 + reduced_income = tax_unit("amt_income_less_exemptions", period) + # Line 7 consists of 3 parts: + # Tax on Foreign income (not modelled) + # Tax on capital gains (Part III) + # Regular AMT tax + # If Form 6251, Part III is required, the regular AMT tax is calculated + # by using the smaller of the regular AMT tax calculated on the + # reduced income or the regular AMT tax calculated on the applied income + + # Regular AMT tax: + bracket_fraction = where( + filing_status == filing_status.possible_values.SEPARATE, + 0.5, + 1.0, + ) + tax_rate_threshold = p.brackets.thresholds[-1] * bracket_fraction + lower_rate = p.brackets.rates[0] + higher_rate = p.brackets.rates[1] + lower_tax = min_(reduced_income, tax_rate_threshold) * lower_rate + higher_tax = max_(0, reduced_income - tax_rate_threshold) * higher_rate + return lower_tax + higher_tax diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.py new file mode 100644 index 00000000000..e3f91c7a716 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_part_iii_required.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class amt_part_iii_required(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax Part III required" + documentation = "Whether the Alternative Minimum Tax (AMT) Part III worksheet is required, Form 6251, Part III" + reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" + + def formula(tax_unit, period, parameters): + relevant_inputs = add( + tax_unit, + period, + [ + "dwks10", + "dwks13", + "dwks14", + "dwks19", + "unrecaptured_section_1250_gain", + ], + ) + return relevant_inputs > 0 diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.py new file mode 100644 index 00000000000..84147fab7a5 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_tax_including_cg.py @@ -0,0 +1,107 @@ +from policyengine_us.model_api import * + + +class amt_tax_including_cg(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax computed using the capital gains rates" + unit = USD + documentation = "Alternative Minimum Tax (AMT) liability computed using the capital gains rates, Form 6251, Part III" + reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" + + def formula(tax_unit, period, parameters): + # Line 12 + reduced_income = tax_unit("amt_income_less_exemptions", period) + # Line 13 - schedule D line 13 + cg_distributions = tax_unit("dwks13", period) + # Line 14 - schedule D line 19 + section_1250_gain_worksheet = tax_unit( + "unrecaptured_section_1250_gain", period + ) + # Line 15 - smaller of the sum of Line 13 and Line 14 or Schedule D line 10 + total_transactions_reported = tax_unit("dwks10", period) + capped_capital_gains = min_( + cg_distributions + section_1250_gain_worksheet, + total_transactions_reported, + ) + # Line 16 - smaller of Line 15 or Line 12 + capped_income = min_(capped_capital_gains, reduced_income) + # Line 17 - Line 12 minus Line 16 + excess_income = max_(0, reduced_income - capped_income) + # Line 18 - Apply CG tax rates to Line 17 + p = parameters(period).gov.irs + income_taxes_at_amt_rates = p.income.amt.brackets.calc(excess_income) + # Line 19 - First CG tax bracket threshold + filing_status = tax_unit("filing_status", period) + cg_bracket = p.capital_gains.brackets.thresholds["1"][filing_status] + # Line 20 - Schedule D Line 14 + lt_capital_loss_carryover = tax_unit("dwks14", period) + # Line 21 - Line 20 minus Line 19 + reduced_cg_bracket = max_(0, cg_bracket - lt_capital_loss_carryover) + # Line 22 - smaller of Line 12 or Line 13 + smaller_of_income_or_cg = min_(reduced_income, cg_distributions) + # Line 23 - smaller of Line 22 or Line 21 (amount is taxed at 0%) + cg_first_rate = p.capital_gains.brackets.rates["1"] + disregarded_gains = ( + min_(smaller_of_income_or_cg, reduced_cg_bracket) * cg_first_rate + ) + # Line 24 - Line 22 minus Line 23 + taxable_income_including_cg = max_( + smaller_of_income_or_cg - disregarded_gains, 0 + ) + # Line 25 - Second CG tax bracket threshold + second_cg_bracket = p.capital_gains.brackets.thresholds["2"][ + filing_status + ] + # Line 26 - same as line 21 + # Line 27 - Schedule D Line 21 + loss_limited_net_capital_gains = tax_unit( + "loss_limited_net_capital_gains", period + ) + # Line 28 - Line 26 plus Line 27 + first_cg_bracket_increased_by_loss = ( + loss_limited_net_capital_gains + reduced_cg_bracket + ) + # Line 29 Line 25 minus Line 28 + reduced_second_cg_bracket = max_( + 0, second_cg_bracket - first_cg_bracket_increased_by_loss + ) + # Line 30 - smaller of Line 24 or Line 29 + capped_income_including_cg = min_( + taxable_income_including_cg, reduced_second_cg_bracket + ) + # Line 31 - multiply Line 30by second CG tax rate + cg_second_bracket_tax = ( + capped_income_including_cg * p.capital_gains.brackets.rates["2"] + ) + # Line 32 - Line 23 plus Line 30 + taxed_gains = disregarded_gains + capped_income_including_cg + # Line 33 - Line 22 minus Line 32 + excess_taxed_gains = max_(0, smaller_of_income_or_cg - taxed_gains) + # Line 34 - multiply Line 33 by third CG tax rate + cg_third_bracket_tax = ( + excess_taxed_gains * p.capital_gains.brackets.rates["3"] + ) + # Line 35 - sum of Line 17, Line 32, Line 33 + final_taxed_income = excess_income + taxed_gains + excess_taxed_gains + # Line 36 Line 12 minus Line 35 + final_excess = max_(0, reduced_income - final_taxed_income) + # Line 37 - Multiply Line 36 by the AMT specific capital gain excess tax rate + # The increased tax does not applied if no recaptured section 1250 gains + unrecaptured_section_1250_gain = tax_unit( + "unrecaptured_section_1250_gain", period + ) + excess_tax = where( + unrecaptured_section_1250_gain == 0, + 0, + final_excess + * p.income.amt.capital_gains.capital_gain_excess_tax_rate, + ) + # Line 38 - sum of Line 18, Line 31, Line 34, and Line 37 + return ( + income_taxes_at_amt_rates + + cg_second_bracket_tax + + cg_third_bracket_tax + + excess_tax + ) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.py new file mode 100644 index 00000000000..f4014f53327 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/income/amt_income_less_exemptions.py @@ -0,0 +1,44 @@ +from policyengine_us.model_api import * + + +class amt_income_less_exemptions(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax Income less exemptions" + unit = USD + documentation = "Alternative Minimum Tax (AMT) income less exemptions" + + def formula(tax_unit, period, parameters): + # Form 6251, Part I + # Line 4 + amt_income = tax_unit("amt_income", period) + # For filers subject to the kiddie tax, the deductions are not added back + taxable_income = tax_unit("taxable_income", period) + kiddie_tax_applies = tax_unit("amt_kiddie_tax_applies", period) + applied_income = where(kiddie_tax_applies, taxable_income, amt_income) + # Form 6251, Part II top + p = parameters(period).gov.irs.income.amt + phase_out = p.exemption.phase_out + filing_status = tax_unit("filing_status", period) + # Line 5 the exemption amount is based on filing status and + # is phased-out at higher income + base_exemption_amount = p.exemption.amount[filing_status] + income_excess = max_(0, amt_income - phase_out.start[filing_status]) + exemption_phase_out = phase_out.rate * income_excess + reduced_exemption_amount = max_( + 0, + (base_exemption_amount - exemption_phase_out), + ) + # A reduced exemption amount is applied to kiddie tax filers + adj_earnings = tax_unit("filer_adjusted_earnings", period) + child_amount = p.exemption.child.amount + + exemption_cap = where( + kiddie_tax_applies, + adj_earnings + child_amount, + np.inf, + ) + capped_exemption_amount = min_(reduced_exemption_amount, exemption_cap) + # Line 6 + return max_(0, applied_income - capped_exemption_amount) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py new file mode 100644 index 00000000000..e3407c31ab7 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class amt_kiddie_tax_applies(Variable): + value_type = bool + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax kiddie tax applies" + documentation = "Whether the kiddie tax applies to the tax unit" + + def formula(tax_unit, period, parameters): + age_head = tax_unit("age_head", period) + child = parameters(period).gov.irs.dependent.ineligible_age + young_head = (age_head != 0) & (age_head < child.non_student) + no_or_young_spouse = tax_unit("age_spouse", period) < child.non_student + return young_head & no_or_young_spouse diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dividend_income_reduced_by_investment_income.py b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dividend_income_reduced_by_investment_income.py new file mode 100644 index 00000000000..6336d412ca8 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dividend_income_reduced_by_investment_income.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class dividend_income_reduced_by_investment_income(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Dividend income reduced by investment income" + documentation = "IRS Form 1040 Schedule D worksheet (part 1 of 6)" + unit = USD + + def formula(tax_unit, period, parameters): + qualified_dividend_income = add( + tax_unit, period, ["qualified_dividend_income"] + ) + investment_income = tax_unit("investment_income_form_4952", period) + # dwks04 always assumed to be zero + floored_investment_income = max_(0, investment_income) + return max_(0, qualified_dividend_income - floored_investment_income) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks06.py b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks06.py deleted file mode 100644 index 41ad0d2ba0d..00000000000 --- a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks06.py +++ /dev/null @@ -1,16 +0,0 @@ -from policyengine_us.model_api import * - - -class dwks06(Variable): - value_type = float - entity = TaxUnit - definition_period = YEAR - label = "IRS Form 1040 Schedule D worksheet (part 1 of 6)" - unit = USD - - def formula(tax_unit, period, parameters): - dwks02 = add(tax_unit, period, ["qualified_dividend_income"]) - dwks03 = tax_unit("investment_income_form_4952", period) - # dwks04 always assumed to be zero - dwks05 = max_(0, dwks03) - return max_(0, dwks02 - dwks05) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks09.py b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks09.py index 30c949c0285..457a2f005f3 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks09.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks09.py @@ -15,12 +15,12 @@ def formula(tax_unit, period, parameters): period, ["long_term_capital_gains", "qualified_dividend_income"], ) - dwks07 = min_(qdiv_plus_ltcg, tax_unit("net_capital_gains", period)) + net_cg = min_(qdiv_plus_ltcg, tax_unit("net_capital_gains", period)) # dwks08 = min(dwks03, dwks04) # dwks09 = max(0., dwks07 - dwks08) # BELOW TWO STATEMENTS ARE UNCLEAR IN LIGHT OF dwks09=... COMMENT other_cg = add(tax_unit, period, ["non_sch_d_capital_gains"]) - mod_cg = where(other_cg > 0, other_cg, max_(0, dwks07) + other_cg) + mod_cg = where(other_cg > 0, other_cg, max_(0, net_cg) + other_cg) return max_( 0, mod_cg - min_(0, tax_unit("investment_income_form_4952", period)), diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks10.py b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks10.py index 1aa2bd720e3..3cd875d37c5 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks10.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/capital_gains/dwks10.py @@ -9,7 +9,11 @@ class dwks10(Variable): unit = USD def formula(tax_unit, period, parameters): - dwks10_if_gains = add(tax_unit, period, ["dwks06", "dwks09"]) + dwks10_if_gains = add( + tax_unit, + period, + ["dividend_income_reduced_by_investment_income", "dwks09"], + ) dwks10_if_no_gains = max_( 0, min_( diff --git a/test.ipynb b/test.ipynb new file mode 100644 index 00000000000..9d367d6685c --- /dev/null +++ b/test.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/pavelmakarchuk/anaconda3/envs/pe/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1251561.]\n" + ] + } + ], + "source": [ + "from policyengine_us import Simulation\n", + "\n", + "\n", + "situation = {\n", + " \"people\": {\n", + " \"you\": {\"age\": {\"2024\": 40}, \"employment_income\": {\"2024\": 2000000}}\n", + " },\n", + " \"families\": {\"your family\": {\"members\": [\"you\"]}},\n", + " \"marital_units\": {\"your marital unit\": {\"members\": [\"you\"]}},\n", + " \"tax_units\": {\"your tax unit\": {\"members\": [\"you\"]}},\n", + " \"spm_units\": {\"your household\": {\"members\": [\"you\"]}},\n", + " \"households\": {\n", + " \"your household\": {\"members\": [\"you\"], \"state_name\": {\"2024\": \"TX\"}}\n", + " },\n", + "}\n", + "\n", + "simulation = Simulation(\n", + " situation=situation,\n", + ")\n", + "\n", + "output = simulation.calculate(\"household_net_income\", 2024)\n", + "print(output)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1985400.]\n" + ] + } + ], + "source": [ + "taxable_income = simulation.calculate(\"taxable_income\", 2024)\n", + "print(taxable_income)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0\n" + ] + } + ], + "source": [ + "amt = simulation.calculate(\"alternative_minimum_tax\", 2024)\n", + "print(amt.sum())" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0.]\n" + ] + } + ], + "source": [ + "tax_exempt_interest_income = simulation.calculate(\n", + " \"tax_exempt_interest_income\", 2024\n", + ")\n", + "print(tax_exempt_interest_income)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 3495. 13614.745 20518.86 27655.145 36517.586 45396.99\n", + " 54225.97 63024.965 71823.96 80622.95 89421.95 98220.945\n", + " 107019.94 115818.94 124617.93 133101.78 141498.75 150035.5\n", + " 159055.61 168075.72 177086.77 186016.42 194946.06 203875.72\n", + " 212805.36 221735. 230664.66 239557.97 248336.64 257069.42\n", + " 265809.2 274503.47 283167.78 291832.1 298943.9 305660.56\n", + " 312210.3 318644.72 325056. 331467.25 337873.7 343480.94\n", + " 349088.16 354695.4 360302.62 365909.88 371259.5 376565.25\n", + " 381870.97 387176.7 392482.44 397788.16 403093.88 408399.62\n", + " 413705.3 419011.06 424316.78 429622.5 434928.25 440233.97\n", + " 445539.7 450845.44 456151.16 461456.88 466698.03 471897.22\n", + " 477096.44 482295.62 487494.8 492694. 497893.2 503003.38\n", + " 508096. 513188.7 518281.34 523374.03 528466.75 533559.4\n", + " 538652. 543744.7 548837.4 553930. 558927.25 563818.94\n", + " 568710.6 573602.25 578493.9 583385.56 588277.25 593168.9\n", + " 598060.5 602952.2 607843.9 612735.5 617627.1 622518.8\n", + " 627410.5 632302.1 637113.6 641898.75 646683.9 651469.\n", + " 656254.1 661039.25 665824.4 670609.5 675394.6 680179.75\n", + " 684964.9 689750. 694535.1 699320.25 704105.4 708890.5\n", + " 713675.6 718460.75 723245.9 728031. 732816.1 737601.25\n", + " 742386.4 747171.5 751956.6 756741.75 761526.9 766312.\n", + " 771097.1 775882.25 780667.4 785452.5 790237.6 795022.75\n", + " 799807.9 804593. 809378.1 814163.25 818948.4 823733.5\n", + " 828518.6 833303.75 838088.9 842874. 847659.1 852444.25\n", + " 857229.4 862014.5 866799.6 871584.75 876369.9 881155.\n", + " 885940.2 890725.3 895510.44 900295.56 905080.7 909865.8\n", + " 914650.94 919436.06 924221.2 929006.3 933791.44 938576.56\n", + " 943361.75 948146.9 952932. 957717.1 962502.2 967287.3\n", + " 972072.5 976857.56 981642.75 986427.8 991212.94 995998.06\n", + " 1000783.2 1005568.4 1010353.44 1015138.6 1019923.7 1024708.9\n", + " 1029493.94 1034279.1 1039064.2 1043849.4 1048634.5 1053419.6\n", + " 1058204.8 1062989.9 1067775. 1072560.1 1077345.2 1082130.4\n", + " 1086915.5 1091700.5 1096485.8 1101270.8 1106056. 1110841.\n", + " 1115626.2 1120411.2 ]\n" + ] + } + ], + "source": [ + "from policyengine_us import Simulation\n", + "\n", + "\n", + "situation = {\n", + " \"people\": {\n", + " \"you\": {\n", + " \"age\": {\"2024\": 40},\n", + " \"real_estate_taxes\": {\"2024\": 100000},\n", + " \"charitable_cash_donations\": {\"2024\": 100000},\n", + " \"charitable_non_cash_donations\": {\"2024\": 100000},\n", + " }\n", + " },\n", + " \"families\": {\"your family\": {\"members\": [\"you\"]}},\n", + " \"marital_units\": {\"your marital unit\": {\"members\": [\"you\"]}},\n", + " \"tax_units\": {\"your tax unit\": {\"members\": [\"you\"]}},\n", + " \"spm_units\": {\"your household\": {\"members\": [\"you\"]}},\n", + " \"households\": {\n", + " \"your household\": {\"members\": [\"you\"], \"state_name\": {\"2024\": \"CA\"}}\n", + " },\n", + " \"axes\": [\n", + " [{\"name\": \"employment_income\", \"count\": 200, \"min\": 0, \"max\": 2000000}]\n", + " ],\n", + "}\n", + "\n", + "simulation = Simulation(\n", + " situation=situation,\n", + ")\n", + "\n", + "output = simulation.calculate(\"household_net_income\", 2024)\n", + "print(output)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", + " 0. 0. 0. 0. 0. 0. 0. 0.]\n" + ] + } + ], + "source": [ + "amt = simulation.calculate(\"alternative_minimum_tax\", 2024)\n", + "print(amt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "pe", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 1ec06ddc449a09cff4995571212fb63781f77bce Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 14:24:37 +0100 Subject: [PATCH 2/6] revert --- .../rent_relief_credit/high_income_area_threshold_increase.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml b/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml index 54b6ae6ce24..9f0997527f0 100644 --- a/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml +++ b/policyengine_us/parameters/gov/contrib/harris/rent_relief_act/rent_relief_credit/high_income_area_threshold_increase.yaml @@ -8,4 +8,4 @@ metadata: href: https://www.congress.gov/bill/116th-congress/senate-bill/1106/text values: - 2019-01-01: 2 + 2019-01-01: 25_000 From 244391d7f3581c6f3d22649830a3e128fb664cf2 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 14:25:09 +0100 Subject: [PATCH 3/6] delete notebook --- test.ipynb | 239 ----------------------------------------------------- 1 file changed, 239 deletions(-) delete mode 100644 test.ipynb diff --git a/test.ipynb b/test.ipynb deleted file mode 100644 index 9d367d6685c..00000000000 --- a/test.ipynb +++ /dev/null @@ -1,239 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/pavelmakarchuk/anaconda3/envs/pe/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1251561.]\n" - ] - } - ], - "source": [ - "from policyengine_us import Simulation\n", - "\n", - "\n", - "situation = {\n", - " \"people\": {\n", - " \"you\": {\"age\": {\"2024\": 40}, \"employment_income\": {\"2024\": 2000000}}\n", - " },\n", - " \"families\": {\"your family\": {\"members\": [\"you\"]}},\n", - " \"marital_units\": {\"your marital unit\": {\"members\": [\"you\"]}},\n", - " \"tax_units\": {\"your tax unit\": {\"members\": [\"you\"]}},\n", - " \"spm_units\": {\"your household\": {\"members\": [\"you\"]}},\n", - " \"households\": {\n", - " \"your household\": {\"members\": [\"you\"], \"state_name\": {\"2024\": \"TX\"}}\n", - " },\n", - "}\n", - "\n", - "simulation = Simulation(\n", - " situation=situation,\n", - ")\n", - "\n", - "output = simulation.calculate(\"household_net_income\", 2024)\n", - "print(output)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1985400.]\n" - ] - } - ], - "source": [ - "taxable_income = simulation.calculate(\"taxable_income\", 2024)\n", - "print(taxable_income)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.0\n" - ] - } - ], - "source": [ - "amt = simulation.calculate(\"alternative_minimum_tax\", 2024)\n", - "print(amt.sum())" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.]\n" - ] - } - ], - "source": [ - "tax_exempt_interest_income = simulation.calculate(\n", - " \"tax_exempt_interest_income\", 2024\n", - ")\n", - "print(tax_exempt_interest_income)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ 3495. 13614.745 20518.86 27655.145 36517.586 45396.99\n", - " 54225.97 63024.965 71823.96 80622.95 89421.95 98220.945\n", - " 107019.94 115818.94 124617.93 133101.78 141498.75 150035.5\n", - " 159055.61 168075.72 177086.77 186016.42 194946.06 203875.72\n", - " 212805.36 221735. 230664.66 239557.97 248336.64 257069.42\n", - " 265809.2 274503.47 283167.78 291832.1 298943.9 305660.56\n", - " 312210.3 318644.72 325056. 331467.25 337873.7 343480.94\n", - " 349088.16 354695.4 360302.62 365909.88 371259.5 376565.25\n", - " 381870.97 387176.7 392482.44 397788.16 403093.88 408399.62\n", - " 413705.3 419011.06 424316.78 429622.5 434928.25 440233.97\n", - " 445539.7 450845.44 456151.16 461456.88 466698.03 471897.22\n", - " 477096.44 482295.62 487494.8 492694. 497893.2 503003.38\n", - " 508096. 513188.7 518281.34 523374.03 528466.75 533559.4\n", - " 538652. 543744.7 548837.4 553930. 558927.25 563818.94\n", - " 568710.6 573602.25 578493.9 583385.56 588277.25 593168.9\n", - " 598060.5 602952.2 607843.9 612735.5 617627.1 622518.8\n", - " 627410.5 632302.1 637113.6 641898.75 646683.9 651469.\n", - " 656254.1 661039.25 665824.4 670609.5 675394.6 680179.75\n", - " 684964.9 689750. 694535.1 699320.25 704105.4 708890.5\n", - " 713675.6 718460.75 723245.9 728031. 732816.1 737601.25\n", - " 742386.4 747171.5 751956.6 756741.75 761526.9 766312.\n", - " 771097.1 775882.25 780667.4 785452.5 790237.6 795022.75\n", - " 799807.9 804593. 809378.1 814163.25 818948.4 823733.5\n", - " 828518.6 833303.75 838088.9 842874. 847659.1 852444.25\n", - " 857229.4 862014.5 866799.6 871584.75 876369.9 881155.\n", - " 885940.2 890725.3 895510.44 900295.56 905080.7 909865.8\n", - " 914650.94 919436.06 924221.2 929006.3 933791.44 938576.56\n", - " 943361.75 948146.9 952932. 957717.1 962502.2 967287.3\n", - " 972072.5 976857.56 981642.75 986427.8 991212.94 995998.06\n", - " 1000783.2 1005568.4 1010353.44 1015138.6 1019923.7 1024708.9\n", - " 1029493.94 1034279.1 1039064.2 1043849.4 1048634.5 1053419.6\n", - " 1058204.8 1062989.9 1067775. 1072560.1 1077345.2 1082130.4\n", - " 1086915.5 1091700.5 1096485.8 1101270.8 1106056. 1110841.\n", - " 1115626.2 1120411.2 ]\n" - ] - } - ], - "source": [ - "from policyengine_us import Simulation\n", - "\n", - "\n", - "situation = {\n", - " \"people\": {\n", - " \"you\": {\n", - " \"age\": {\"2024\": 40},\n", - " \"real_estate_taxes\": {\"2024\": 100000},\n", - " \"charitable_cash_donations\": {\"2024\": 100000},\n", - " \"charitable_non_cash_donations\": {\"2024\": 100000},\n", - " }\n", - " },\n", - " \"families\": {\"your family\": {\"members\": [\"you\"]}},\n", - " \"marital_units\": {\"your marital unit\": {\"members\": [\"you\"]}},\n", - " \"tax_units\": {\"your tax unit\": {\"members\": [\"you\"]}},\n", - " \"spm_units\": {\"your household\": {\"members\": [\"you\"]}},\n", - " \"households\": {\n", - " \"your household\": {\"members\": [\"you\"], \"state_name\": {\"2024\": \"CA\"}}\n", - " },\n", - " \"axes\": [\n", - " [{\"name\": \"employment_income\", \"count\": 200, \"min\": 0, \"max\": 2000000}]\n", - " ],\n", - "}\n", - "\n", - "simulation = Simulation(\n", - " situation=situation,\n", - ")\n", - "\n", - "output = simulation.calculate(\"household_net_income\", 2024)\n", - "print(output)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", - " 0. 0. 0. 0. 0. 0. 0. 0.]\n" - ] - } - ], - "source": [ - "amt = simulation.calculate(\"alternative_minimum_tax\", 2024)\n", - "print(amt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "pe", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.14" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 4fe01a39c0f4f734c57a60cec245e6233dfd7f9f Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 14:25:59 +0100 Subject: [PATCH 4/6] comment remove --- .../alternative_minimum_tax/amt_base_tax.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py index 2926f3fb7ad..dcfadc58326 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py @@ -13,17 +13,7 @@ class amt_base_tax(Variable): def formula(tax_unit, period, parameters): p = parameters(period).gov.irs.income.amt filing_status = tax_unit("filing_status", period) - # Line 6 reduced_income = tax_unit("amt_income_less_exemptions", period) - # Line 7 consists of 3 parts: - # Tax on Foreign income (not modelled) - # Tax on capital gains (Part III) - # Regular AMT tax - # If Form 6251, Part III is required, the regular AMT tax is calculated - # by using the smaller of the regular AMT tax calculated on the - # reduced income or the regular AMT tax calculated on the applied income - - # Regular AMT tax: bracket_fraction = where( filing_status == filing_status.possible_values.SEPARATE, 0.5, From d8be53a45249ac3be3c46b43078a4f3b2dc240c5 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 16:17:41 +0100 Subject: [PATCH 5/6] test fix --- .../reforms/second_earner/second_earner_tax_reform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policyengine_us/reforms/second_earner/second_earner_tax_reform.py b/policyengine_us/reforms/second_earner/second_earner_tax_reform.py index 7e8eeebd387..1a72f8fb62d 100644 --- a/policyengine_us/reforms/second_earner/second_earner_tax_reform.py +++ b/policyengine_us/reforms/second_earner/second_earner_tax_reform.py @@ -684,7 +684,7 @@ def formula(tax_unit, period, parameters): line44 = dwks14 # Apply different thresholds for primary/secondary for capital gains - cg = p.capital_gains.brackets + cg = parameters(period).gov.irs.capital_gains.brackets primary_line45 = max_( 0, cg.thresholds["1"][filing_status] - line44 ) From 9ede0e4095ee127fb949a6fd50a88083989db959 Mon Sep 17 00:00:00 2001 From: PavelMakarchuk Date: Tue, 4 Feb 2025 23:41:22 +0100 Subject: [PATCH 6/6] format fixes --- changelog_entry.yaml | 2 +- .../gov/irs/income/amt/multiplier.yaml | 21 +++++++++++++++++ .../{ => base_tax}/amt_base_tax.yaml | 0 .../base_tax/amt_higher_base_tax.yaml | 23 +++++++++++++++++++ .../base_tax/amt_lower_base_tax.yaml | 23 +++++++++++++++++++ .../base_tax/amt_base_tax.py | 16 +++++++++++++ .../amt_higher_base_tax.py} | 17 ++++---------- .../base_tax/amt_lower_base_tax.py | 20 ++++++++++++++++ .../kiddie_tax/amt_kiddie_tax_applies.py | 6 ++--- 9 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 policyengine_us/parameters/gov/irs/income/amt/multiplier.yaml rename policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/{ => base_tax}/amt_base_tax.yaml (100%) create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.yaml create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.py rename policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/{amt_base_tax.py => base_tax/amt_higher_base_tax.py} (55%) create mode 100644 policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.py diff --git a/changelog_entry.yaml b/changelog_entry.yaml index 822eb2d31db..f035801bf44 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -1,4 +1,4 @@ - bump: minor changes: added: - - Reafctor the Alternative Minimum Tax (AMT) logic. + - Refactor the Alternative Minimum Tax (AMT) logic. diff --git a/policyengine_us/parameters/gov/irs/income/amt/multiplier.yaml b/policyengine_us/parameters/gov/irs/income/amt/multiplier.yaml new file mode 100644 index 00000000000..f55398da609 --- /dev/null +++ b/policyengine_us/parameters/gov/irs/income/amt/multiplier.yaml @@ -0,0 +1,21 @@ +description: The IRS multiplies the Alternative Minimum Tax income tax brackets by this rate, based on filing status. +metadata: + unit: /1 + period: year + breakdown: + - filing_status + label: AMT tax bracket multiplier + reference: + - title: 26 U.S. Code § 55 - Alternative minimum tax imposed (b)(1)(C) + href: https://www.law.cornell.edu/uscode/text/26/55#b_1_C + +SINGLE: + 2013-01-01: 1 +JOINT: + 2013-01-01: 1 +HEAD_OF_HOUSEHOLD: + 2013-01-01: 1 +SURVIVING_SPOUSE: + 2013-01-01: 0.5 +SEPARATE: + 2013-01-01: 1 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.yaml similarity index 100% rename from policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.yaml rename to policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.yaml diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.yaml new file mode 100644 index 00000000000..5a977f910aa --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.yaml @@ -0,0 +1,23 @@ +- name: Single person, low income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 10_000 + output: + amt_higher_base_tax: 0 + +- name: Single person, 400k income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 400_000 + output: + amt_higher_base_tax: 54_292 + +- name: Joint, 600k income + period: 2022 + input: + filing_status: JOINT + amt_income_less_exemptions: 600_000 + output: + amt_higher_base_tax: 110_292 diff --git a/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.yaml b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.yaml new file mode 100644 index 00000000000..031f588ebba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.yaml @@ -0,0 +1,23 @@ +- name: Single person, low income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 10_000 + output: + amt_lower_base_tax: 2_600 + +- name: Single person, no income + period: 2022 + input: + filing_status: SINGLE + amt_income_less_exemptions: 0 + output: + amt_lower_base_tax: 0 + +- name: Joint, high income + period: 2022 + input: + filing_status: JOINT + amt_income_less_exemptions: 400_000 + output: + amt_lower_base_tax: 53_586 diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.py new file mode 100644 index 00000000000..2c773f946ee --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_base_tax.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class amt_base_tax(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax base tax" + unit = USD + documentation = "Alternative Minimum Tax (AMT) base tax, Form 6251 Part II Line 7 'All Others'" + reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" + + adds = [ + "amt_lower_base_tax", + "amt_higher_base_tax", + ] diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.py similarity index 55% rename from policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py rename to policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.py index dcfadc58326..9c13d570c7f 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/amt_base_tax.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_higher_base_tax.py @@ -1,27 +1,20 @@ from policyengine_us.model_api import * -class amt_base_tax(Variable): +class amt_higher_base_tax(Variable): value_type = float entity = TaxUnit definition_period = YEAR - label = "Alternative Minimum Tax" + label = "Alternative Minimum Tax higher base tax amount" unit = USD - documentation = "Alternative Minimum Tax (AMT) base tax, Form 6251 Part II Line 7 'All Others'" + documentation = "Alternative Minimum Tax (AMT) base tax, Form 6251 Part II Line 7 'All Others' - higher bracket" reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" def formula(tax_unit, period, parameters): p = parameters(period).gov.irs.income.amt filing_status = tax_unit("filing_status", period) reduced_income = tax_unit("amt_income_less_exemptions", period) - bracket_fraction = where( - filing_status == filing_status.possible_values.SEPARATE, - 0.5, - 1.0, - ) + bracket_fraction = p.multiplier[filing_status] tax_rate_threshold = p.brackets.thresholds[-1] * bracket_fraction - lower_rate = p.brackets.rates[0] higher_rate = p.brackets.rates[1] - lower_tax = min_(reduced_income, tax_rate_threshold) * lower_rate - higher_tax = max_(0, reduced_income - tax_rate_threshold) * higher_rate - return lower_tax + higher_tax + return max_(0, reduced_income - tax_rate_threshold) * higher_rate diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.py new file mode 100644 index 00000000000..fea07ad0982 --- /dev/null +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/base_tax/amt_lower_base_tax.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class amt_lower_base_tax(Variable): + value_type = float + entity = TaxUnit + definition_period = YEAR + label = "Alternative Minimum Tax lower base tax amount" + unit = USD + documentation = "Alternative Minimum Tax (AMT) base tax, Form 6251 Part II Line 7 'All Others' - lower bracket" + reference = "https://www.irs.gov/pub/irs-pdf/f6251.pdf" + + def formula(tax_unit, period, parameters): + p = parameters(period).gov.irs.income.amt + filing_status = tax_unit("filing_status", period) + reduced_income = tax_unit("amt_income_less_exemptions", period) + bracket_fraction = p.multiplier[filing_status] + tax_rate_threshold = p.brackets.thresholds[-1] * bracket_fraction + lower_rate = p.brackets.rates[0] + return min_(reduced_income, tax_rate_threshold) * lower_rate diff --git a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py index e3407c31ab7..f4c857896ac 100644 --- a/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py +++ b/policyengine_us/variables/gov/irs/tax/federal_income/alternative_minimum_tax/kiddie_tax/amt_kiddie_tax_applies.py @@ -10,7 +10,7 @@ class amt_kiddie_tax_applies(Variable): def formula(tax_unit, period, parameters): age_head = tax_unit("age_head", period) - child = parameters(period).gov.irs.dependent.ineligible_age - young_head = (age_head != 0) & (age_head < child.non_student) - no_or_young_spouse = tax_unit("age_spouse", period) < child.non_student + p = parameters(period).gov.irs.dependent.ineligible_age + young_head = (age_head != 0) & (age_head < p.non_student) + no_or_young_spouse = tax_unit("age_spouse", period) < p.non_student return young_head & no_or_young_spouse