taxcalc 4.2.1__py3-none-any.whl → 4.3.0__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.
Files changed (123) hide show
  1. taxcalc/__init__.py +1 -1
  2. taxcalc/assumptions/ASSUMPTIONS.md +53 -0
  3. taxcalc/assumptions/README.md +17 -0
  4. taxcalc/assumptions/economic_assumptions_template.json +77 -0
  5. taxcalc/calcfunctions.py +7 -4
  6. taxcalc/data.py +10 -5
  7. taxcalc/policy.py +1 -1
  8. taxcalc/policy_current_law.json +4649 -288
  9. taxcalc/records.py +20 -15
  10. taxcalc/reforms/2017_law.json +125 -0
  11. taxcalc/reforms/2017_law.out.csv +10 -0
  12. taxcalc/reforms/ARPA.json +78 -0
  13. taxcalc/reforms/ARPA.out.csv +10 -0
  14. taxcalc/reforms/BrownKhanna.json +23 -0
  15. taxcalc/reforms/BrownKhanna.out.csv +10 -0
  16. taxcalc/reforms/CARES.json +40 -0
  17. taxcalc/reforms/CARES.out.csv +10 -0
  18. taxcalc/reforms/ConsolidatedAppropriationsAct2021.json +15 -0
  19. taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv +10 -0
  20. taxcalc/reforms/Larson2019.json +36 -0
  21. taxcalc/reforms/Larson2019.out.csv +10 -0
  22. taxcalc/reforms/README.md +22 -0
  23. taxcalc/reforms/REFORMS.md +92 -0
  24. taxcalc/reforms/Renacci.json +61 -0
  25. taxcalc/reforms/Renacci.out.csv +10 -0
  26. taxcalc/reforms/SandersDeFazio.json +15 -0
  27. taxcalc/reforms/SandersDeFazio.out.csv +10 -0
  28. taxcalc/reforms/TCJA.json +160 -0
  29. taxcalc/reforms/TCJA.md +48 -0
  30. taxcalc/reforms/TCJA.out.csv +10 -0
  31. taxcalc/reforms/Trump2016.json +71 -0
  32. taxcalc/reforms/Trump2016.out.csv +10 -0
  33. taxcalc/reforms/Trump2017.json +51 -0
  34. taxcalc/reforms/Trump2017.out.csv +10 -0
  35. taxcalc/reforms/archive/Clinton2016.json +56 -0
  36. taxcalc/reforms/archive/RyanBrady.json +104 -0
  37. taxcalc/reforms/archive/TCJA_House.json +144 -0
  38. taxcalc/reforms/archive/TCJA_House_Amended.json +152 -0
  39. taxcalc/reforms/archive/TCJA_Reconciliation.json +187 -0
  40. taxcalc/reforms/archive/TCJA_Senate.json +116 -0
  41. taxcalc/reforms/archive/TCJA_Senate_111417.json +169 -0
  42. taxcalc/reforms/archive/TCJA_Senate_120117.json +174 -0
  43. taxcalc/reforms/cases.csv +10 -0
  44. taxcalc/reforms/clp.out.csv +10 -0
  45. taxcalc/reforms/ext.json +59 -0
  46. taxcalc/reforms/growfactors_ext.csv +65 -0
  47. taxcalc/reforms/ptaxes0.json +37 -0
  48. taxcalc/reforms/ptaxes0.out.csv +10 -0
  49. taxcalc/reforms/ptaxes1.json +21 -0
  50. taxcalc/reforms/ptaxes1.out.csv +10 -0
  51. taxcalc/reforms/ptaxes2.json +18 -0
  52. taxcalc/reforms/ptaxes2.out.csv +10 -0
  53. taxcalc/reforms/ptaxes3.json +28 -0
  54. taxcalc/reforms/ptaxes3.out.csv +10 -0
  55. taxcalc/taxcalcio.py +44 -22
  56. taxcalc/tests/benefits_expect.csv +169 -0
  57. taxcalc/tests/cmpi_cps_expect.txt +132 -0
  58. taxcalc/tests/cmpi_puf_expect.txt +132 -0
  59. taxcalc/tests/conftest.py +143 -0
  60. taxcalc/tests/cpscsv_agg_expect.csv +26 -0
  61. taxcalc/tests/puf_var_correl_coeffs_2016.csv +80 -0
  62. taxcalc/tests/puf_var_wght_means_by_year.csv +80 -0
  63. taxcalc/tests/pufcsv_agg_expect.csv +26 -0
  64. taxcalc/tests/pufcsv_mtr_expect.txt +63 -0
  65. taxcalc/tests/reforms.json +649 -0
  66. taxcalc/tests/reforms_expect.csv +65 -0
  67. taxcalc/tests/test_4package.py +67 -0
  68. taxcalc/tests/test_benefits.py +86 -0
  69. taxcalc/tests/test_calcfunctions.py +871 -0
  70. taxcalc/tests/test_calculator.py +1021 -0
  71. taxcalc/tests/test_compare.py +336 -0
  72. taxcalc/tests/test_compatible_data.py +338 -0
  73. taxcalc/tests/test_consumption.py +144 -0
  74. taxcalc/tests/test_cpscsv.py +163 -0
  75. taxcalc/tests/test_data.py +133 -0
  76. taxcalc/tests/test_decorators.py +332 -0
  77. taxcalc/tests/test_growdiff.py +102 -0
  78. taxcalc/tests/test_growfactors.py +94 -0
  79. taxcalc/tests/test_parameters.py +617 -0
  80. taxcalc/tests/test_policy.py +1557 -0
  81. taxcalc/tests/test_puf_var_stats.py +194 -0
  82. taxcalc/tests/test_pufcsv.py +385 -0
  83. taxcalc/tests/test_records.py +234 -0
  84. taxcalc/tests/test_reforms.py +386 -0
  85. taxcalc/tests/test_responses.py +41 -0
  86. taxcalc/tests/test_taxcalcio.py +755 -0
  87. taxcalc/tests/test_utils.py +792 -0
  88. taxcalc/validation/CSV_INPUT_VARS.md +29 -0
  89. taxcalc/validation/CSV_OUTPUT_VARS.md +63 -0
  90. taxcalc/validation/README.md +68 -0
  91. taxcalc/validation/taxsim35/Differences_Explained.md +54 -0
  92. taxcalc/validation/taxsim35/README.md +139 -0
  93. taxcalc/validation/taxsim35/expected_differences/a17-taxdiffs-expect.csv +25 -0
  94. taxcalc/validation/taxsim35/expected_differences/a18-taxdiffs-expect.csv +25 -0
  95. taxcalc/validation/taxsim35/expected_differences/a19-taxdiffs-expect.csv +25 -0
  96. taxcalc/validation/taxsim35/expected_differences/a20-taxdiffs-expect.csv +25 -0
  97. taxcalc/validation/taxsim35/expected_differences/a21-taxdiffs-expect.csv +25 -0
  98. taxcalc/validation/taxsim35/expected_differences/b17-taxdiffs-expect.csv +25 -0
  99. taxcalc/validation/taxsim35/expected_differences/b18-taxdiffs-expect.csv +25 -0
  100. taxcalc/validation/taxsim35/expected_differences/b19-taxdiffs-expect.csv +25 -0
  101. taxcalc/validation/taxsim35/expected_differences/b20-taxdiffs-expect.csv +25 -0
  102. taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv +25 -0
  103. taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv +25 -0
  104. taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv +25 -0
  105. taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv +25 -0
  106. taxcalc/validation/taxsim35/input_setup.py +67 -0
  107. taxcalc/validation/taxsim35/main_comparison.py +183 -0
  108. taxcalc/validation/taxsim35/prepare_taxcalc_input.py +161 -0
  109. taxcalc/validation/taxsim35/process_taxcalc_output.py +140 -0
  110. taxcalc/validation/taxsim35/taxsim_emulation.json +49 -0
  111. taxcalc/validation/taxsim35/taxsim_input.py +321 -0
  112. taxcalc/validation/taxsim35/tc_sims.py +98 -0
  113. taxcalc/validation/taxsim35/tests_35.py +80 -0
  114. taxcalc/validation/tests_35.sh +13 -0
  115. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/METADATA +3 -4
  116. taxcalc-4.3.0.dist-info/RECORD +139 -0
  117. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/WHEEL +1 -1
  118. taxcalc/tmd_growfactors.csv +0 -55
  119. taxcalc/tmd_weights.csv.gz +0 -0
  120. taxcalc-4.2.1.dist-info/RECORD +0 -34
  121. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/LICENSE +0 -0
  122. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/entry_points.txt +0 -0
  123. {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,25 @@
1
+ ,# of differing records,max_diff,max_diff_index,max_diff_taxsim_val,max_diff_taxcalc_val
2
+ iitax,1000,-27840.640000000014,246,246001.89,218161.25
3
+ statetax,0,0.0,no diff,no diff,no diff
4
+ payrolltax,939,15897.900000000001,861,39167.24,55065.14
5
+ mtr_inctax,384,-21.490000000000002,17,50.49,29.0
6
+ mtr_state,0,0.0,no diff,no diff,no diff
7
+ c00100,573,-7949.859999999986,861,963275.51,955325.65
8
+ e02300,0,0.0,no diff,no diff,no diff
9
+ c02500,0,0.0,no diff,no diff,no diff
10
+ post_phase_out_pe,0,0.0,no diff,no diff,no diff
11
+ phased_out_pe,0,0.0,no diff,no diff,no diff
12
+ c21040,0,0.0,no diff,no diff,no diff
13
+ c04470,0,0.0,no diff,no diff,no diff
14
+ c04800,1000,-75244.97999999998,246,828115.91,752870.93
15
+ taxbc,1000,-32292.660000000003,956,229141.22,196848.56
16
+ exemption_surtax,0,0.0,no diff,no diff,no diff
17
+ gen_tax_credit,0,0.0,no diff,no diff,no diff
18
+ non_refundable_child_odep_credit,12,234.75,561,1293.63,1528.38
19
+ c11070,0,0.0,no diff,no diff,no diff
20
+ c07180,0,0.0,no diff,no diff,no diff
21
+ eitc,0,0.0,no diff,no diff,no diff
22
+ c62100,1000,-75244.97999999998,246,854715.91,779470.93
23
+ amt_liability,0,0.0,no diff,no diff,no diff
24
+ iitax_before_credits_ex_AMT,1000,-27840.640000000014,246,245271.89,217431.25
25
+ recovery_rebate_credit,0,0.0,no diff,no diff,no diff
@@ -0,0 +1,25 @@
1
+ ,# of differing records,max_diff,max_diff_index,max_diff_taxsim_val,max_diff_taxcalc_val
2
+ iitax,1000,-27608.780000000028,837,312222.07,284613.29
3
+ statetax,0,0.0,no diff,no diff,no diff
4
+ payrolltax,942,16454.309999999998,873,46662.91,63117.22
5
+ mtr_inctax,366,-19.259999999999998,130,48.26,29.0
6
+ mtr_state,0,0.0,no diff,no diff,no diff
7
+ c00100,550,-8228.23999999999,873,1128648.72,1120420.48
8
+ e02300,0,0.0,no diff,no diff,no diff
9
+ c02500,0,0.0,no diff,no diff,no diff
10
+ post_phase_out_pe,0,0.0,no diff,no diff,no diff
11
+ phased_out_pe,0,0.0,no diff,no diff,no diff
12
+ c21040,0,0.0,no diff,no diff,no diff
13
+ c04470,0,0.0,no diff,no diff,no diff
14
+ c04800,1000,-74618.33999999997,837,1015746.15,941127.81
15
+ taxbc,1000,-29988.790000000037,837,313966.08,283977.29
16
+ exemption_surtax,0,0.0,no diff,no diff,no diff
17
+ gen_tax_credit,0,0.0,no diff,no diff,no diff
18
+ non_refundable_child_odep_credit,10,382.96000000000004,3,3128.1,3511.06
19
+ c11070,0,0.0,no diff,no diff,no diff
20
+ c07180,0,0.0,no diff,no diff,no diff
21
+ eitc,0,0.0,no diff,no diff,no diff
22
+ c62100,1000,-74618.33999999997,837,1025746.15,951127.81
23
+ amt_liability,0,0.0,no diff,no diff,no diff
24
+ iitax_before_credits_ex_AMT,1000,-27608.780000000028,837,311586.07,283977.29
25
+ recovery_rebate_credit,0,0.0,no diff,no diff,no diff
@@ -0,0 +1,67 @@
1
+ """
2
+ Generates TAXSIM-35 `.in` input files, downloads `.in.out-taxsim` output files,
3
+ prepares files for Tax Calculator and zips them
4
+ """
5
+
6
+ import os
7
+ import glob
8
+ import taxsim_input
9
+
10
+
11
+ def get_ftp_output(letter, year):
12
+ """
13
+ Uses `curl` to upload assumption set input files
14
+ and save taxsim-35 output files
15
+
16
+ Args:
17
+ letter (character): letter denoting assumption set to generate data
18
+ year (int): year data will represent
19
+ offset (int): offset to alter the random number seed
20
+
21
+ Returns:
22
+ None
23
+ """
24
+ f = str(letter + str(year) + ".in")
25
+ file_out = f + ".out-taxsim"
26
+ os.system(
27
+ f"ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null taxsim35@taxsim35.nber.org <{f} >{file_out}"
28
+ )
29
+
30
+
31
+ def change_delim(letter, year):
32
+ """ "
33
+ This function changes the delimeter in the taxsim output files from
34
+ a comma to a space
35
+
36
+ This is necessary because taxsim output seems to vary - for some years
37
+ the separator is a comma and for others (seemingly before 2020) it's a space
38
+
39
+ Args:
40
+ letter (character): letter denoting assumption set to generate data
41
+ year (int): year data will represent
42
+ offset (int): offset to alter the random number seed
43
+
44
+ Returns:
45
+ None
46
+ """
47
+ f = str(letter + str(year) + ".in")
48
+ file_out = f + ".out-taxsim"
49
+ # Read in the file
50
+ with open(file_out, "r") as fin:
51
+ filedata = fin.read()
52
+
53
+ # Replace the target string
54
+ # filedata = filedata.replace(",", " ")
55
+ filedata = filedata.replace(" ", "")
56
+
57
+ # Write the file out again
58
+ with open(file_out, "w") as fout:
59
+ fout.write(filedata)
60
+
61
+
62
+ def taxsim_io(assump_set, years):
63
+ for letter in assump_set:
64
+ for year in years:
65
+ taxsim_input.generate_datasets(letter, year)
66
+ get_ftp_output(letter, year)
67
+ change_delim(letter, year)
@@ -0,0 +1,183 @@
1
+ # DESCRIPTIONS of variable outputs can be found on the TAXSIM-35 website near
2
+ # the bottom of the page
3
+ # URL: https://users.nber.org/~taxsim/taxsim35/
4
+
5
+ import sys
6
+ import os
7
+ import pandas as pd
8
+ import numpy as np
9
+ import tc_sims
10
+
11
+ CUR_PATH = os.path.abspath(os.path.dirname(__file__))
12
+ # check if directory exists, if not create it
13
+ if not os.path.isdir(os.path.join(CUR_PATH, "actual_differences")):
14
+ os.mkdir(os.path.join(CUR_PATH, "actual_differences"))
15
+
16
+
17
+ def main(letter, year):
18
+
19
+ test_passed = False # set boolean to False, change in tests pass
20
+ # (1) generate TAXSIM-35-formatted output using Tax-Calculator tc CLI
21
+ tc_sims.io(letter, year)
22
+
23
+ # (2) generate tax differences
24
+ print("Trying to read ", f"{letter}{year}.in.out-taxsim")
25
+ taxsim_df = pd.read_csv(
26
+ f"{letter}{year}.in.out-taxsim",
27
+ # skipinitialspace=True,
28
+ # delim_whitespace=True,
29
+ index_col=False,
30
+ )
31
+ # taxsim_df = taxsim_df.iloc[:, 0:28]
32
+ taxcalc_df = pd.read_csv(
33
+ f"{letter}{year}.in.out-taxcalc",
34
+ # skipinitialspace=True,
35
+ index_col=0,
36
+ )
37
+
38
+ taxsim_out_cols_map = {
39
+ "taxsimid": "RECID",
40
+ "year": "FLPDYR",
41
+ "state": "state",
42
+ "fiitax": "iitax",
43
+ "siitax": "statetax",
44
+ "fica": "payrolltax",
45
+ "frate": "mtr_inctax",
46
+ "srate": "mtr_state",
47
+ # "ficar": "mtr_paytax", # not sure why, but this is always zero from taxsim
48
+ # "tfica": "ptax_oasdi", # I don't understand how fica and tfica differ in taxsim
49
+ "v10": "c00100", # federal agi
50
+ "v11": "e02300", # UI in federal AGI
51
+ "v12": "c02500", # social security in AGI
52
+ # "v13": "zero_bracket_amount", # zero bracket amount (for itemizers) -- always set to zero in taxcalc output
53
+ "v14": "post_phase_out_pe", # personal exemptions
54
+ "v15": "phased_out_pe", # exemption phaseout
55
+ "v16": "c21040", # deduction phaseout
56
+ "v17": "c04470", # itemized deductions
57
+ "v18": "c04800", # federal taxable income
58
+ "v19": "taxbc", # tax on taxable income (no special cap gains rates)
59
+ "v20": "exemption_surtax", # exemption surtax -- always set to zero in taxcalc output
60
+ "v21": "gen_tax_credit", # general tax credit -- always set to zero in taxcalc output
61
+ "v22": "non_refundable_child_odep_credit", # child tax credit (as adjusted) # Is this right?? Should it be c07220 only?
62
+ "v23": "c11070", # additional child tax credit (refundable)
63
+ "v24": "c07180", # child care credit
64
+ "v25": "eitc", # earned income credit (total federal)
65
+ "v26": "c62100", # income for amt
66
+ "v27": "amt_liability", # AMT liability
67
+ "v28": "iitax_before_credits_ex_AMT", # federal tax before credits
68
+ # "v29": , # FICA -- is this not the same as "fica" above?
69
+ # state calculations all zeros since we don't do state calculations
70
+ # "v30": , #state household income
71
+ # "v31": , # state rent expense
72
+ # "v32": , # state AGI
73
+ # "v33": , # state exemption amount
74
+ # "v34": , # state standard deduction
75
+ # "v35": , # state itemized deductions
76
+ # "v36": , # state taxable income
77
+ # "v37": , # state property tax credit
78
+ # "v38": , # state child care tax credit
79
+ # "v39": , # state EIC
80
+ # "v40": , # state total credits
81
+ # "v41": , # state bracket rate
82
+ # "v42": , # earned self-employed income for FICA
83
+ # "v43": , # medicare tax on unearned income
84
+ # "v44": , # medicare tax on earned income
85
+ "v45": "recovery_rebate_credit", # CARES act Recovery Rebates
86
+ # "v46": ,
87
+ # "v47": ,
88
+ }
89
+
90
+ # give tax-calculator variable names to taxsim output variables
91
+ taxsim_df.rename(columns=taxsim_out_cols_map, inplace=True)
92
+ taxsim_df = taxsim_df[list(taxsim_out_cols_map.values())]
93
+
94
+ diff_dict = {
95
+ "# of differing records": [],
96
+ "max_diff": [],
97
+ "max_diff_index": [],
98
+ "max_diff_taxsim_val": [],
99
+ "max_diff_taxcalc_val": [],
100
+ }
101
+ diff_df = taxcalc_df - taxsim_df
102
+ input_df = pd.read_csv(
103
+ f"{letter}{year}.in",
104
+ # skipinitialspace=True,
105
+ # delim_whitespace=True,
106
+ index_col=False,
107
+ )
108
+ with pd.ExcelWriter(
109
+ os.path.join(
110
+ CUR_PATH, "actual_differences", f"{letter}{year}differences.xlsx"
111
+ )
112
+ ) as writer:
113
+ # use to_excel function and specify the sheet_name and index
114
+ # to store the dataframe in specified sheet
115
+ taxsim_df.to_excel(writer, sheet_name="taxsim", index=False)
116
+ taxcalc_df.to_excel(writer, sheet_name="taxcalc", index=False)
117
+ diff_df.to_excel(writer, sheet_name="differences", index=False)
118
+ input_df.to_excel(writer, sheet_name="inputs", index=False)
119
+
120
+ for col in taxsim_df.columns[3:]:
121
+ df_diff = pd.DataFrame({"a": taxsim_df[col], "b": taxcalc_df[col]})
122
+ df_diff_recs = df_diff[df_diff["a"] != df_diff["b"]]
123
+ diff_dict["# of differing records"].append(df_diff_recs.shape[0])
124
+
125
+ ind, max_val = max(
126
+ enumerate(
127
+ abs(x - y)
128
+ for x, y in zip(taxcalc_df.loc[:, col], taxsim_df.loc[:, col])
129
+ ),
130
+ key=lambda x: x[1],
131
+ )
132
+
133
+ diff_dict["max_diff"].append(
134
+ taxcalc_df.loc[ind, col] - taxsim_df.loc[ind, col]
135
+ )
136
+ if max_val != 0:
137
+ diff_dict["max_diff_index"].append(ind)
138
+ diff_dict["max_diff_taxsim_val"].append(taxsim_df.loc[ind, col])
139
+ diff_dict["max_diff_taxcalc_val"].append(taxcalc_df.loc[ind, col])
140
+ else:
141
+ diff_dict["max_diff_index"].append("no diff")
142
+ diff_dict["max_diff_taxsim_val"].append("no diff")
143
+ diff_dict["max_diff_taxcalc_val"].append("no diff")
144
+
145
+ actual_df = pd.DataFrame(diff_dict, index=taxsim_df.columns[3:])
146
+ print(
147
+ f"Difference in dataframes for assumption set {letter} in year {year}"
148
+ )
149
+ print(actual_df)
150
+
151
+ # (3) check for difference between LYY.taxdiffs-actual and LYY.taxdiffs-expect
152
+ expected_file_name = os.path.join(
153
+ CUR_PATH, "expected_differences", f"{letter}{year}-taxdiffs-expect.csv"
154
+ )
155
+ if os.path.isfile(expected_file_name):
156
+ expect_df = pd.read_csv(expected_file_name, index_col=0)
157
+ print(actual_df.eq(expect_df))
158
+ test_passed = np.allclose(
159
+ actual_df[["# of differing records", "max_diff"]].values,
160
+ expect_df[["# of differing records", "max_diff"]].values
161
+ )
162
+
163
+ print(
164
+ "Above, True values mean the element is the same between the ACTUAL and EXPECT dataframes. "
165
+ + "(EXPECT files are used for debugging purposes.)"
166
+ )
167
+ else:
168
+ print("This EXPECT file doesn't exist.")
169
+
170
+ # (4) Write the created df to *.taxdiffs-actual
171
+ actual_df.to_csv(
172
+ os.path.join(
173
+ CUR_PATH,
174
+ "actual_differences",
175
+ f"{letter}{year}-taxdiffs-actual.csv",
176
+ )
177
+ )
178
+
179
+ return test_passed
180
+
181
+
182
+ if __name__ == "__main__":
183
+ sys.exit(main())
@@ -0,0 +1,161 @@
1
+ """
2
+ Translates TAXSIM-35 input file to Tax-Calculator tc input file.
3
+ """
4
+
5
+ # CODING-STYLE CHECKS:
6
+ # pycodestyle prepare_tc_input.py
7
+ # pylint --disable=locally-disabled prepare_tc_input.py
8
+
9
+ import argparse
10
+ import os
11
+ import sys
12
+ import numpy as np
13
+ import pandas as pd
14
+
15
+
16
+ TAXSIM_TC_MAP = {
17
+ "taxsimid": "RECID",
18
+ "year": "FLPDYR",
19
+ # 'state': # no Tax-Calculator use of TAXSIM variable 3, state code
20
+ # 'mstat', # Tax-Calculator MARS differs from TAXSIM mstat
21
+ "page": "age_head",
22
+ "sage": "age_spouse",
23
+ # 'depx': "", # no Tax-Calculator variable for total number of dependents
24
+ "dep13": "nu13",
25
+ "dep17": "nu18",
26
+ # 'dep18': "n24", #"f2441", # no direct Tax-Calculator use of number EIC qualified dependents
27
+ "pwages": "e00200p",
28
+ "swages": "e00200s",
29
+ "psemp": "e00900p",
30
+ "ssemp": "e00900s",
31
+ "dividends": "e00650",
32
+ "intrec": "e00300",
33
+ "stcg": "p22250",
34
+ "ltcg": "p23250",
35
+ "otherprop": "e02000",
36
+ "nonprop": "e00800",
37
+ "pensions": "e01700",
38
+ "gssi": "e02400",
39
+ # 'ui': 'e02300', # For TAXSIM-35, UI is separated between primary and secondary filers
40
+ # 'transfers': # no Tax-Calculator use of TAXSIM variable 22, non-taxable transfers
41
+ # 'rentpaid' # no Tax-Calculator use of TAXSIM variable 23, rent paid
42
+ "proptax": "e18500",
43
+ "otheritem": "e18400",
44
+ "childcare": "e32800",
45
+ "mortgage": "e19200",
46
+ "scorp": "e26270",
47
+ # 'pbusinc': 'e00900p', # Not perfect match for this in Tax-Calculator -- will add to e00900s below
48
+ # 'pprofinc': # no direct analog in Tax-Calculator
49
+ # 'sbusinc': 'e00900s', # Not perfect match for this in Tax-Calculator -- will add to e00900s below
50
+ # 'sprofinc':# no direct analog in Tax-Calculator
51
+ }
52
+
53
+
54
+ def main(file_in_name, file_out_name):
55
+ """
56
+ Translates TAXSIM-35 input file into a Tax-Calculator CSV-formatted
57
+ tc input file. Any pre-existing OUTPUT file contents are overwritten.
58
+ For details on Internet TAXSIM version 32 INPUT format, go to
59
+ https://users.nber.org/~taxsim/taxsim35/
60
+
61
+ Args:
62
+ file_in_name (string): name of input file to run taxcalc with
63
+ file_out_name (string): name of file to save taxcalc output to
64
+
65
+ Returns:
66
+ None
67
+ """
68
+ print("File in and out names: ", file_in_name, file_out_name)
69
+ # check INPUT filename
70
+ if not os.path.isfile(file_in_name):
71
+ emsg = "INPUT file named {} does not exist".format(file_in_name)
72
+ sys.stderr.write("ERROR: {}\n".format(emsg))
73
+ assert False
74
+ # check OUTPUT filename
75
+ if file_out_name == "":
76
+ sys.stderr.write("ERROR: must specify OUTPUT file name\n")
77
+ assert False
78
+ if os.path.isfile(file_out_name):
79
+ os.remove(file_out_name)
80
+ # read TAXSIM-35 INPUT file into a pandas DataFrame
81
+ ivar = pd.read_csv(file_in_name, header=0, index_col=False)
82
+ # Drop 'idtl' – used to generate detailed output
83
+ ivar.drop(columns=["idtl"], inplace=True)
84
+ # translate INPUT variables into OUTPUT variables
85
+ invar = translate(ivar)
86
+ # write OUTPUT file containing Tax-Calculator input variables
87
+ invar.to_csv(file_out_name, index=False)
88
+ # return no-error exit code
89
+ return 0
90
+
91
+
92
+ # end of main function code
93
+
94
+
95
+ def translate(ivar):
96
+ """
97
+ Translate TAXSIM-35 input variables into Tax-Calculator input variables.
98
+ Both ivar and returned invar are pandas DataFrame objects.
99
+ """
100
+ assert isinstance(ivar, pd.DataFrame)
101
+ # Rename variables to be consistent with Tax-Calculator naming conventions
102
+ invar = ivar.rename(TAXSIM_TC_MAP, axis=1)
103
+ invar["n24"] = ivar["dep17"]
104
+ # Create variables for Tax-Calculator that aren't directly represented in TAXSIM
105
+ invar["e02000"] += invar[
106
+ "e26270"
107
+ ] # add active scorp income to "otherprop" income from taxsim
108
+ mstat = ivar["mstat"]
109
+ assert np.all(np.logical_or(mstat == 1, mstat == 2))
110
+ num_deps = ivar["depx"]
111
+ mars = np.where(mstat == 1, np.where(num_deps > 0, 4, 1), 2)
112
+ assert np.all(
113
+ np.logical_or(mars == 1, np.logical_or(mars == 2, mars == 4))
114
+ )
115
+ invar["MARS"] = mars
116
+ num_eitc_qualified_kids = ivar["dep18"]
117
+ invar["f2441"] = invar["nu13"]
118
+ invar["EIC"] = np.minimum(num_eitc_qualified_kids, 3)
119
+ num_taxpayers = np.where(mars == 2, 2, 1)
120
+ invar["XTOT"] = num_taxpayers + num_deps
121
+ invar["e00200"] = invar["e00200p"] + invar["e00200s"]
122
+ invar["e00900p"] += invar["pbusinc"]
123
+ invar["e00900s"] += invar[
124
+ "sbusinc"
125
+ ] # NB: will need to check this later because in TAXSIM, the e00900 does not include QBI, but businc does...
126
+ invar["e00900"] = invar["e00900p"] + invar["e00900s"]
127
+ invar["e00600"] = invar["e00650"]
128
+ invar["e01500"] = invar["e01700"]
129
+ invar["e02300"] = invar["pui"] + invar["sui"]
130
+ # variables for QBID calculation
131
+ invar["PT_SSTB_income"] = (
132
+ 0 # np.where(invar['pprofinc'] + invar['sprofinc'] > 0, 1, 0)
133
+ )
134
+ invar["PT_SSTB_income"] = (
135
+ 0 # np.where(invar['e26270'] > 0, 1, invar['PT_SSTB_income'])
136
+ )
137
+
138
+ # Drop TAXSIM variables not used in Tax-Calculator
139
+ invar.drop(
140
+ columns=[
141
+ "state",
142
+ "mstat",
143
+ "depx",
144
+ # "dep18",
145
+ "transfers",
146
+ "rentpaid",
147
+ "pprofinc",
148
+ "pbusinc",
149
+ "sbusinc",
150
+ "sprofinc",
151
+ "pui",
152
+ "sui",
153
+ ],
154
+ inplace=True,
155
+ )
156
+
157
+ return invar
158
+
159
+
160
+ if __name__ == "__main__":
161
+ sys.exit(main())
@@ -0,0 +1,140 @@
1
+ """
2
+ Translates tc --dump output file into file formatted like TAXSIM-35 output.
3
+ """
4
+
5
+ # CODING-STYLE CHECKS:
6
+ # pycodestyle process_tc_output.py
7
+ # pylint --disable=locally-disabled process_tc_output.py
8
+
9
+ import argparse
10
+ import os
11
+ import sys
12
+ import pandas as pd
13
+
14
+
15
+ def main(input_file_name, output_file_name):
16
+ """
17
+ Translates tc --dump output file into an output file that is
18
+ formatted like the first 28 variables in TAXSIM-35 output. The INPUT
19
+ file contains the output generated by running tc with the --dump
20
+ option. Any pre-existing OUTPUT file contents will be overwritten.
21
+ For details on Internet TAXSIM version 35 OUTPUT format, go to
22
+ https://users.nber.org/~taxsim/taxsim35/
23
+
24
+ Args:
25
+ input_file_name (string): name of file with taxcalc formatted output
26
+ output_file_name (string): name of file with taxsim formatted output
27
+
28
+ Returns:
29
+ None
30
+ """
31
+ # check INPUT filename
32
+ if input_file_name == "":
33
+ sys.stderr.write("ERROR: must specify INPUT file name\n")
34
+ sys.stderr.write("USAGE: {}\n".format(usage_str))
35
+ assert False
36
+ if not os.path.isfile(input_file_name):
37
+ emsg = "INPUT file named {} does not exist".format(args.INPUT)
38
+ sys.stderr.write("ERROR: {}\n".format(emsg))
39
+ assert False
40
+ # check OUTPUT filename
41
+ if output_file_name == "":
42
+ sys.stderr.write("ERROR: must specify OUTPUT file name\n")
43
+ sys.stderr.write("USAGE: {}\n".format(usage_str))
44
+ assert False
45
+ if os.path.isfile(output_file_name):
46
+ os.remove(output_file_name)
47
+ # read INPUT file into a pandas DataFrame
48
+ tcvar = pd.read_csv(input_file_name)
49
+ # write OUTPUT file using the pandas DataFrame
50
+ write_taxsim_formatted_output(output_file_name, tcvar)
51
+ # return no-error exit code
52
+ return 0
53
+
54
+
55
+ # end of main function code
56
+
57
+
58
+ def write_taxsim_formatted_output(filename, tcvar):
59
+ """
60
+ Write contents of tcvar pandas DataFrame to filename using
61
+ Internet-TAXSIM 9.3 output format containing 28 variables.
62
+ """
63
+ assert isinstance(tcvar, pd.DataFrame)
64
+ # with open(filename, 'w') as output_file:
65
+ # for idx in range(0, len(tcvar.index)):
66
+ # odict4idx = extract_output(tcvar.xs(idx))
67
+ # outline = construct_output_line(odict4idx)
68
+ # output_file.write(outline)
69
+ tcvar["state"] = 0 # state code is always zero
70
+ tcvar["statetax"] = 0.0 # no state income tax calculation
71
+ tcvar["mtr_state"] = 0.0 # no state income tax calculation
72
+ tcvar["zero_bracket_amount"] = (
73
+ 0.0 # always set zero-bracket amount to zero
74
+ )
75
+ pre_phase_out_pe = tcvar["pre_c04600"].values
76
+ post_phase_out_pe = tcvar["c04600"].values
77
+ phased_out_pe = pre_phase_out_pe - post_phase_out_pe
78
+ tcvar["post_phase_out_pe"] = (
79
+ post_phase_out_pe # post-phase-out personal exemption
80
+ )
81
+ tcvar["phased_out_pe"] = (
82
+ phased_out_pe # personal exemption that is phased out
83
+ )
84
+ tcvar["exemption_surtax"] = 0.0 # always set exemption surtax to zero
85
+ tcvar["gen_tax_credit"] = 0.0 # always set general tax credit to zero
86
+ tcvar["non_refundable_child_odep_credit"] = (
87
+ tcvar["c07220"] + tcvar["odc"] + tcvar["ctc_new"]
88
+ ) # non-refundable child+odep credit
89
+ tcvar["refundable_CDCC"] = tcvar["CDCC_refund"] # refundable CDCC
90
+ tcvar["amt_liability"] = tcvar["c09600"] # federal AMT liability
91
+ # var28 from TAXSIM-35 is federal income tax before credits; the Tax-Calculator
92
+ # tcvar['c05800'] is this concept but includes AMT liability
93
+ # while Internet-TAXSIM tcvar[28] explicitly excludes AMT liability, so
94
+ # we have the following:
95
+ tcvar["iitax_before_credits_ex_AMT"] = (
96
+ tcvar["c05800"] - tcvar["amt_liability"]
97
+ )
98
+ tcvar = tcvar[
99
+ [
100
+ "RECID",
101
+ "FLPDYR",
102
+ "state",
103
+ "iitax",
104
+ "statetax",
105
+ "payrolltax",
106
+ "mtr_inctax",
107
+ "mtr_state",
108
+ # 'mtr_paytax',
109
+ "c00100",
110
+ "e02300",
111
+ "c02500",
112
+ # 'zero_bracket_amount',
113
+ "post_phase_out_pe",
114
+ "phased_out_pe",
115
+ "c21040",
116
+ "c04470",
117
+ "c04800",
118
+ "taxbc",
119
+ "exemption_surtax",
120
+ "gen_tax_credit",
121
+ "non_refundable_child_odep_credit",
122
+ "c11070",
123
+ "c07180",
124
+ "refundable_CDCC",
125
+ "eitc",
126
+ "c62100",
127
+ "amt_liability",
128
+ "iitax_before_credits_ex_AMT",
129
+ "recovery_rebate_credit",
130
+ ]
131
+ ]
132
+ # better mapping of to how TAXSIM-35 handles refundable credits in 2021
133
+ tcvar.loc[tcvar["FLPDYR"] == 2021, "c11070"] = tcvar.loc[
134
+ tcvar["FLPDYR"] == 2021, "non_refundable_child_odep_credit"
135
+ ]
136
+ tcvar.loc[tcvar["FLPDYR"] == 2021, "c07180"] = tcvar.loc[
137
+ tcvar["FLPDYR"] == 2021, "refundable_CDCC"
138
+ ]
139
+ tcvar.round(decimals=2)
140
+ tcvar.to_csv(filename)
@@ -0,0 +1,49 @@
1
+ // JSON "reform" file that specifies changes in current-law policy that
2
+ // are required to make Tax-Calculator work like TAXSIM-35.
3
+ //
4
+ // (1) AMT_child_em_c_age = 24 (rather than 18)
5
+ // Whether to set this parameter to 18 or 24 is arbitary because
6
+ // neither model has enough information to apply correctly the child
7
+ // AMT exemption rules. Information on full-time student status and
8
+ // whether taxpayers provide more than half of their support are required
9
+ // to apply the rules correctly. Tax-Calculator makes the arbitrary
10
+ // assumption that only those under 18 are required to use the child
11
+ // AMT exemption rules, while TAXSIM-27 makes the arbitrary assumption
12
+ // that all those under 24 are required to use the child AMT exemption.
13
+ // (This change was introduced for assumption set b and higher.)
14
+ //
15
+ // (2) EITC_excess_InvestIncome_rt = 1.0 (rather than 9e99)
16
+ // The rate at which the EITC amount is reduced per dollar of investment
17
+ // income in excess of the EITC investment income ceiling is infinity under
18
+ // current law (that is, any investment income in excess of the ceiling
19
+ // causes EITC ineligibility). However, TAXSIM-27 assumes it is one, so
20
+ // that the EITC amount is reduced a dollar for each dollar of excess
21
+ // investment income. This difference in the parameter value leads to
22
+ // many EITC differences in the randomly-generated validation samples,
23
+ // with some of the differences being in the thousands of dollars. This
24
+ // non-current-law assumption in TAXSIM-27 is presumably made to reduce
25
+ // the magnitude of model-calculated marginal tax rates with respect to
26
+ // investment income in cases where a marginal increase in investment
27
+ // income takes a filing unit above the ceiling.
28
+
29
+ // (3) ALD_AlimonyReceived_hc = 1.0 (rather than 0)
30
+ // TAXSIM35 nonproperty income is mapped into AlimonyRecieved
31
+ // which had its haircut change from 1.0 to 0.0, a change that
32
+ // TAXSIM35 has not implemented for good reason given this:
33
+ // IRS: 'Beginning Jan. 1, 2019, alimony or separate
34
+ // maintenance payments are not deductible from the
35
+ // income of the payer spouse, or includable in the
36
+ // income of the receiving spouse, if made under a
37
+ // divorce or separation agreement executed after
38
+ // Dec. 31, 2018.
39
+
40
+ // (4) PT_qbid_limit_switch = false implies TAXSIM35-like QBI deduction logic.
41
+ {
42
+ "AMT_child_em_c_age": {"2013": 24},
43
+
44
+ "EITC_excess_InvestIncome_rt": {"2013": 1.0},
45
+
46
+ "ALD_AlimonyReceived_hc": {"2019": 1.0},
47
+
48
+ "PT_qbid_limit_switch": {"2018": false}
49
+ }