Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Adding Corporate Income Tax Distribution #1479

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added CIT_description.pdf
Binary file not shown.
1,845 changes: 1,845 additions & 0 deletions Corp_Inc_Tax_Test.ipynb

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion taxcalc/calculate.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
NonrefundableCredits, C1040, IITAX,
BenefitSurtax, BenefitLimitation,
FairShareTax, LumpSumTax, ExpandIncome,
AfterTaxIncome)
AfterTaxIncome, AggCorpIncTax, DistCorpIncTax)
from taxcalc.policy import Policy
from taxcalc.records import Records
from taxcalc.behavior import Behavior
Expand Down Expand Up @@ -149,6 +149,8 @@ def calc_all(self, zero_out_calc_vars=False):
LumpSumTax(self.policy, self.records)
ExpandIncome(self.policy, self.records)
AfterTaxIncome(self.policy, self.records)
AggCorpIncTax(self)
DistCorpIncTax(self.policy, self.records)

def increment_year(self):
"""
Expand Down
16 changes: 16 additions & 0 deletions taxcalc/current_law_policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -3438,5 +3438,21 @@
"col_var": "",
"col_label": "",
"value": [0.0]
},

"_CIT_Distribution": {
"long_name": "Corporate Income Tax distribution among labor income, normal income and supernormal income",
"description": "Set to 0.2, 0.2 and 0.6, according to TPC",
"section_1": "",
"section_2": "",
"irs_ref": "",
"notes": "",
"row_var": "FLPDYR",
"row_label": ["2013"],
"start_year": 2013,
"cpi_inflated": false,
"col_var": "",
"col_label": "",
"value": [[0.2,0.2,0.6]]
}
}
75 changes: 75 additions & 0 deletions taxcalc/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1633,3 +1633,78 @@ def AfterTaxIncome(combined, expanded_income, aftertax_income):
"""
aftertax_income = expanded_income - combined
return aftertax_income

def AggCorpIncTax(calc):
"""
AggCorpIncTax function: computes the aggregated amounts of labor income, normal income and supernormal income
Prepares the parameters for DistCorpIncTax function
"""
#No e00250
length = len(calc.records.s006)
#positive p23250 and p22250
#positivep23250 = np.where(calc.records.p23250<0, 0, calc.records.p23250)
#positivep22250 = np.where(calc.records.p22250<0, 0, calc.records.p22250)
#labor = ((calc.records.e00200 + calc.records.e07240 + calc.records.e03150 + calc.records.e01400 + calc.records.e01700 + calc.records.e02400 + calc.records.e02100 + calc.records.e00900 + calc.records.e02000) * calc.records.s006).sum()
#normal = 0.4 * ((calc.records.e00650 + positivep23250 + positivep22250 + calc.records.e02100 + calc.records.e00900 + calc.records.e02000) * calc.records.s006).sum() + ((calc.records.e00300 + calc.records.e00400 + calc.records.e00600) * calc.records.s006).sum()
#supernormal = 0.6 * ((calc.records.e00650 + positivep23250 + positivep22250) * calc.records.s006).sum()
#original p23250 and p22250
labor = ((calc.records.e00200 + calc.records.e07240 + calc.records.e03150 + calc.records.e01400 + calc.records.e01700 + calc.records.e02400 + calc.records.e02100 + calc.records.e00900 + calc.records.e02000) * calc.records.s006).sum()
normal = 0.4 * ((calc.records.e00650 + calc.records.p23250 + calc.records.p22250 + calc.records.e02100 + calc.records.e00900 + calc.records.e02000) * calc.records.s006).sum() + ((calc.records.e00300 + calc.records.e00400 + calc.records.e00600) * calc.records.s006).sum()
supernormal = 0.6 * ((calc.records.e00650 + calc.records.p23250 + calc.records.p22250) * calc.records.s006).sum()
# Create arrays with same aggregated amounts for each tax-payer
calc.records.agg_labor = np.ones(length) * labor + 0.0000000001
calc.records.agg_normal = np.ones(length) * normal + 0.0000000001
calc.records.agg_supernormal = np.ones(length) * supernormal + 0.0000000001

@iterate_jit(nopython=True)
def DistCorpIncTax(e00200, e07240, e03150, e01400, e01700, e02400, e02100, e00900, e02000, e00650, p23250, p22250, e00300, e00400, e00600, share_corptax_burden, agg_labor, agg_normal, agg_supernormal, CIT_Distribution):
"""
Compute Corporate Income Tax Distribution
According to TPC,
20% distributed by labor income
20% distributed by normal income
60% distributed by supernormal income

Parameters:
e00200: salaries and wages
e00250: other earned income(DNE)
e07240: retirement savings contribution
e03150: IRA deduction
e01400: taxable IRA distribution
e01700: taxable pensions and annuities included in AGI
e02400: social security benefits
e02100: farm income or loss
e00900: business income or loss
e02000: schedule E net income or loss
e00650: qualified dividends
p23250: long-term gains / losses
p22250: short-term gains / losses
e00300: interest received
e00400: tax-exempt interest income
e00600: dividends included in AGI
CIT_Distribution: [0.2, 0.2, 0.6]
"""
#Do not have this variable in current Puf: e00250
#positive p23250 and p22250
#if p23250<0:
# positivep23250 = 0
#else:
# positivep23250 = p23250
#if p22250<0:
# positivep22250 = 0
#else:
# positivep22250 = p22250
#labor = e00200 + e07240 + e03150 + e01400 + e01700 + e02400 + e02100 + e00900 + e02000
#normal = 0.4 * (e00650 + positivep23250 + positivep22250 + e02100 + e00900 + e02000) + (e00300 + e00400 + e00600)
#supernormal = 0.6 * (e00650 + positivep23250 + positivep22250)
#original p23250 and p22250
labor = e00200 + e07240 + e03150 + e01400 + e01700 + e02400 + e02100 + e00900 + e02000
normal = 0.4 * (e00650 + p23250 + p22250 + e02100 + e00900 + e02000) + (e00300 + e00400 + e00600)
supernormal = 0.6 * (e00650 + p23250 + p22250)
revenue_collected = 100000000000
share_from_labor = CIT_Distribution[0] * revenue_collected * labor / agg_labor
share_from_normal = CIT_Distribution[1] * revenue_collected * normal / agg_normal
share_from_supernormal = CIT_Distribution[2] * revenue_collected * supernormal / agg_supernormal
share_corptax_burden = share_from_labor + share_from_normal + share_from_supernormal
return share_corptax_burden

20 changes: 20 additions & 0 deletions taxcalc/records_variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,26 @@
"type": "float",
"desc": "After tax income is equal to expanded_income minus combined",
"form": {}
},
"share_corptax_burden": {
"type": "float",
"desc": "Amount of corporate income tax distribution",
"form": {}
},
"agg_labor": {
"type": "float",
"desc": "Amount of corporate income tax distribution",
"form": {}
},
"agg_normal": {
"type": "float",
"desc": "Amount of corporate income tax distribution",
"form": {}
},
"agg_supernormal": {
"type": "float",
"desc": "Amount of corporate income tax distribution",
"form": {}
}
}
}
3 changes: 2 additions & 1 deletion taxcalc/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def test_calc_and_used_vars(tests_path):
all_cvars.update(set(['num', 'sep', 'exact']))
# .. add to all_cvars set variables calculated elsewhere
all_cvars.update(set(['mtr_paytax', 'mtr_inctax']))
all_cvars.update(set(['agg_labor', 'agg_normal', 'agg_supernormal']))
# .. check that each var in Records.CALCULATED_VARS is in the all_cvars set
found_error1 = False
if not Records.CALCULATED_VARS <= all_cvars:
Expand All @@ -99,7 +100,7 @@ def test_calc_and_used_vars(tests_path):
msg1 += 'VAR NOT CALCULATED: {}\n'.format(var)
# Test (2):
faux_functions = ['EITCamount', 'ComputeBenefit',
'BenefitSurtax', 'BenefitLimitation']
'BenefitSurtax', 'BenefitLimitation', 'AggCorpIncTax']
found_error2 = False
msg2 = 'calculated & returned variables are not function arguments\n'
for fname in fnames:
Expand Down
58 changes: 57 additions & 1 deletion taxcalc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
STATS_COLUMNS = ['expanded_income', 'c00100', 'aftertax_income', 'standard',
'c04470', 'c04600', 'c04800', 'taxbc', 'c62100', 'c09600',
'c05800', 'othertaxes', 'refund', 'c07100', 'iitax',
'payrolltax', 'combined', 's006']
'payrolltax', 'combined', 's006', 'share_corptax_burden']

# Items in the TABLE_COLUMNS list below correspond to the items in the
# TABLE_LABELS list below; this correspondence allows us to use TABLE_LABELS
Expand All @@ -49,6 +49,10 @@
'Individual Income Tax Liabilities', 'Payroll Tax Liablities',
'Combined Payroll and Individual Income Tax Liabilities']

# Items in the CORP_TABLE are used in the table fro the corporate income tax

CORP_TABLE = ['s006', 'expanded_income', 'c00100', 'share_corptax_burden']

# Following list is used in our difference table to label its columns.
DIFF_TABLE_LABELS = ['Tax Units with Tax Cut', 'Tax Units with Tax Increase',
'Count', 'Average Tax Change', 'Total Tax Difference',
Expand Down Expand Up @@ -1273,3 +1277,55 @@ def delete_file(filename):
"""
if os.path.isfile(filename):
os.remove(filename)

def create_corpinctax_table(calc, groupby, result_type, income_measure='expanded_income'):
res = results(calc.records)
# weight of returns with positive AGI and
# itemized deduction greater than standard deduction
res['c04470'] = res['c04470'].where(((res['c00100'] > 0) &
(res['c04470'] > res['standard'])), 0)

# weight of returns with positive AGI and itemized deduction
res['num_returns_ItemDed'] = res['s006'].where(((res['c00100'] > 0) &
(res['c04470'] > 0)), 0)

# weight of returns with positive AGI and standard deduction
res['num_returns_StandardDed'] = res['s006'].where(((res['c00100'] > 0) &
(res['standard'] > 0)),0)

# weight of returns with positive Alternative Minimum Tax (AMT)
res['num_returns_AMT'] = res['s006'].where(res['c09600'] > 0, 0)

# sorts the data
if groupby == "weighted_deciles":
df = add_weighted_income_bins(res, income_measure=income_measure)
elif groupby == "small_income_bins":
df = add_income_bins(res, compare_with="soi",
income_measure=income_measure)
elif groupby == "large_income_bins":
df = add_income_bins(res, compare_with="tpc",
income_measure=income_measure)
elif groupby == "webapp_income_bins":
df = add_income_bins(res, compare_with="webapp",
income_measure=income_measure)
else:
err = ("groupby must be either 'weighted_deciles' or 'small_income_bins'"
"or 'large_income_bins' or 'webapp_income_bins'")
raise ValueError(err)

# manipulates the data
pd.options.display.float_format = '{:8,.0f}'.format
if result_type == "weighted_sum":
df = weighted(df, STATS_COLUMNS)
gp_mean = df.groupby('bins', as_index=False)[CORP_TABLE].sum()
gp_mean.drop('bins', axis=1, inplace=True)
sum_row = get_sums(df)[CORP_TABLE]
elif result_type == "weighted_avg":
gp_mean = weighted_avg_allcols(df, CORP_TABLE,
income_measure=income_measure)
sum_row = get_sums(df, not_available=True)[CORP_TABLE]
else:
err = ("result_type must be either 'weighted_sum' or 'weighted_avg")
raise ValueError(err)

return gp_mean.append(sum_row)