def test_response_json(tests_path): """ Check that each JSON file can be converted into dictionaries that can be used to construct objects needed for a Calculator object. """ responses_path = os.path.join(tests_path, '..', 'responses', '*.json') for jpf in glob.glob(responses_path): # read contents of jpf (JSON parameter filename) jfile = open(jpf, 'r') jpf_text = jfile.read() # check that jpf_text can be used to construct objects response_file = ('"consumption"' in jpf_text and '"behavior"' in jpf_text and '"growdiff_baseline"' in jpf_text and '"growdiff_response"' in jpf_text) if response_file: # pylint: disable=protected-access (con, beh, gdiff_base, gdiff_resp) = Calculator._read_json_econ_assump_text(jpf_text) cons = Consumption() cons.update_consumption(con) behv = Behavior() behv.update_behavior(beh) growdiff_baseline = Growdiff() growdiff_baseline.update_growdiff(gdiff_base) growdiff_response = Growdiff() growdiff_response.update_growdiff(gdiff_resp) else: # jpf_text is not a valid JSON response assumption file print('test-failing-filename: ' + jpf) assert False
def test_consumption_response(puf_1991, weights_1991): consump = Consumption() mpc = 0.5 consumption_response = {2013: {"_MPC_e20400": [mpc]}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): consump.response(list(), 1) # test correct call to response method recs = Records(data=puf_1991, weights=weights_1991, start_year=2009) pre = copy.deepcopy(recs.e20400) consump.response(recs, 1.0) post = recs.e20400 actual_diff = post - pre expected_diff = np.ones(recs.dim) * mpc assert np.allclose(actual_diff, expected_diff) # compute earnings mtr with no consumption response recs0 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc0 = Calculator(policy=Policy(), records=recs0, consumption=None) ided0 = copy.deepcopy(recs0.e20400) (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str="e00200p", wrt_full_compensation=False) assert np.allclose(calc0.records.e20400, ided0) # compute earnings mtr with consumption response recs1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=Policy(), records=recs1, consumption=None) assert np.allclose(calc1.records.e20400, ided0) calc1.consumption.update_consumption(consumption_response) (mtr1_ptax, mtr1_itax, _) = calc1.mtr(variable_str="e00200p", wrt_full_compensation=False) assert np.allclose(calc1.records.e20400, ided0) # confirm that payroll mtr values are no different assert np.allclose(mtr1_ptax, mtr0_ptax) # confirm that all mtr with cons-resp are no greater than without cons-resp assert np.all(np.less_equal(mtr1_itax, mtr0_itax)) # confirm that some mtr with cons-resp are less than without cons-resp assert np.any(np.less(mtr1_itax, mtr0_itax))
def test_make_calculator(cps_subsample): """ Test Calculator class ctor. """ start_year = Policy.JSON_START_YEAR sim_year = 2018 pol = Policy() assert pol.current_year == start_year rec = Records.cps_constructor(data=cps_subsample) consump = Consumption() consump.update_consumption({'MPC_e20400': {sim_year: 0.05}}) assert consump.current_year == start_year calc = Calculator(policy=pol, records=rec, consumption=consump, verbose=True) assert calc.data_year == Records.CPSCSV_YEAR assert calc.current_year == Records.CPSCSV_YEAR # test incorrect Calculator instantiation: with pytest.raises(ValueError): Calculator(policy=None, records=rec) with pytest.raises(ValueError): Calculator(policy=pol, records=None) with pytest.raises(ValueError): Calculator(policy=pol, records=rec, consumption=list())
def test_consumption_response(cps_subsample): consump = Consumption() mpc = 0.5 consumption_response = {2013: {'_MPC_e20400': [mpc]}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): consump.response(list(), 1) # test correct call to response method rec = Records.cps_constructor(data=cps_subsample) pre = copy.deepcopy(rec.e20400) consump.response(rec, 1.0) post = rec.e20400 actual_diff = post - pre expected_diff = np.ones(rec.dim) * mpc assert np.allclose(actual_diff, expected_diff) # compute earnings mtr with no consumption response rec = Records.cps_constructor(data=cps_subsample) ided0 = copy.deepcopy(rec.e20400) calc0 = Calculator(policy=Policy(), records=rec, consumption=None) (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc0.records.e20400, ided0) # compute earnings mtr with consumption response calc1 = Calculator(policy=Policy(), records=rec, consumption=consump) mtr1_ptax, mtr1_itax, _ = calc1.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc1.records.e20400, ided0) # confirm that payroll mtr values are no different assert np.allclose(mtr1_ptax, mtr0_ptax) # confirm that all mtr with cons-resp are no greater than without cons-resp assert np.all(np.less_equal(np.around(mtr1_itax, decimals=5), np.around(mtr0_itax, decimals=5))) # confirm that some mtr with cons-resp are less than without cons-resp assert np.any(np.less(mtr1_itax, mtr0_itax))
def test_update_consumption(): consump = Consumption(start_year=2013) consump.update_consumption({ 2014: { '_MPC_e20400': [0.05], '_BEN_mcare_value': [0.75] }, 2015: { '_MPC_e20400': [0.06], '_BEN_mcare_value': [0.80] } }) expected_mpc_e20400 = np.full((Consumption.DEFAULT_NUM_YEARS, ), 0.06) expected_mpc_e20400[0] = 0.0 expected_mpc_e20400[1] = 0.05 assert np.allclose(consump._MPC_e20400, expected_mpc_e20400, rtol=0.0) assert np.allclose(consump._MPC_e17500, np.zeros((Consumption.DEFAULT_NUM_YEARS, )), rtol=0.0) expected_ben_mcare_value = np.full((Consumption.DEFAULT_NUM_YEARS, ), 0.80) expected_ben_mcare_value[0] = 1.0 expected_ben_mcare_value[1] = 0.75 assert np.allclose(consump._BEN_mcare_value, expected_ben_mcare_value, rtol=0.0) assert np.allclose(consump._BEN_snap_value, np.ones((Consumption.DEFAULT_NUM_YEARS, )), rtol=0.0) consump.set_year(2015) assert consump.current_year == 2015 assert consump.MPC_e20400 == 0.06 assert consump.MPC_e17500 == 0.0 assert consump.BEN_mcare_value == 0.80 assert consump.BEN_snap_value == 1.0
def test_response_json(tests_path): """ Check that each JSON file can be converted into dictionaries that can be used to construct objects needed for a Calculator object. """ # pylint: disable=too-many-locals responses_path = os.path.join(tests_path, '..', 'responses', '*.json') for jpf in glob.glob(responses_path): # read contents of jpf (JSON parameter filename) jfile = open(jpf, 'r') jpf_text = jfile.read() # check that jpf_text can be used to construct objects response_file = ('"consumption"' in jpf_text and '"growdiff_baseline"' in jpf_text and '"growdiff_response"' in jpf_text) if response_file: # pylint: disable=protected-access (con, gdiff_base, gdiff_resp) = Calculator._read_json_econ_assump_text(jpf_text) cons = Consumption() cons.update_consumption(con) growdiff_baseline = GrowDiff() growdiff_baseline.update_growdiff(gdiff_base) growdiff_response = GrowDiff() growdiff_response.update_growdiff(gdiff_resp) else: # jpf_text is not a valid JSON response assumption file print('test-failing-filename: ' + jpf) assert False
def test_update_consumption(): consump = Consumption() consump.update_consumption({}) revision = { 'MPC_e20400': {2014: 0.05, 2015: 0.06}, 'BEN_mcare_value': {2014: 0.75, 2015: 0.80} } consump.update_consumption(revision) expected_mpc_e20400 = np.full((Consumption.DEFAULT_NUM_YEARS,), 0.06) expected_mpc_e20400[0] = 0.0 expected_mpc_e20400[1] = 0.05 assert np.allclose(consump._MPC_e20400, expected_mpc_e20400, rtol=0.0) assert np.allclose(consump._MPC_e17500, np.zeros((Consumption.DEFAULT_NUM_YEARS,)), rtol=0.0) expected_ben_mcare_value = np.full((Consumption.DEFAULT_NUM_YEARS,), 0.80) expected_ben_mcare_value[0] = 1.0 expected_ben_mcare_value[1] = 0.75 assert np.allclose(consump._BEN_mcare_value, expected_ben_mcare_value, rtol=0.0) assert np.allclose(consump._BEN_snap_value, np.ones((Consumption.DEFAULT_NUM_YEARS,)), rtol=0.0) consump.set_year(2015) assert consump.current_year == 2015 assert consump.MPC_e20400 == 0.06 assert consump.MPC_e17500 == 0.0 assert consump.BEN_mcare_value == 0.80 assert consump.BEN_snap_value == 1.0
def test_consumption_response(cps_subsample): consump = Consumption() mpc = 0.5 consumption_response = {'MPC_e20400': {2013: mpc}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): consump.response(list(), 1) # test correct call to response method rec = Records.cps_constructor(data=cps_subsample) pre = copy.deepcopy(rec.e20400) consump.response(rec, 1.0) post = rec.e20400 actual_diff = post - pre expected_diff = np.ones(rec.array_length) * mpc assert np.allclose(actual_diff, expected_diff) # compute earnings mtr with no consumption response rec = Records.cps_constructor(data=cps_subsample) ided0 = copy.deepcopy(rec.e20400) calc0 = Calculator(policy=Policy(), records=rec, consumption=None) (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc0.array('e20400'), ided0) # compute earnings mtr with consumption response calc1 = Calculator(policy=Policy(), records=rec, consumption=consump) mtr1_ptax, mtr1_itax, _ = calc1.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc1.array('e20400'), ided0) # confirm that payroll mtr values are no different assert np.allclose(mtr1_ptax, mtr0_ptax) # confirm that all mtr with cons-resp are no greater than without cons-resp assert np.all(np.less_equal(np.around(mtr1_itax, decimals=5), np.around(mtr0_itax, decimals=5))) # confirm that some mtr with cons-resp are less than without cons-resp assert np.any(np.less(mtr1_itax, mtr0_itax))
def test_taxbrain_json(taxbrain_path): # pylint: disable=redefined-outer-name """ Check that each JSON parameter file can be converted into dictionaries that can be used to construct objects needed for a Calculator object. """ for jpf in glob.glob(taxbrain_path): # read contents of jpf (JSON parameter filename) jfile = open(jpf, 'r') jpf_text = jfile.read() # check that jpf_text can be used to construct objects if '"policy"' in jpf_text: pol = Calculator.read_json_policy_reform_text(jpf_text) policy = Policy() policy.implement_reform(pol) elif ('"consumption"' in jpf_text and '"behavior"' in jpf_text and '"growdiff_baseline"' in jpf_text and '"growdiff_response"' in jpf_text): (con, beh, gdiff_base, gdiff_resp) = Calculator.read_json_econ_assump_text(jpf_text) cons = Consumption() cons.update_consumption(con) behv = Behavior() behv.update_behavior(beh) growdiff_baseline = Growdiff() growdiff_baseline.update_growdiff(gdiff_base) growdiff_response = Growdiff() growdiff_response.update_growdiff(gdiff_resp) else: # jpf_text is not a valid JSON parameter file print('test-failing-filename: ' + jpf) assert False
def test_response_json(tests_path): """ Check that each JSON file can be converted into dictionaries that can be used to construct objects needed for a Calculator object. """ # pylint: disable=too-many-locals responses_path = os.path.join(tests_path, '..', 'responses', '*.json') for jpf in glob.glob(responses_path): # read contents of jpf (JSON parameter filename) jfile = open(jpf, 'r') jpf_text = jfile.read() # check that jpf_text can be used to construct objects response_file = ('"consumption"' in jpf_text and '"growdiff_baseline"' in jpf_text and '"growdiff_response"' in jpf_text) if response_file: consumption = Consumption() con_change = Consumption.read_json_update(jpf_text) consumption.update_consumption(con_change) del consumption for topkey in ['growdiff_baseline', 'growdiff_response']: growdiff = GrowDiff() gdiff_change = GrowDiff.read_json_update(jpf_text, topkey) growdiff.update_growdiff(gdiff_change) del growdiff else: # jpf_text is not a valid JSON response assumption file print('test-failing-filename: ' + jpf) assert False
def reform_warnings_errors(user_mods, using_puf): """ The reform_warnings_errors function assumes user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns a dictionary containing five STR:STR subdictionaries, where the dictionary keys are: 'policy', 'behavior', consumption', 'growdiff_baseline' and 'growdiff_response'; and the subdictionaries are: {'warnings': '<empty-or-message(s)>', 'errors': '<empty-or-message(s)>'}. Note that non-policy parameters have no warnings, so the 'warnings' string for the non-policy parameters is always empty. """ rtn_dict = {'policy': {'warnings': '', 'errors': ''}, 'behavior': {'warnings': '', 'errors': ''}, 'consumption': {'warnings': '', 'errors': ''}, 'growdiff_baseline': {'warnings': '', 'errors': ''}, 'growdiff_response': {'warnings': '', 'errors': ''}} # create GrowDiff objects gdiff_baseline = GrowDiff() try: gdiff_baseline.update_growdiff(user_mods['growdiff_baseline']) except ValueError as valerr_msg: rtn_dict['growdiff_baseline']['errors'] = valerr_msg.__str__() gdiff_response = GrowDiff() try: gdiff_response.update_growdiff(user_mods['growdiff_response']) except ValueError as valerr_msg: rtn_dict['growdiff_response']['errors'] = valerr_msg.__str__() # create Growfactors object growfactors = GrowFactors() gdiff_baseline.apply_to(growfactors) gdiff_response.apply_to(growfactors) # create Policy object pol = Policy(gfactors=growfactors) try: pol.implement_reform(user_mods['policy'], print_warnings=False, raise_errors=False) if using_puf: rtn_dict['policy']['warnings'] = pol.parameter_warnings rtn_dict['policy']['errors'] = pol.parameter_errors except ValueError as valerr_msg: rtn_dict['policy']['errors'] = valerr_msg.__str__() # create Behavior object behv = Behavior() try: behv.update_behavior(user_mods['behavior']) except ValueError as valerr_msg: rtn_dict['behavior']['errors'] = valerr_msg.__str__() # create Consumption object consump = Consumption() try: consump.update_consumption(user_mods['consumption']) except ValueError as valerr_msg: rtn_dict['consumption']['errors'] = valerr_msg.__str__() # return composite dictionary of warnings/errors return rtn_dict
def test_future_update_consumption(): consump = Consumption() assert consump.current_year == consump.start_year assert consump.has_response() is False cyr = 2020 consump.set_year(cyr) consump.update_consumption({cyr: {'_MPC_e20400': [0.01]}}) assert consump.current_year == cyr assert consump.has_response() is True consump.set_year(cyr - 1) assert consump.has_response() is False
def test_future_update_consumption(): consump = Consumption() assert consump.current_year == consump.start_year assert consump.has_response() is False cyr = 2020 consump.set_year(cyr) consump.update_consumption({cyr: {"_MPC_e20400": [0.01]}}) assert consump.current_year == cyr assert consump.has_response() is True consump.set_year(cyr - 1) assert consump.has_response() is False
def test_update_consumption(): consump = Consumption(start_year=2013) consump.update_consumption({2014: {"_MPC_e20400": [0.05]}, 2015: {"_MPC_e20400": [0.06]}}) expected_mpc_e20400 = np.full((Consumption.DEFAULT_NUM_YEARS,), 0.06) expected_mpc_e20400[0] = 0.0 expected_mpc_e20400[1] = 0.05 assert np.allclose(consump._MPC_e20400, expected_mpc_e20400, rtol=0.0) assert np.allclose(consump._MPC_e17500, np.zeros((Consumption.DEFAULT_NUM_YEARS,)), rtol=0.0) consump.set_year(2015) assert consump.current_year == 2015 assert consump.MPC_e20400 == 0.06 assert consump.MPC_e17500 == 0.0
def reform_warnings_errors(user_mods, using_puf): """ The reform_warnings_errors function assumes user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns a dictionary containing five STR:STR subdictionaries, where the dictionary keys are: 'policy', 'consumption', 'growdiff_baseline' and 'growdiff_response'; and the subdictionaries are: {'warnings': '<empty-or-message(s)>', 'errors': '<empty-or-message(s)>'}. Note that non-policy parameters have no warnings, so the 'warnings' string for the non-policy parameters is always empty. """ rtn_dict = {'policy': {'warnings': '', 'errors': ''}, 'consumption': {'warnings': '', 'errors': ''}, 'growdiff_baseline': {'warnings': '', 'errors': ''}, 'growdiff_response': {'warnings': '', 'errors': ''}} # create GrowDiff objects gdiff_baseline = GrowDiff() try: gdiff_baseline.update_growdiff(user_mods['growdiff_baseline']) except ValueError as valerr_msg: rtn_dict['growdiff_baseline']['errors'] = valerr_msg.__str__() gdiff_response = GrowDiff() try: gdiff_response.update_growdiff(user_mods['growdiff_response']) except ValueError as valerr_msg: rtn_dict['growdiff_response']['errors'] = valerr_msg.__str__() # create Growfactors object growfactors = GrowFactors() gdiff_baseline.apply_to(growfactors) gdiff_response.apply_to(growfactors) # create Policy object pol = Policy(gfactors=growfactors) try: pol.implement_reform(user_mods['policy'], print_warnings=False, raise_errors=False) if using_puf: rtn_dict['policy']['warnings'] = pol.parameter_warnings rtn_dict['policy']['errors'] = pol.parameter_errors except ValueError as valerr_msg: rtn_dict['policy']['errors'] = valerr_msg.__str__() # create Consumption object consump = Consumption() try: consump.update_consumption(user_mods['consumption']) except ValueError as valerr_msg: rtn_dict['consumption']['errors'] = valerr_msg.__str__() # return composite dictionary of warnings/errors return rtn_dict
def test_update_consumption(): consump = Consumption(start_year=2013) consump.update_consumption({2014: {'_MPC_e20400': [0.05]}, 2015: {'_MPC_e20400': [0.06]}}) expected_mpc_e20400 = np.full((Consumption.DEFAULT_NUM_YEARS,), 0.06) expected_mpc_e20400[0] = 0.0 expected_mpc_e20400[1] = 0.05 assert np.allclose(consump._MPC_e20400, expected_mpc_e20400, rtol=0.0) assert np.allclose(consump._MPC_e17500, np.zeros((Consumption.DEFAULT_NUM_YEARS,)), rtol=0.0) consump.set_year(2015) assert consump.current_year == 2015 assert consump.MPC_e20400 == 0.06 assert consump.MPC_e17500 == 0.0
def test_make_Calculator(cps_subsample): parm = Policy(start_year=2014, num_years=9) assert parm.current_year == 2014 recs = Records.cps_constructor(data=cps_subsample) consump = Consumption() consump.update_consumption({2014: {'_MPC_e20400': [0.05]}}) assert consump.current_year == 2013 calc = Calculator(policy=parm, records=recs, consumption=consump, behavior=Behavior()) assert calc.current_year == 2014 # test incorrect Calculator instantiation: with pytest.raises(ValueError): calc = Calculator(policy=None, records=recs) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=None) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=recs, behavior=list()) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=recs, consumption=list())
def test_make_Calculator(records_2009): parm = Policy() assert parm.current_year == 2013 recs = records_2009 consump = Consumption() consump.update_consumption({2014: {'_MPC_e20400': [0.05]}}) assert consump.current_year == 2013 calc = Calculator(policy=parm, records=recs, consumption=consump) assert calc.current_year == 2013 # test incorrect Calculator instantiation: with pytest.raises(ValueError): calc = Calculator(policy=None, records=recs) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=None) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=recs, behavior=list()) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=recs, growth=list()) with pytest.raises(ValueError): calc = Calculator(policy=parm, records=recs, consumption=list())
def test_future_update_consumption(): consump = Consumption() assert consump.current_year == consump.start_year assert consump.has_response() is False cyr = 2020 consump.set_year(cyr) consump.update_consumption({'MPC_e20400': {cyr: 0.01}}) assert consump.current_year == cyr assert consump.has_response() is True consump.set_year(cyr - 1) assert consump.has_response() is False # test future updates for benefits consump_ben = Consumption() assert consump_ben.current_year == consump_ben.start_year assert consump_ben.has_response() is False consump_ben.set_year(cyr) consump_ben.update_consumption({'BEN_vet_value': {cyr: 0.95}}) assert consump_ben.current_year == cyr assert consump_ben.has_response() is True consump_ben.set_year(cyr - 1) assert consump_ben.has_response() is False
def test_future_update_consumption(): consump = Consumption() assert consump.current_year == consump.start_year assert consump.has_response() is False cyr = 2020 consump.set_year(cyr) consump.update_consumption({cyr: {'_MPC_e20400': [0.01]}}) assert consump.current_year == cyr assert consump.has_response() is True consump.set_year(cyr - 1) assert consump.has_response() is False # test future updates for benefits consump_ben = Consumption() assert consump_ben.current_year == consump_ben.start_year assert consump_ben.has_response() is False consump_ben.set_year(cyr) consump_ben.update_consumption({cyr: {'_BEN_vet_value': [0.95]}}) assert consump_ben.current_year == cyr assert consump_ben.has_response() is True consump_ben.set_year(cyr - 1) assert consump_ben.has_response() is False
def test_make_calculator(cps_subsample): syr = 2014 pol = Policy(start_year=syr, num_years=9) assert pol.current_year == syr rec = Records.cps_constructor(data=cps_subsample) consump = Consumption() consump.update_consumption({syr: {'_MPC_e20400': [0.05]}}) assert consump.current_year == Consumption.JSON_START_YEAR calc = Calculator(policy=pol, records=rec, consumption=consump, behavior=Behavior()) assert calc.current_year == syr assert calc.records_current_year() == syr # test incorrect Calculator instantiation: with pytest.raises(ValueError): Calculator(policy=None, records=rec) with pytest.raises(ValueError): Calculator(policy=pol, records=None) with pytest.raises(ValueError): Calculator(policy=pol, records=rec, behavior=list()) with pytest.raises(ValueError): Calculator(policy=pol, records=rec, consumption=list())
def test_make_calculator(cps_subsample): """ Test Calculator class ctor. """ start_year = Policy.JSON_START_YEAR sim_year = 2018 pol = Policy() assert pol.current_year == start_year rec = Records.cps_constructor(data=cps_subsample) consump = Consumption() consump.update_consumption({sim_year: {'_MPC_e20400': [0.05]}}) assert consump.current_year == start_year calc = Calculator(policy=pol, records=rec, consumption=consump) assert calc.data_year == Records.CPSCSV_YEAR assert calc.current_year == Records.CPSCSV_YEAR # test incorrect Calculator instantiation: with pytest.raises(ValueError): Calculator(policy=None, records=rec) with pytest.raises(ValueError): Calculator(policy=pol, records=None) with pytest.raises(ValueError): Calculator(policy=pol, records=rec, consumption=list())
def test_consumption_response(puf_1991, weights_1991): consump = Consumption() mpc = 0.5 consumption_response = {2013: {'_MPC_e20400': [mpc]}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): consump.response(list(), 1) # test correct call to response method recs = Records(data=puf_1991, weights=weights_1991, start_year=2009) pre = copy.deepcopy(recs.e20400) consump.response(recs, 1.0) post = recs.e20400 actual_diff = post - pre expected_diff = np.ones(recs.dim) * mpc assert np.allclose(actual_diff, expected_diff) # compute earnings mtr with no consumption response recs0 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc0 = Calculator(policy=Policy(), records=recs0, consumption=None) ided0 = copy.deepcopy(recs0.e20400) (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc0.records.e20400, ided0) # compute earnings mtr with consumption response recs1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=Policy(), records=recs1, consumption=None) assert np.allclose(calc1.records.e20400, ided0) calc1.consumption.update_consumption(consumption_response) (mtr1_ptax, mtr1_itax, _) = calc1.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc1.records.e20400, ided0) # confirm that payroll mtr values are no different assert np.allclose(mtr1_ptax, mtr0_ptax) # confirm that all mtr with cons-resp are no greater than without cons-resp assert np.all(np.less_equal(mtr1_itax, mtr0_itax)) # confirm that some mtr with cons-resp are less than without cons-resp assert np.any(np.less(mtr1_itax, mtr0_itax))
def test_update_consumption(): consump = Consumption() consump.update_consumption({}) revision = { 'MPC_e20400': { 2014: 0.05, 2015: 0.06 }, 'BEN_mcare_value': { 2014: 0.75, 2015: 0.80 } } consump.update_consumption(revision) expected_mpc_e20400 = np.full((Consumption.DEFAULT_NUM_YEARS, ), 0.06) expected_mpc_e20400[0] = 0.0 expected_mpc_e20400[1] = 0.05 assert np.allclose(consump._MPC_e20400, expected_mpc_e20400, rtol=0.0) assert np.allclose(consump._MPC_e17500, np.zeros((Consumption.DEFAULT_NUM_YEARS, )), rtol=0.0) expected_ben_mcare_value = np.full((Consumption.DEFAULT_NUM_YEARS, ), 0.80) expected_ben_mcare_value[0] = 1.0 expected_ben_mcare_value[1] = 0.75 assert np.allclose(consump._BEN_mcare_value, expected_ben_mcare_value, rtol=0.0) assert np.allclose(consump._BEN_snap_value, np.ones((Consumption.DEFAULT_NUM_YEARS, )), rtol=0.0) consump.set_year(2015) assert consump.current_year == 2015 assert consump.MPC_e20400 == 0.06 assert consump.MPC_e17500 == 0.0 assert consump.BEN_mcare_value == 0.80 assert consump.BEN_snap_value == 1.0
def run_nth_year_gdp_elast_model(year_n, start_year, taxrec_df, user_mods, return_json=True): """ The run_nth_year_gdp_elast_model function assumes user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. """ # pylint: disable=too-many-arguments,too-many-locals,too-many-statements check_user_mods(user_mods) # Only makes sense to run for budget years 1 through n-1 (not for year 0) assert year_n > 0 # Specify value of gdp_elasticity gdp_elasticity = user_mods['gdp_elasticity']['value'] # Specify Consumption instance consump = Consumption() consump_assumps = user_mods['consumption'] consump.update_consumption(consump_assumps) # Specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # Create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # Create pre-reform Calculator instance records1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=records1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # Create post-reform Calculator instance records2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=records2, consumption=consump) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # Seed random number generator with a seed value based on user_mods seed = random_seed(user_mods) np.random.seed(seed) # pylint: disable=no-member for _ in range(0, year_n - 1): calc1.increment_year() calc2.increment_year() calc1.calc_all() calc2.calc_all() # Assert that the current year is one behind the year we are calculating assert (calc1.current_year + 1) == (start_year + year_n) assert (calc2.current_year + 1) == (start_year + year_n) # Compute gdp effect gdp_effect = proportional_change_gdp(calc1, calc2, gdp_elasticity) # Return gdp_effect results if return_json: gdp_df = pd.DataFrame(data=[gdp_effect], columns=['col0']) gdp_elast_names_i = [ x + '_' + str(year_n) for x in GDP_ELAST_ROW_NAMES ] gdp_elast_total = create_json_table(gdp_df, row_names=gdp_elast_names_i, num_decimals=5) gdp_elast_total = dict((k, v[0]) for k, v in gdp_elast_total.items()) return gdp_elast_total else: return gdp_effect
def calculators(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods): """ This function assumes that the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns (calc1, calc2) where calc1 is pre-reform Calculator object for year_n, and calc2 is post-reform Calculator object for year_n. Neither Calculator object has had the calc_all() method executed. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = GrowDiff() growdiff_response = GrowDiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform GrowFactors instances growfactors_pre = GrowFactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = GrowFactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 2222 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=sample, gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=sample, gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=sample, gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=sample, gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # delete objects now embedded in calc1 and calc2 del sample del full_sample del consump del growdiff_baseline del growdiff_response del growfactors_pre del growfactors_post del recs1 del recs2 del policy1 del policy2 # increment Calculator objects for year_n years for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() # return Calculator objects return (calc1, calc2)
def calculate(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods, behavior_allowed): """ The calculate function assumes the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. The function returns (calc1, calc2, mask) where calc1 is pre-reform Calculator object calculated for year_n, calc2 is post-reform Calculator object calculated for year_n, and mask is boolean array marking records with reform-induced iitax diffs Set behavior_allowed to False when generating static results or set behavior_allowed to True when generating dynamic results. """ # pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme stime = time.time() tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 180 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample( # pylint: disable=no-member frac=sampling_frac, random_state=sampling_seed) if use_puf_not_cps: print('puf-read-time= {:.1f}'.format(time.time() - stime)) else: print('cps-read-time= {:.1f}'.format(time.time() - stime)) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=copy.deepcopy(sample), gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=copy.deepcopy(sample), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # compute mask array res1 = calc1.dataframe(DIST_VARIABLES) if use_puf_not_cps: # create pre-reform Calculator instance with extra income recs1p = Records(data=copy.deepcopy(sample), gfactors=growfactors_pre) # add one dollar to the income of each filing unit to determine # which filing units undergo a resulting change in tax liability recs1p.e00200 += 1.0 # pylint: disable=no-member recs1p.e00200p += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) # create Calculator with recs1p and calculate for start_year calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # compute mask showing which of the calc1 and calc1p results differ; # mask is true if a filing unit's income tax liability changed after # a dollar was added to the filing unit's wage and salary income res1p = calc1p.dataframe(DIST_VARIABLES) mask = np.logical_not( # pylint: disable=no-member np.isclose(res1.iitax, res1p.iitax, atol=0.001, rtol=0.0)) assert np.any(mask) else: # if use_cps_not_cps is False # indicate that no fuzzing of reform results is required mask = np.zeros(res1.shape[0], dtype=np.int8) # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=copy.deepcopy(sample), gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=copy.deepcopy(sample), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior_has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects and mask return (calc1, calc2, mask)
def calculator_objects(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods, behavior_allowed): """ This function assumes that the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns (calc1, calc2) where calc1 is pre-reform Calculator object calculated for year_n, and calc2 is post-reform Calculator object calculated for year_n. Set behavior_allowed to False when generating static results or set behavior_allowed to True when generating dynamic results. """ # pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = GrowDiff() growdiff_response = GrowDiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform GrowFactors instances growfactors_pre = GrowFactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = GrowFactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 2222 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=sample, gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=sample, gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=sample, gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=sample, gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # delete objects now embedded in calc1 and calc2 del sample del full_sample del consump del growdiff_baseline del growdiff_response del growfactors_pre del growfactors_post del behv del recs1 del recs2 del policy1 del policy2 # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior_has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects return (calc1, calc2)
def dropq_calculate(year_n, start_year, taxrec_df, user_mods, behavior_allowed, mask_computed): """ The dropq_calculate function assumes specified user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. The function returns (calc1, calc2, mask) where calc1 is pre-reform Calculator object calculated for year_n, calc2 is post-reform Calculator object calculated for year_n, and mask is boolean array if compute_mask=True or None otherwise """ # pylint: disable=too-many-arguments,too-many-locals,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create pre-reform Calculator instance recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # optionally compute mask if mask_computed: # create pre-reform Calculator instance with extra income recs1p = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) # add one dollar to total wages and salaries of each filing unit recs1p.e00200 += 1.0 # pylint: disable=no-member recs1p.e00200p += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) # create Calculator with recs1p and calculate for start_year calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # compute mask that shows which of the calc1 and calc1p results differ res1 = results(calc1.records) res1p = results(calc1p.records) mask = (res1.iitax != res1p.iitax) else: mask = None # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior.has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects and mask return (calc1, calc2, mask)
def main(mpc_e17500, mpc_e18400, mpc_e19800, mpc_e20400): """ Highest-level logic of consumption.py script that produces Tax-Calculator marginal-tax-rate results running the taxcalc package on this computer. """ # pylint: disable=too-many-locals # pylint: disable=too-many-statements if not os.path.isfile(PUFCSV_PATH): sys.stderr.write('ERROR: file {} does not exist\n'.format(PUFCSV_PATH)) return 1 cyr = 2014 # compute mtr under current-law policy with no consumption response recs0 = Records(data=PUFCSV_PATH) calc0 = Calculator(policy=Policy(), records=recs0, consumption=None, verbose=False) calc0.advance_to_year(cyr) wghts = calc0.records.s006 (mtr0_fica, mtr0_itax, _) = calc0.mtr(income_type_str='e00200p', wrt_full_compensation=False) # compute mtr under current-law policy with specified consumption response consump = Consumption() consump_mpc = {cyr: {'_MPC_e17500': [mpc_e17500], '_MPC_e18400': [mpc_e18400], '_MPC_e19800': [mpc_e19800], '_MPC_e20400': [mpc_e20400]}} consump.update_consumption(consump_mpc) recs1 = Records(data=PUFCSV_PATH) calc1 = Calculator(policy=Policy(), records=recs1, consumption=consump, verbose=False) calc1.advance_to_year(cyr) assert calc1.consumption.current_year == cyr (mtr1_fica, mtr1_itax, _) = calc1.mtr(income_type_str='e00200p', wrt_full_compensation=False) # compare unweighted mtr results with and without consumption response epsilon = 1.0e-6 # this would represent a mtr of 0.0001 percent assert np.allclose(mtr1_fica, mtr0_fica, atol=epsilon, rtol=0.0) mtr_raw_diff = mtr1_itax - mtr0_itax mtr1_itax = np.where(np.logical_and(mtr_raw_diff > 0.0, mtr_raw_diff < epsilon), mtr0_itax, mtr1_itax) # zero out small positive diffs num_total = mtr1_itax.size num_increases = np.sum(np.greater(mtr1_itax, mtr0_itax)) num_decreases = np.sum(np.less(mtr1_itax, mtr0_itax)) num_nochanges = num_total - num_increases - num_decreases res = 'unweighted_num_of_mtr_{}_with_consump_response= {:6d} ({:5.1f}%)\n' sys.stdout.write(res.format('increases', num_increases, (100.0 * num_increases) / num_total)) sys.stdout.write(res.format('decreases', num_decreases, (100.0 * num_decreases) / num_total)) sys.stdout.write(res.format('nochanges', num_nochanges, (100.0 * num_nochanges) / num_total)) sys.stdout.write(res.format('all_units', num_total, 100.0)) # compute average size of decreases in mtr_itax mtr_pre = mtr0_itax[mtr1_itax < mtr0_itax] assert mtr_pre.size == num_decreases avg_pre = np.mean(mtr_pre) res = 'unweighted_abs_mean_no_c_resp(for_decreases)mtr_itax= {:.4f}\n' sys.stdout.write(res.format(avg_pre)) mtr_diff = mtr1_itax - mtr0_itax mtr_neg = mtr_diff[mtr_diff < 0.0] assert mtr_neg.size == num_decreases avg_neg = np.mean(mtr_neg) assert avg_neg < 0.0 res = 'unweighted_abs_mean_change(for_decreases)in_mtr_itax= {:.4f}\n' sys.stdout.write(res.format(-avg_neg)) res = ' ratio_of_abs_change_in_mtr_itax_and_no_c_resp_mtr_itax= {:.3f}\n' sys.stdout.write(res.format(-avg_neg / avg_pre)) # compare weighted mtr results with and without consumption response wghts_pre = wghts[mtr1_itax < mtr0_itax] assert wghts_pre.size == num_decreases res = 'weighted_percent_of_units_with_mtr_decrease= {:.1f}%\n' frac = wghts_pre.sum() / wghts.sum() sys.stdout.write(res.format(100.0 * frac)) res = ' ratio_of_abs_change_in_mtr_itax_and_no_c_resp_mtr_itax= {:.3f}\n' w_avg_pre = np.mean((mtr_pre * wghts_pre).sum() / wghts_pre.sum()) w_avg_neg = np.mean((mtr_neg * wghts_pre).sum() / wghts_pre.sum()) sys.stdout.write(res.format(-w_avg_neg / w_avg_pre)) # return no-error exit code return 0
def main(mpc_e17500, mpc_e18400, mpc_e19800, mpc_e20400): """ Highest-level logic of consumption.py script that produces Tax-Calculator marginal-tax-rate results running the taxcalc package on this computer. """ # pylint: disable=too-many-locals # pylint: disable=too-many-statements if not os.path.isfile(PUFCSV_PATH): sys.stderr.write('ERROR: file {} does not exist\n'.format(PUFCSV_PATH)) return 1 cyr = 2014 # compute mtr under current-law policy with no consumption response recs0 = Records(data=PUFCSV_PATH) calc0 = Calculator(policy=Policy(), records=recs0, consumption=None, verbose=False) calc0.advance_to_year(cyr) wghts = calc0.records.s006 (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p', wrt_full_compensation=False) # compute mtr under current-law policy with specified consumption response consump = Consumption() consump_mpc = { cyr: { '_MPC_e17500': [mpc_e17500], '_MPC_e18400': [mpc_e18400], '_MPC_e19800': [mpc_e19800], '_MPC_e20400': [mpc_e20400] } } consump.update_consumption(consump_mpc) recs1 = Records(data=PUFCSV_PATH) calc1 = Calculator(policy=Policy(), records=recs1, consumption=consump, verbose=False) calc1.advance_to_year(cyr) assert calc1.consumption.current_year == cyr (mtr1_ptax, mtr1_itax, _) = calc1.mtr(variable_str='e00200p', wrt_full_compensation=False) # compare unweighted mtr results with and without consumption response epsilon = 1.0e-6 # this would represent a mtr of 0.0001 percent assert np.allclose(mtr1_ptax, mtr0_ptax, atol=epsilon, rtol=0.0) mtr_raw_diff = mtr1_itax - mtr0_itax mtr1_itax = np.where( np.logical_and(mtr_raw_diff > 0.0, mtr_raw_diff < epsilon), mtr0_itax, mtr1_itax) # zero out small positive diffs num_total = mtr1_itax.size num_increases = np.sum(np.greater(mtr1_itax, mtr0_itax)) num_decreases = np.sum(np.less(mtr1_itax, mtr0_itax)) num_nochanges = num_total - num_increases - num_decreases res = 'unweighted_num_of_mtr_{}_with_consump_response= {:6d} ({:5.1f}%)\n' sys.stdout.write( res.format('increases', num_increases, (100.0 * num_increases) / num_total)) sys.stdout.write( res.format('decreases', num_decreases, (100.0 * num_decreases) / num_total)) sys.stdout.write( res.format('nochanges', num_nochanges, (100.0 * num_nochanges) / num_total)) sys.stdout.write(res.format('all_units', num_total, 100.0)) # compute average size of decreases in mtr_itax mtr_pre = mtr0_itax[mtr1_itax < mtr0_itax] assert mtr_pre.size == num_decreases avg_pre = np.mean(mtr_pre) res = 'unweighted_abs_mean_no_c_resp(for_decreases)mtr_itax= {:.4f}\n' sys.stdout.write(res.format(avg_pre)) mtr_diff = mtr1_itax - mtr0_itax mtr_neg = mtr_diff[mtr_diff < 0.0] assert mtr_neg.size == num_decreases avg_neg = np.mean(mtr_neg) assert avg_neg < 0.0 res = 'unweighted_abs_mean_change(for_decreases)in_mtr_itax= {:.4f}\n' sys.stdout.write(res.format(-avg_neg)) res = ' ratio_of_abs_change_in_mtr_itax_and_no_c_resp_mtr_itax= {:.3f}\n' sys.stdout.write(res.format(-avg_neg / avg_pre)) # compare weighted mtr results with and without consumption response wghts_pre = wghts[mtr1_itax < mtr0_itax] assert wghts_pre.size == num_decreases res = 'weighted_percent_of_units_with_mtr_decrease= {:.1f}%\n' frac = wghts_pre.sum() / wghts.sum() sys.stdout.write(res.format(100.0 * frac)) res = ' ratio_of_abs_change_in_mtr_itax_and_no_c_resp_mtr_itax= {:.3f}\n' w_avg_pre = np.mean((mtr_pre * wghts_pre).sum() / wghts_pre.sum()) w_avg_neg = np.mean((mtr_neg * wghts_pre).sum() / wghts_pre.sum()) sys.stdout.write(res.format(-w_avg_neg / w_avg_pre)) # return no-error exit code return 0
def calculate_baseline_and_reform(year_n, start_year, taxrec_df, user_mods): """ calculate_baseline_and_reform function assumes specified user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements check_user_mods(user_mods) # Specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # Specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # Create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # Create pre-reform Calculator instance recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # Create pre-reform Calculator instance with extra income recs1p = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) # add one dollar to total wages and salaries of each filing unit recs1p.e00200 += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # Construct mask to show which of the calc1 and calc1p results differ soit1 = results(calc1) soit1p = results(calc1p) mask = (soit1._iitax != soit1p._iitax) # pylint: disable=protected-access # Specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # Prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # Create post-reform Calculator instance with behavior recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # Seed random number generator with a seed value based on user_mods seed = random_seed(user_mods) print('seed={}'.format(seed)) np.random.seed(seed) # pylint: disable=no-member # Increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior.has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # Return calculated results and mask soit1 = results(calc1) soit2 = results(calc2) return soit1, soit2, mask