forked from PSLmodels/Tax-Calculator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions.py
1762 lines (1521 loc) · 66.2 KB
/
functions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Tax-Calculator functions that calculate payroll and individual income taxes.
"""
# CODING-STYLE CHECKS:
# pep8 --ignore=E402 functions.py
# pylint --disable=locally-disabled functions.py
#
# pylint: disable=too-many-lines
# pylint: disable=invalid-name
# pylint: disable=too-many-arguments
# pylint: disable=too-many-locals
import math
import copy
import numpy as np
from taxcalc.decorators import iterate_jit, jit
@iterate_jit(nopython=True)
def EI_PayrollTax(SS_Earnings_c, e00200, e00200p, e00200s,
FICA_ss_trt, FICA_mc_trt, ALD_SelfEmploymentTax_hc,
e00900p, e00900s, e02100p, e02100s, k1bx14p, k1bx14s,
payrolltax, ptax_was, setax, c03260, ptax_oasdi,
sey, earned, earned_p, earned_s):
"""
Compute part of total OASDI+HI payroll taxes and earned income variables.
"""
# compute sey and its individual components
sey_p = e00900p + e02100p + k1bx14p
sey_s = e00900s + e02100s + k1bx14s
sey = sey_p + sey_s # total self-employment income for filing unit
# compute taxable earnings for OASDI FICA ('was' denotes 'wage and salary')
sey_frac = 1.0 - 0.5 * (FICA_ss_trt + FICA_mc_trt)
txearn_was_p = min(SS_Earnings_c, e00200p)
txearn_was_s = min(SS_Earnings_c, e00200s)
txearn_sey_p = min(max(0., sey_p * sey_frac), SS_Earnings_c - txearn_was_p)
txearn_sey_s = min(max(0., sey_s * sey_frac), SS_Earnings_c - txearn_was_s)
# compute OASDI and HI payroll taxes on wage-and-salary income
ptax_ss_was_p = FICA_ss_trt * txearn_was_p
ptax_ss_was_s = FICA_ss_trt * txearn_was_s
ptax_mc_was_p = FICA_mc_trt * e00200p
ptax_mc_was_s = FICA_mc_trt * e00200s
ptax_was = ptax_ss_was_p + ptax_ss_was_s + ptax_mc_was_p + ptax_mc_was_s
# compute self-employment tax on taxable self-employment income
setax_ss_p = FICA_ss_trt * txearn_sey_p
setax_ss_s = FICA_ss_trt * txearn_sey_s
setax_mc_p = FICA_mc_trt * max(0., sey_p * sey_frac)
setax_mc_s = FICA_mc_trt * max(0., sey_s * sey_frac)
setax_p = setax_ss_p + setax_mc_p
setax_s = setax_ss_s + setax_mc_s
setax = setax_p + setax_s
# compute part of total regular payroll taxes for filing unit
payrolltax = ptax_was + setax
# compute OASDI part of payroll taxes
ptax_oasdi = ptax_ss_was_p + ptax_ss_was_s + setax_ss_p + setax_ss_s
# compute earned* variables and AGI deduction for
# "employer share" of self-employment tax, c03260
# Note: c03260 is the amount on 2015 Form 1040, line 27
c03260 = (1. - ALD_SelfEmploymentTax_hc) * 0.5 * setax
earned = max(0., e00200 + sey - c03260)
earned_p = max(0., (e00200p + sey_p -
(1. - ALD_SelfEmploymentTax_hc) * 0.5 * setax_p))
earned_s = max(0., (e00200s + sey_s -
(1. - ALD_SelfEmploymentTax_hc) * 0.5 * setax_s))
return (sey, payrolltax, ptax_was, setax, c03260, ptax_oasdi,
earned, earned_p, earned_s)
@iterate_jit(nopython=True)
def DependentCare(nu13, elderly_dependent, earned,
MARS, ALD_Dependents_thd, ALD_Dependents_hc,
ALD_Dependents_Child_c, ALD_Dependents_Elder_c,
care_deduction):
"""
Parameters
----------
nu13: Number of dependents under 13 years old
elderly_dependent: 1 if unit has an elderly dependent; 0 otherwise
earned: Form 2441 earned income amount
MARS: Marital Status
ALD_Dependents_thd: Maximum income to qualify for deduction
ALD_Dependents_hc: Deduction for dependent care haircut
ALD_Dependents_Child_c: National weighted average cost of childcare
ALD_Dependents_Elder_c: Eldercare deduction ceiling
Returns
-------
care_deduction: Total above the line deductions for dependent care.
"""
if earned <= ALD_Dependents_thd[MARS - 1]:
care_deduction = (((1. - ALD_Dependents_hc) * nu13 *
ALD_Dependents_Child_c) +
((1. - ALD_Dependents_hc) * elderly_dependent *
ALD_Dependents_Elder_c))
else:
care_deduction = 0.
return care_deduction
@iterate_jit(nopython=True)
def Adj(e03150, e03210, c03260,
e03270, e03300, e03400, e03500,
e03220, e03230, e03240, e03290, care_deduction,
ALD_StudentLoan_hc, ALD_SelfEmp_HealthIns_hc, ALD_KEOGH_SEP_hc,
ALD_EarlyWithdraw_hc, ALD_Alimony_hc, ALD_EducatorExpenses_hc,
ALD_HSADeduction_hc, ALD_IRAContributions_hc,
ALD_DomesticProduction_hc, ALD_Tuition_hc,
c02900, c02900_in_ei):
"""
Adj calculates Form 1040 AGI adjustments (i.e., Above-the-Line Deductions)
Notes
-----
Taxpayer characteristics:
e03210 : Student loan interest paid
e03220 : Educator expenses
e03150 : Total deductible IRA plan contributions
e03230 : Tuition and fees (Form 8917)
e03240 : Domestic production activity deduction (Form 8903)
c03260 : Self-employment tax deduction (after haircut)
e03270 : Self-employed health insurance premiums
e03290 : HSA deduction (Form 8889)
e03300 : Total deductible KEOGH/SEP/SIMPLE/etc. plan contributions
e03400 : Penalty on early withdrawal of savings deduction
e03500 : Alimony paid deduction
care_deduction : Dependent care expense deduction
Tax law parameters:
ALD_StudentLoan_hc : Student loan interest deduction haircut
ALD_SelfEmp_HealthIns_hc : Self-employed h.i. deduction haircut
ALD_KEOGH_SEP_hc : KEOGH/etc. plan contribution deduction haircut
ALD_EarlyWithdraw_hc : Penalty on early withdrawal deduction haricut
ALD_Alimony_hc : Alimony paid deduction haircut
ALD_EducatorExpenses_hc: Eductor expenses haircut
ALD_HSADeduction_hc: HSA Deduction haircut
ALD_IRAContributions_hc: IRA Contribution haircut
ALD_DomesticProduction_hc: Domestic production haircut
ALD_Tuition_hc: Tuition and fees haircut
Returns
-------
c02900 : total Form 1040 adjustments, which are not included in AGI
c02900_in_ei : total adjustments included in expanded income
"""
# Form 2555 foreign earned income deduction is assumed to be zero
# Form 1040 adjustments that are included in expanded income:
c02900_in_ei = ((1. - ALD_StudentLoan_hc) * e03210 +
c03260 +
(1. - ALD_EarlyWithdraw_hc) * e03400 +
(1. - ALD_Alimony_hc) * e03500 +
(1. - ALD_EducatorExpenses_hc) * e03220 +
(1. - ALD_Tuition_hc) * e03230 +
(1. - ALD_DomesticProduction_hc) * e03240 +
(1. - ALD_HSADeduction_hc) * e03290 +
care_deduction)
# add in Form 1040 adjustments that are not included in expanded income:
c02900 = c02900_in_ei + ((1. - ALD_SelfEmp_HealthIns_hc) * e03270 +
# deductible IRA contributions
(1. - ALD_IRAContributions_hc) * e03150 +
(1. - ALD_KEOGH_SEP_hc) * e03300)
# FUTURE: move e03270 term into c02900_in_ei after
# health-insurance-premium imputations are available
# FUTURE: move e03150 and e03300 term into c02900_in_ei after
# pension-contribution imputations are available
return (c02900, c02900_in_ei)
@iterate_jit(nopython=True)
def ALD_InvInc_ec_base(p22250, p23250, sep,
e00300, e00600, e01100, e01200,
invinc_ec_base):
"""
Compute invinc_ec_base
"""
# limitation on net short-term and long-term capital losses
cgain = max((-3000. / sep), p22250 + p23250)
# compute exclusion of investment income from AGI
invinc_ec_base = e00300 + e00600 + cgain + e01100 + e01200
return invinc_ec_base
@iterate_jit(nopython=True)
def CapGains(p23250, p22250, sep, ALD_StudentLoan_hc,
ALD_InvInc_ec_rt, invinc_ec_base, ALD_InvInc_ec_base_RyanBrady,
e00200, e00300, e00600, e00650, e00700, e00800,
CG_nodiff, CG_ec, CG_reinvest_ec_rt,
e00900, e01100, e01200, e01400, e01700, e02000, e02100,
e02300, e00400, e02400, c02900, e03210, e03230, e03240,
c01000, c23650, ymod, ymod1, invinc_agi_ec):
"""
CapGains function: ...
"""
# net capital gain (long term + short term) before exclusion
c23650 = p23250 + p22250
# limitation on capital losses
c01000 = max((-3000. / sep), c23650)
# compute total investment income
invinc = e00300 + e00600 + c01000 + e01100 + e01200
# compute exclusion of investment income from AGI
invinc_agi_ec = ALD_InvInc_ec_rt * max(0., invinc_ec_base)
# compute exclusion of investment income for Ryan-Brady plan
if ALD_InvInc_ec_base_RyanBrady:
# This RyanBrady code interprets the Blueprint reform as providing
# an investment income AGI exclusion for each of three investment
# income types (e00300, e00650, p23250) separately. The alternative
# interpretation (that is not adopted here) is that the investment
# income AGI exclusion is calculated using a base that is the sum
# of those three investment income types, with the base being zero
# if the sum of the three is negative.
CG_ec_RyanBrady = (c01000 - max(-3000. / sep,
p22250 + ALD_InvInc_ec_rt * p23250))
invinc_agi_ec = ALD_InvInc_ec_rt * (e00300 + e00650) + CG_ec_RyanBrady
# compute ymod1 variable that is included in AGI
ymod1 = (e00200 + e00700 + e00800 + e00900 + e01400 + e01700 +
invinc - invinc_agi_ec +
e02000 + e02100 + e02300)
if CG_nodiff:
# apply QDIV+CG exclusion if QDIV+LTCG receive no special tax treatment
qdcg_pos = max(0., e00650 + c01000)
qdcg_exclusion = (min(CG_ec, qdcg_pos) +
CG_reinvest_ec_rt * max(0., qdcg_pos - CG_ec))
ymod1 = max(0., ymod1 - qdcg_exclusion)
invinc_agi_ec += qdcg_exclusion
# compute ymod variable that is used in OASDI benefit taxation logic
ymod2 = e00400 + (0.50 * e02400) - c02900
ymod3 = (1. - ALD_StudentLoan_hc) * e03210 + e03230 + e03240
ymod = ymod1 + ymod2 + ymod3
return (c01000, c23650, ymod, ymod1, invinc_agi_ec)
@iterate_jit(nopython=True)
def SSBenefits(MARS, ymod, e02400, SS_thd50, SS_thd85,
SS_percentage1, SS_percentage2, c02500):
"""
SSBenefits function calculates OASDI benefits included in AGI, c02500.
"""
if ymod < SS_thd50[MARS - 1]:
c02500 = 0.
elif ymod >= SS_thd50[MARS - 1] and ymod < SS_thd85[MARS - 1]:
c02500 = SS_percentage1 * min(ymod - SS_thd50[MARS - 1], e02400)
else:
c02500 = min(SS_percentage2 * (ymod - SS_thd85[MARS - 1]) +
SS_percentage1 *
min(e02400, SS_thd85[MARS - 1] -
SS_thd50[MARS - 1]), SS_percentage2 * e02400)
return c02500
@iterate_jit(nopython=True)
def UBI(nu18, n1821, n21, UBI1, UBI2, UBI3, UBI_ecrt,
ubi, taxable_ubi, nontaxable_ubi):
"""
Parameters
----------
nu18: Number of people in the tax unit under 18
n1821: Number of people in the tax unit age 18-20
n21: Number of people in the tax unit age 21+
UBI1: UBI for those under 18
UBI2: UBI for those between 18 to 20
UBI3: UBI for those 21 or more
UBI_ecrt: Fraction of UBI benefits that are not included in AGI
Returns
-------
ubi: total UBI received by the tax unit
taxable_ubi: amount of UBI that is taxable. This is added to AGI
nontaxable_ubi: amount of UBI that is nontaxable.
This is added to expanded income
"""
ubi = nu18 * UBI1 + n1821 * UBI2 + n21 * UBI3
taxable_ubi = ubi * (1. - UBI_ecrt)
nontaxable_ubi = ubi - taxable_ubi
return ubi, taxable_ubi, nontaxable_ubi
@iterate_jit(nopython=True)
def AGI(ymod1, c02500, c02900, XTOT, MARS, sep, DSI, exact, nu18, taxable_ubi,
II_em, II_em_ps, II_prt, II_no_em_nu18,
c00100, pre_c04600, c04600):
"""
AGI function: compute Adjusted Gross Income, c00100 and
compute personal exemption amount, c04600
"""
# calculate AGI assuming no foreign earned income exclusion
c00100 = ymod1 + c02500 - c02900 + taxable_ubi
# calculate personal exemption amount
if II_no_em_nu18: # repeal of personal exemptions for deps. under 18
pre_c04600 = max(0, XTOT - nu18) * II_em
else:
pre_c04600 = XTOT * II_em
if DSI:
pre_c04600 = 0.
# phase-out personal exemption amount
if exact == 1: # exact calculation as on tax forms
line5 = max(0., c00100 - II_em_ps[MARS - 1])
line6 = math.ceil(line5 / (2500. / sep))
line7 = II_prt * line6
c04600 = max(0., pre_c04600 * (1. - line7))
else: # smoothed calculation needed for sensible mtr calculation
dispc_numer = II_prt * (c00100 - II_em_ps[MARS - 1])
dispc_denom = 2500. / sep
dispc = min(1., max(0., dispc_numer / dispc_denom))
c04600 = pre_c04600 * (1. - dispc)
return (c00100, pre_c04600, c04600)
@iterate_jit(nopython=True)
def ItemDedCap(e17500, e18400, e18500, e19200, e19800, e20100, e20400, g20500,
c00100, ID_AmountCap_rt, ID_AmountCap_Switch, e17500_capped,
e18400_capped, e18500_capped, e19200_capped, e19800_capped,
e20100_capped, e20400_capped, g20500_capped):
"""
Apply a cap to gross itemized deductions.
Notes
-----
Tax Law Parameters:
ID_AmountCap_Switch : Indicator for which itemized deductions are
capped
ID_AmountCap_rt : Cap on itemized deductions; decimal fraction of AGI
Taxpayer Characteristics:
e17500 : Medical expenses
e18400 : State and local taxes
e18500 : Real-estate taxes
e19200 : Interest paid
e19800 : Charity cash contributions
e20100 : Charity noncash contributions
e20400 : Total miscellaneous expenses
g20500 : Gross casualty or theft loss (before disregard)
c00100: Adjusted Gross Income
Returns
-------
e17500_capped: Medical expenses, capped by ItemDedCap
e18400_capped: State and local taxes, capped by ItemDedCap
e18500_capped : Real-estate taxes, capped by ItemDedCap
e19200_capped : Interest paid, capped by ItemDedCap
e19800_capped : Charity cash contributions, capped by ItemDedCap
e20100_capped : Charity noncash contributions, capped by ItemDedCap
e20400_capped : Total miscellaneous expenses, capped by ItemDedCap
g20500_capped : Gross casualty or theft loss (before disregard),
capped by ItemDedCap
"""
# pylint: disable=too-many-branches
cap = max(0., ID_AmountCap_rt * c00100)
gross_ded_amt = 0
if ID_AmountCap_Switch[0]: # medical
gross_ded_amt += e17500
if ID_AmountCap_Switch[1]: # statelocal
gross_ded_amt += e18400
if ID_AmountCap_Switch[2]: # realestate
gross_ded_amt += e18500
if ID_AmountCap_Switch[3]: # casualty
gross_ded_amt += g20500
if ID_AmountCap_Switch[4]: # misc
gross_ded_amt += e20400
if ID_AmountCap_Switch[5]: # interest
gross_ded_amt += e19200
if ID_AmountCap_Switch[6]: # charitycash
gross_ded_amt += e19800 + e20100
if ID_AmountCap_Switch[7]: # charitynoncash
gross_ded_amt += e20100
overage = max(0., gross_ded_amt - cap)
e17500_capped = e17500
e18400_capped = e18400
e18500_capped = e18500
g20500_capped = g20500
e20400_capped = e20400
e19200_capped = e19200
e19800_capped = e19800
e20100_capped = e20100
if overage > 0. and c00100 > 0.:
if ID_AmountCap_Switch[0]: # medical
e17500_capped -= (e17500 / gross_ded_amt) * overage
if ID_AmountCap_Switch[1]: # statelocal
e18400_capped -= (e18400 / (gross_ded_amt) * overage)
if ID_AmountCap_Switch[2]: # realestate
e18500_capped -= (e18500 / gross_ded_amt) * overage
if ID_AmountCap_Switch[3]: # casualty
g20500_capped -= (g20500 / gross_ded_amt) * overage
if ID_AmountCap_Switch[4]: # misc
e20400_capped -= (e20400 / gross_ded_amt) * overage
if ID_AmountCap_Switch[5]: # interest
e19200_capped -= (e19200 / gross_ded_amt) * overage
if ID_AmountCap_Switch[6]: # charity
e19800_capped -= (e19800 / gross_ded_amt) * overage
e20100_capped -= (e20100 / gross_ded_amt) * overage
return (e17500_capped, e18400_capped, e18500_capped, g20500_capped,
e20400_capped, e19200_capped, e19800_capped, e20100_capped)
@iterate_jit(nopython=True)
def ItemDed(e17500_capped, e18400_capped, e18500_capped,
g20500_capped, e20400_capped, e19200_capped, e19800_capped,
e20100_capped, MARS, age_head, age_spouse,
c00100, c04470, c17000, c18300, c20500, c19200,
c20800, c21040, c21060, c19700,
ID_ps, ID_Medical_frt, ID_Medical_frt_add4aged, ID_Medical_hc,
ID_Casualty_frt, ID_Casualty_hc, ID_Miscellaneous_frt,
ID_Miscellaneous_hc, ID_Charity_crt_all, ID_Charity_crt_noncash,
ID_prt, ID_crt, ID_c, ID_StateLocalTax_hc, ID_Charity_frt,
ID_Charity_hc, ID_InterestPaid_hc, ID_RealEstate_hc,
ID_Medical_c, ID_StateLocalTax_c, ID_RealEstate_c,
ID_InterestPaid_c, ID_Charity_c, ID_Casualty_c,
ID_Miscellaneous_c):
"""
ItemDed function: itemized deductions, Form 1040, Schedule A
Notes
-----
Tax Law Parameters:
ID_ps : Itemized deduction phaseout AGI start (Pease)
ID_crt : Itemized deduction maximum phaseout
as a decimal fraction of total itemized deduction (Pease)
ID_prt : Itemized deduction phaseout rate (Pease)
ID_c: Dollar limit on itemized deductions
ID_Medical_frt : Deduction for medical expenses;
floor as a decimal fraction of AGI
ID_Medical_frt_add4aged : Addon for medical expenses deduction for
elderly; addon as a decimal fraction of AGI
ID_Casualty_frt : Deduction for casualty loss;
floor as a decimal fraction of AGI
ID_Miscellaneous_frt : Deduction for miscellaneous expenses;
floor as a decimal fraction of AGI
ID_Charity_crt_all : Deduction for all charitable contributions;
ceiling as a decimal fraction of AGI
ID_Charity_crt_noncash : Deduction for noncash charitable
contributions; ceiling as a decimal fraction of AGI
ID_Charity_frt : Disregard for charitable contributions;
floor as a decimal fraction of AGI
ID_Medical_c : Ceiling on medical expense deduction
ID_StateLocalTax_c : Ceiling on state and local tax deduction
ID_RealEstate_c : Ceiling on real estate tax deduction
ID_InterestPaid_c : Ceiling on interest paid deduction
ID_Charity_c : Ceiling on charity expense deduction
ID_Casualty_c : Ceiling on casuality expense deduction
ID_Miscellaneous_c : Ceiling on miscellaneous expense deduction
Taxpayer Characteristics:
e17500_capped : Medical expenses, capped by ItemDedCap
e18400_capped : State and local taxes, capped by ItemDedCap
e18500_capped : Real-estate taxes, capped by ItemDedCap
e19200_capped : Interest paid, capped by ItemDedCap
e19800_capped : Charity cash contributions, capped by ItemDedCap
e20100_capped : Charity noncash contributions, capped by ItemDedCap
e20400_capped : Total miscellaneous expenses, capped by ItemDedCap
g20500_capped : Gross casualty or theft loss (before disregard),
capped by ItemDedCap
Returns
-------
c04470 : Itemized deduction amount (and other intermediate variables)
"""
posagi = max(c00100, 0.)
# Medical
medical_frt = ID_Medical_frt
if age_head >= 65 or (MARS == 2 and age_spouse >= 65):
medical_frt += ID_Medical_frt_add4aged
c17750 = medical_frt * posagi
c17000 = max(0., e17500_capped - c17750) * (1. - ID_Medical_hc)
c17000 = min(c17000, ID_Medical_c[MARS - 1])
# State and local taxes
c18400 = min((1. - ID_StateLocalTax_hc) * max(e18400_capped, 0.),
ID_StateLocalTax_c[MARS - 1])
c18500 = min((1. - ID_RealEstate_hc) * e18500_capped,
ID_RealEstate_c[MARS - 1])
c18300 = c18400 + c18500
# Interest paid
c19200 = e19200_capped * (1. - ID_InterestPaid_hc)
c19200 = min(c19200, ID_InterestPaid_c[MARS - 1])
# Charity
lim30 = min(ID_Charity_crt_noncash * posagi, e20100_capped)
c19700 = min(ID_Charity_crt_all * posagi, lim30 + e19800_capped)
charity_floor = ID_Charity_frt * posagi # floor is zero in present law
c19700 = max(0., c19700 - charity_floor) * (1. - ID_Charity_hc)
c19700 = min(c19700, ID_Charity_c[MARS - 1])
# Casualty
c20500 = (max(0., g20500_capped - ID_Casualty_frt * posagi) *
(1. - ID_Casualty_hc))
c20500 = min(c20500, ID_Casualty_c[MARS - 1])
# Miscellaneous
c20400 = e20400_capped
c20750 = ID_Miscellaneous_frt * posagi
c20800 = max(0., c20400 - c20750) * (1. - ID_Miscellaneous_hc)
c20800 = min(c20800, ID_Miscellaneous_c[MARS - 1])
# Gross Itemized Deductions
c21060 = c17000 + c18300 + c19200 + c19700 + c20500 + c20800
# Limitation on total itemized deductions
nonlimited = c17000 + c20500
limitstart = ID_ps[MARS - 1]
if c21060 > nonlimited and c00100 > limitstart:
dedmin = ID_crt * (c21060 - nonlimited)
dedpho = ID_prt * max(0., posagi - limitstart)
c21040 = min(dedmin, dedpho)
c04470 = c21060 - c21040
else:
c21040 = 0.
c04470 = c21060
c04470 = min(c04470, ID_c[MARS - 1])
return (c17000, c18300, c19200, c20500, c20800, c21040, c21060, c04470,
c19700)
@iterate_jit(nopython=True)
def AdditionalMedicareTax(e00200, MARS,
AMEDT_ec, sey, AMEDT_rt,
FICA_mc_trt, FICA_ss_trt,
ptax_amc, payrolltax):
"""
Computes Additional Medicare Tax (Form 8959) included in payroll taxes.
Notes
-----
Tax Law Parameters:
AMEDT_ec : Additional Medicare Tax earnings exclusion
AMEDT_rt : Additional Medicare Tax rate
FICA_ss_trt : FICA Social Security tax rate
FICA_mc_trt : FICA Medicare tax rate
Taxpayer Charateristics:
e00200 : Wages and salaries
sey : Self-employment income
Returns
-------
ptax_amc : Additional Medicare Tax
payrolltax : payroll tax augmented by Additional Medicare Tax
"""
line8 = max(0., sey) * (1. - 0.5 * (FICA_mc_trt + FICA_ss_trt))
line11 = max(0., AMEDT_ec[MARS - 1] - e00200)
ptax_amc = AMEDT_rt * (max(0., e00200 - AMEDT_ec[MARS - 1]) +
max(0., line8 - line11))
payrolltax = payrolltax + ptax_amc
return (ptax_amc, payrolltax)
@iterate_jit(nopython=True)
def StdDed(DSI, earned, STD, age_head, age_spouse, STD_Aged, STD_Dep,
MARS, MIDR, blind_head, blind_spouse, standard, c19700,
STD_allow_charity_ded_nonitemizers):
"""
StdDed function:
Standard Deduction; Form 1040
This function calculates standard deduction,
including standard deduction for dependents, aged and bind.
Notes
-----
Tax Law Parameters:
STD : Standard deduction amount, filing status dependent
STD_Dep : Standard deduction for dependents
STD_Aged : Additional standard deduction for blind and aged
Taxpayer Characteristics:
earned : Form 2441 earned income amount
e02400 : Gross Social Security Benefit
DSI : Dependent Status Indicator:
0 - not being claimed as a dependent
1 - claimed as a dependent
MIDR : Married filing separately itemized deductions
requirement indicator:
0 - not necessary to itemize because of filing status
1 - necessary to itemize when filing separately
Returns
-------
standard
Standard deduction amount for each taxpayer
who files standard deduction. Otherwise value is zero.
"""
# calculate deduction for dependents
if DSI == 1:
c15100 = max(350. + earned, STD_Dep)
basic_stded = min(STD[MARS - 1], c15100)
else:
c15100 = 0.
if MIDR == 1:
basic_stded = 0.
else:
basic_stded = STD[MARS - 1]
# calculate extra standard deduction for aged and blind
num_extra_stded = blind_head + blind_spouse
if age_head >= 65:
num_extra_stded += 1
if MARS == 2 and age_spouse >= 65:
num_extra_stded += 1
extra_stded = num_extra_stded * STD_Aged[MARS - 1]
# calculate the total standard deduction
standard = basic_stded + extra_stded
if MARS == 3 and MIDR == 1:
standard = 0.
if STD_allow_charity_ded_nonitemizers:
standard += c19700
return standard
@iterate_jit(nopython=True)
def TaxInc(c00100, standard, c04470, c04600, c04800,
PT_exclusion_rt, PT_exclusion_wage_limit, e00900,
e26270, e00200):
"""
TaxInc function: ...
"""
pt_exclusion = max(0., PT_exclusion_rt * (e00900 + e26270))
if e26270 > 0.:
pt_exclusion = min(pt_exclusion, e00200 * PT_exclusion_wage_limit)
c04800 = max(0., c00100 - max(c04470, standard) - c04600 -
pt_exclusion)
return c04800
@jit(nopython=True)
def SchXYZ(taxable_income, MARS, e00900, e26270, e02000, e00200,
PT_rt1, PT_rt2, PT_rt3, PT_rt4, PT_rt5,
PT_rt6, PT_rt7, PT_rt8,
PT_brk1, PT_brk2, PT_brk3, PT_brk4, PT_brk5,
PT_brk6, PT_brk7,
II_rt1, II_rt2, II_rt3, II_rt4, II_rt5,
II_rt6, II_rt7, II_rt8,
II_brk1, II_brk2, II_brk3, II_brk4, II_brk5,
II_brk6, II_brk7, PT_EligibleRate_active,
PT_EligibleRate_passive, PT_wages_active_income,
PT_top_stacking):
"""
Return Schedule X, Y, Z tax amount for specified taxable_income.
"""
# separate non-negative taxable income into two non-negative components,
# doing this in a way so that the components add up to taxable income
# define pass-through income eligible for PT schedule
pt_passive = PT_EligibleRate_passive * (e02000 - e26270)
pt_active_gross = e00900 + e26270
if (pt_active_gross > 0) and PT_wages_active_income:
pt_active_gross = pt_active_gross + e00200
pt_active = PT_EligibleRate_active * pt_active_gross
pt_active = min(pt_active, e00900 + e26270)
pt_taxinc = max(0., pt_passive + pt_active)
if pt_taxinc >= taxable_income:
pt_taxinc = taxable_income
reg_taxinc = 0.
else:
# pt_taxinc is unchanged
reg_taxinc = taxable_income - pt_taxinc
# determine stacking order
if PT_top_stacking:
reg_tbase = 0.
pt_tbase = reg_taxinc
else:
reg_tbase = pt_taxinc
pt_tbase = 0.
# compute Schedule X,Y,Z tax using the two components of taxable income
if reg_taxinc > 0.:
reg_tax = Taxes(reg_taxinc, MARS, reg_tbase,
II_rt1, II_rt2, II_rt3, II_rt4,
II_rt5, II_rt6, II_rt7, II_rt8, II_brk1, II_brk2,
II_brk3, II_brk4, II_brk5, II_brk6, II_brk7)
else:
reg_tax = 0.
if pt_taxinc > 0.:
pt_tax = Taxes(pt_taxinc, MARS, pt_tbase,
PT_rt1, PT_rt2, PT_rt3, PT_rt4,
PT_rt5, PT_rt6, PT_rt7, PT_rt8, PT_brk1, PT_brk2,
PT_brk3, PT_brk4, PT_brk5, PT_brk6, PT_brk7)
else:
pt_tax = 0.
return reg_tax + pt_tax
@iterate_jit(nopython=True)
def SchXYZTax(c04800, MARS, e00900, e26270, e02000, e00200,
PT_rt1, PT_rt2, PT_rt3, PT_rt4, PT_rt5,
PT_rt6, PT_rt7, PT_rt8,
PT_brk1, PT_brk2, PT_brk3, PT_brk4, PT_brk5,
PT_brk6, PT_brk7,
II_rt1, II_rt2, II_rt3, II_rt4, II_rt5,
II_rt6, II_rt7, II_rt8,
II_brk1, II_brk2, II_brk3, II_brk4, II_brk5,
II_brk6, II_brk7, PT_EligibleRate_active,
PT_EligibleRate_passive, PT_wages_active_income,
PT_top_stacking, c05200):
"""
SchXYZTax calls SchXYZ function and sets c05200 to returned amount.
"""
c05200 = SchXYZ(c04800, MARS, e00900, e26270, e02000, e00200,
PT_rt1, PT_rt2, PT_rt3, PT_rt4, PT_rt5,
PT_rt6, PT_rt7, PT_rt8,
PT_brk1, PT_brk2, PT_brk3, PT_brk4, PT_brk5,
PT_brk6, PT_brk7,
II_rt1, II_rt2, II_rt3, II_rt4, II_rt5,
II_rt6, II_rt7, II_rt8,
II_brk1, II_brk2, II_brk3, II_brk4, II_brk5,
II_brk6, II_brk7, PT_EligibleRate_active,
PT_EligibleRate_passive, PT_wages_active_income,
PT_top_stacking)
return c05200
@iterate_jit(nopython=True)
def GainsTax(e00650, c01000, c23650, p23250, e01100, e58990, e00200,
e24515, e24518, MARS, c04800, c05200, e00900, e26270, e02000,
II_rt1, II_rt2, II_rt3, II_rt4, II_rt5, II_rt6, II_rt7, II_rt8,
II_brk1, II_brk2, II_brk3, II_brk4, II_brk5, II_brk6, II_brk7,
PT_rt1, PT_rt2, PT_rt3, PT_rt4, PT_rt5, PT_rt6, PT_rt7, PT_rt8,
PT_brk1, PT_brk2, PT_brk3, PT_brk4, PT_brk5, PT_brk6, PT_brk7,
CG_nodiff, PT_EligibleRate_active, PT_EligibleRate_passive,
PT_wages_active_income, PT_top_stacking,
CG_rt1, CG_rt2, CG_rt3, CG_rt4, CG_brk1, CG_brk2, CG_brk3,
dwks10, dwks13, dwks14, dwks19, c05700, taxbc):
"""
GainsTax function implements (2015) Schedule D Tax Worksheet logic for
the special taxation of long-term capital gains and qualified dividends
if CG_nodiff is false
"""
# pylint: disable=too-many-statements
if c01000 > 0. or c23650 > 0. or p23250 > 0. or e01100 > 0. or e00650 > 0.:
hasqdivltcg = 1 # has qualified dividends or long-term capital gains
else:
hasqdivltcg = 0 # no qualified dividends or long-term capital gains
if CG_nodiff:
hasqdivltcg = 0 # no special taxation of qual divids and l-t cap gains
if hasqdivltcg == 1:
dwks1 = c04800
dwks2 = e00650
dwks3 = e58990
dwks4 = 0. # always assumed to be zero
dwks5 = max(0., dwks3 - dwks4)
dwks6 = max(0., dwks2 - dwks5)
dwks7 = min(p23250, c23650) # SchD lines 15 and 16, respectively
# dwks8 = min(dwks3, dwks4)
# dwks9 = max(0., dwks7 - dwks8)
# BELOW TWO STATEMENTS ARE UNCLEAR IN LIGHT OF dwks9=... COMMENT
if e01100 > 0.:
c24510 = e01100
else:
c24510 = max(0., dwks7) + e01100
dwks9 = max(0., c24510 - min(0., e58990))
# ABOVE TWO STATEMENTS ARE UNCLEAR IN LIGHT OF dwks9=... COMMENT
dwks10 = dwks6 + dwks9
dwks11 = e24515 + e24518 # SchD lines 18 and 19, respectively
dwks12 = min(dwks9, dwks11)
dwks13 = dwks10 - dwks12
dwks14 = max(0., dwks1 - dwks13)
dwks16 = min(CG_brk1[MARS - 1], dwks1)
dwks17 = min(dwks14, dwks16)
dwks18 = max(0., dwks1 - dwks10)
dwks19 = max(dwks17, dwks18)
dwks20 = dwks16 - dwks17
lowest_rate_tax = CG_rt1 * dwks20
# break in worksheet lines
dwks21 = min(dwks1, dwks13)
dwks22 = dwks20
dwks23 = max(0., dwks21 - dwks22)
dwks25 = min(CG_brk2[MARS - 1], dwks1)
dwks26 = dwks19 + dwks20
dwks27 = max(0., dwks25 - dwks26)
dwks28 = min(dwks23, dwks27)
dwks29 = CG_rt2 * dwks28
dwks30 = dwks22 + dwks28
dwks31 = dwks21 - dwks30
dwks32 = CG_rt3 * dwks31
hi_base = max(0., dwks31 - CG_brk3[MARS - 1])
hi_incremental_rate = CG_rt4 - CG_rt3
highest_rate_incremental_tax = hi_incremental_rate * hi_base
# break in worksheet lines
dwks33 = min(dwks9, e24518)
dwks34 = dwks10 + dwks19
dwks36 = max(0., dwks34 - dwks1)
dwks37 = max(0., dwks33 - dwks36)
dwks38 = 0.25 * dwks37
# break in worksheet lines
dwks39 = dwks19 + dwks20 + dwks28 + dwks31 + dwks37
dwks40 = dwks1 - dwks39
dwks41 = 0.28 * dwks40
dwks42 = SchXYZ(dwks19, MARS, e00900, e26270, e02000, e00200,
PT_rt1, PT_rt2, PT_rt3, PT_rt4, PT_rt5,
PT_rt6, PT_rt7, PT_rt8,
PT_brk1, PT_brk2, PT_brk3, PT_brk4, PT_brk5,
PT_brk6, PT_brk7,
II_rt1, II_rt2, II_rt3, II_rt4, II_rt5,
II_rt6, II_rt7, II_rt8,
II_brk1, II_brk2, II_brk3, II_brk4, II_brk5,
II_brk6, II_brk7, PT_EligibleRate_active,
PT_EligibleRate_passive, PT_wages_active_income,
PT_top_stacking)
dwks43 = (dwks29 + dwks32 + dwks38 + dwks41 + dwks42 +
lowest_rate_tax + highest_rate_incremental_tax)
dwks44 = c05200
dwks45 = min(dwks43, dwks44)
c24580 = dwks45
else: # if hasqdivltcg is zero
c24580 = c05200
dwks10 = max(0., min(p23250, c23650)) + e01100
dwks13 = 0.
dwks14 = 0.
dwks19 = 0.
# final calculations done no matter what the value of hasqdivltcg
c05100 = c24580 # because no foreign earned income deduction
c05700 = 0. # no Form 4972, Lump Sum Distributions
taxbc = c05700 + c05100
return (dwks10, dwks13, dwks14, dwks19, c05700, taxbc)
@iterate_jit(nopython=True)
def AGIsurtax(c00100, MARS, AGI_surtax_trt, AGI_surtax_thd, taxbc, surtax):
"""
AGIsurtax computes surtax on AGI above some threshold
"""
if AGI_surtax_trt > 0.:
hiAGItax = AGI_surtax_trt * max(c00100 - AGI_surtax_thd[MARS - 1], 0.)
taxbc += hiAGItax
surtax += hiAGItax
return (taxbc, surtax)
@iterate_jit(nopython=True)
def AMT(e07300, dwks13, standard, f6251, c00100, c18300, taxbc,
c04470, c17000, c20800, c21040, e24515, MARS, sep, dwks19,
dwks14, c05700, e62900, e00700, dwks10, age_head, earned, cmbtp,
AMT_KT_c_Age, AMT_brk1,
AMT_em, AMT_prt, AMT_rt1, AMT_rt2,
AMT_Child_em, AMT_em_ps, AMT_em_pe,
AMT_CG_brk1, AMT_CG_brk2, AMT_CG_brk3, AMT_CG_rt1, AMT_CG_rt2,
AMT_CG_rt3, AMT_CG_rt4, c05800, c09600, c62100):
"""
AMT function computes Alternative Minimum Tax taxable income and liability:
c62100 is AMT taxable income
c09600 is AMT tax liability
c05800 is total (regular + AMT) income tax liability before credits
Note that line-number variable names refer to (2015) Form 6251.
"""
# pylint: disable=too-many-statements,too-many-branches
# Form 6251, Part I
if standard == 0.0:
c62100 = (c00100 - e00700 - c04470 +
max(0., min(c17000, 0.025 * c00100)) +
c18300 + c20800 - c21040)
if standard > 0.0:
c62100 = c00100 - e00700
c62100 += cmbtp # add income not in AGI but considered income for AMT
if MARS == 3:
amtsepadd = max(0.,
min(AMT_em[MARS - 1], AMT_prt * (c62100 - AMT_em_pe)))
else:
amtsepadd = 0.
c62100 = c62100 + amtsepadd # AMT taxable income, which is line28
# Form 6251, Part II top
line29 = max(0., AMT_em[MARS - 1] - AMT_prt *
max(0., c62100 - AMT_em_ps[MARS - 1]))
if age_head != 0 and age_head < AMT_KT_c_Age:
line29 = min(line29, earned + AMT_Child_em)
line30 = max(0., c62100 - line29)
line3163 = (AMT_rt1 * line30 +
AMT_rt2 * max(0., (line30 - (AMT_brk1 / sep))))
if dwks10 > 0. or dwks13 > 0. or dwks14 > 0. or dwks19 > 0. or e24515 > 0.:
# complete Form 6251, Part III (line36 is equal to line30)
line37 = dwks13
line38 = e24515
line39 = min(line37 + line38, dwks10)
line40 = min(line30, line39)
line41 = max(0., line30 - line40)
line42 = (AMT_rt1 * line41 +
AMT_rt2 * max(0., (line41 - (AMT_brk1 / sep))))
line44 = dwks14
line45 = max(0., AMT_CG_brk1[MARS - 1] - line44)
line46 = min(line30, line37)
line47 = min(line45, line46) # line47 is amount taxed at AMT_CG_rt1
cgtax1 = line47 * AMT_CG_rt1
line48 = line46 - line47
line51 = dwks19
line52 = line45 + line51
line53 = max(0., AMT_CG_brk2[MARS - 1] - line52)
line54 = min(line48, line53) # line54 is amount taxed at AMT_CG_rt2
cgtax2 = line54 * AMT_CG_rt2
line56 = line47 + line54 # total amount in lower two brackets
if line41 == line56:
line57 = 0. # line57 is amount taxed at AMT_CG_rt3
linex2 = 0. # linex2 is amount taxed at AMT_CG_rt4
else:
line57 = line46 - line56
linex1 = min(line48,
max(0., AMT_CG_brk3[MARS - 1] - line44 - line45))
linex2 = max(0., line54 - linex1)
cgtax3 = line57 * AMT_CG_rt3
cgtax4 = linex2 * AMT_CG_rt4
if line38 == 0.:
line61 = 0.
else:
line61 = 0.25 * max(0., line30 - line41 - line56 - line57 - linex2)
line62 = line42 + cgtax1 + cgtax2 + cgtax3 + cgtax4 + line61
line64 = min(line3163, line62)
line31 = line64
else: # if not completing Form 6251, Part III
line31 = line3163
# Form 6251, Part II bottom
if f6251 == 1:
line32 = e62900
else:
line32 = e07300
line33 = line31 - line32
c09600 = max(0., line33 - max(0., taxbc - e07300 - c05700))
c05800 = taxbc + c09600