88from io import StringIO
99import numpy as np
1010import pandas as pd
11+ import pytest
1112import taxcalc as tc
1213from behresp import PARAM_INFO , response , quantity_response
1314
@@ -133,24 +134,68 @@ def test_alternative_behavior_parameters(cps_subsample):
133134 del df2
134135
135136
136- def test_sub_effect_independence ():
137+ def test_quantity_response ():
138+ """
139+ Test quantity_response function.
140+ """
141+ quantity = np .array ([1.0 ] * 10 )
142+ res = quantity_response (quantity ,
143+ price_elasticity = 0 ,
144+ aftertax_price1 = None ,
145+ aftertax_price2 = None ,
146+ income_elasticity = 0 ,
147+ aftertax_income1 = None ,
148+ aftertax_income2 = None )
149+ assert np .allclose (res , np .zeros (quantity .shape ))
150+ one = np .ones (quantity .shape )
151+ res = quantity_response (quantity ,
152+ price_elasticity = - 0.2 ,
153+ aftertax_price1 = one ,
154+ aftertax_price2 = one ,
155+ income_elasticity = 0.1 ,
156+ aftertax_income1 = one ,
157+ aftertax_income2 = (one + one ))
158+ assert not np .allclose (res , np .zeros (quantity .shape ))
159+
160+
161+ @pytest .mark .skip
162+ @pytest .mark .parametrize ("stcg" ,
163+ [- 3600 ,
164+ - 2400 ,
165+ - 1200 ,
166+ 0 ,
167+ 1200 ,
168+ 2400 ,
169+ 3600 ,
170+ 4800 ])
171+ def test_sub_effect_independence (stcg ):
137172 """
138173 Ensure that LTCG amount does not affect magnitude of substitution effect.
139174 """
175+ # pylint: disable=too-many-locals
140176 # specify reform that raises top-bracket marginal tax rate
141177 refyear = 2020
142178 reform = {refyear : {'_II_rt7' : [0.70 ]}}
143179 # specify a substitution effect behavioral response
144180 beh_json = """{
145181 "BE_sub": {"2013": 0.25}
146182 }"""
147- # specify input consisting of two filing units with high earnings, but
148- # with one having large long-term capital gains and the other having
149- # no long-term capital gains
150- input_csv = (u'RECID,MARS,e00200,e00200p,p23250\n '
151- u'1,1,1000000,1000000,500000\n '
152- u'2,1,1000000,1000000,0\n ' )
153- recs = tc .Records (data = pd .read_csv (StringIO (input_csv )),
183+ # specify several high-earning filing units
184+ num_recs = 9
185+ input_csv = (u'RECID,MARS,e00200,e00200p,p22250,p23250\n '
186+ u'1,2,1000000,1000000,stcg, 0\n '
187+ u'2,2,1000000,1000000,stcg, 4800\n '
188+ u'3,2,1000000,1000000,stcg, 3600\n '
189+ u'4,2,1000000,1000000,stcg, 2400\n '
190+ u'5,2,1000000,1000000,stcg, 1200\n '
191+ u'6,2,1000000,1000000,stcg, 0\n '
192+ u'7,2,1000000,1000000,stcg,-1200\n '
193+ u'8,2,1000000,1000000,stcg,-2400\n '
194+ u'9,2,1000000,1000000,stcg,-3600\n ' )
195+ inputcsv = input_csv .replace ('stcg' , str (stcg ))
196+ input_dataframe = pd .read_csv (StringIO (inputcsv ))
197+ assert len (input_dataframe .index ) == num_recs
198+ recs = tc .Records (data = input_dataframe ,
154199 start_year = refyear ,
155200 gfactors = None , weights = None )
156201 beh_dict = tc .Calculator .read_json_assumptions (beh_json )
@@ -164,39 +209,24 @@ def test_sub_effect_independence():
164209 df1 , df2 = response (calc1 , calc2 , beh_dict )
165210 del calc1
166211 del calc2
167- # compute change in taxable income for each of the two filing units
168- chg_funit1 = df2 ['c04800' ][0 ] - df1 ['c04800' ][0 ] # funit with RECID=1
169- chg_funit2 = df2 ['c04800' ][1 ] - df1 ['c04800' ][1 ] # funit with RECID=2
212+ # compute change in taxable income for each of the filing units
213+ chg_funit = dict ()
214+ for rid in range (1 , num_recs + 1 ):
215+ idx = rid - 1
216+ chg_funit [rid ] = df2 ['c04800' ][idx ] - df1 ['c04800' ][idx ]
170217 del df1
171218 del df2
172219 # confirm reform reduces taxable income when assuming substitution effect
173- assert chg_funit1 < 0
174- assert chg_funit2 < 0
175- # confirm change in taxable income is same for the two filing units
176- assert np .allclose (chg_funit1 , chg_funit2 )
177- del chg_funit1
178- del chg_funit2
179-
180-
181- def test_quantity_response ():
182- """
183- Test quantity_response function.
184- """
185- quantity = np .array ([1.0 ] * 10 )
186- res = quantity_response (quantity ,
187- price_elasticity = 0 ,
188- aftertax_price1 = None ,
189- aftertax_price2 = None ,
190- income_elasticity = 0 ,
191- aftertax_income1 = None ,
192- aftertax_income2 = None )
193- assert np .allclose (res , np .zeros (quantity .shape ))
194- one = np .ones (quantity .shape )
195- res = quantity_response (quantity ,
196- price_elasticity = - 0.2 ,
197- aftertax_price1 = one ,
198- aftertax_price2 = one ,
199- income_elasticity = 0.1 ,
200- aftertax_income1 = one ,
201- aftertax_income2 = (one + one ))
202- assert not np .allclose (res , np .zeros (quantity .shape ))
220+ emsg = ''
221+ for rid in range (1 , num_recs + 1 ):
222+ if not chg_funit [rid ] < 0 :
223+ txt = '\n FAIL: stcg={} : chg[{}]={:.2f} is not negative'
224+ emsg += txt .format (stcg , rid , chg_funit [rid ])
225+ # confirm change in taxable income is same for all filing units
226+ for rid in range (2 , num_recs + 1 ):
227+ if not np .allclose (chg_funit [rid ], chg_funit [1 ]):
228+ txt = '\n FAIL: stcg={} : chg[{}]={:.2f} != chg[1]={:.2f}'
229+ emsg += txt .format (stcg , rid , chg_funit [rid ], chg_funit [1 ])
230+ del chg_funit
231+ if emsg :
232+ raise ValueError (emsg )
0 commit comments